# Storelib Developer Hub: Storelib Builder Framework, complete reference > Source: https://storelib.com/developers. Map of pages: https://storelib.com/llms.txt. --- # Storelib Developer Hub Storelib sites are built from sections, and every section is written in one language: the **Storelib Builder Framework**. This hub is its complete reference, and a guide to the website builder that runs it. The same language is read by everyone who builds here. A creator in the code editor, the builder's own AI, and whatever you bring with you, whether that is Claude Code, Codex, ChatGPT or Cursor, all write the same files through the same compiler and get the same errors back. There is no second format for machines and no private dialect for the platform's own sections: the thirty sections in the library are written in exactly what these pages describe. Where part of the framework is specified but not live yet, the page says so plainly. Nothing here describes a feature you cannot use today without saying that it is not live. ## A section, whole This is a complete, working section. Save it as `sections/notice.storelib` and it compiles, appears in Add Section, and draws its own settings panel. ```html { "type": "notice", "name": "Notice bar", "category": "Promotion", "settings": [ { "type": "text", "id": "message", "label": "Message", "default": "Free shipping on orders over $50" }, { "type": "text", "id": "link_text", "label": "Link text", "default": "Shop now" }, { "type": "url", "id": "link_url", "label": "Link", "default": "" }, { "type": "color_scheme", "id": "color_scheme", "label": "Colour scheme", "default": "dark" } ], "presets": [{ "name": "Notice bar" }] } ``` Four blocks: markup, scoped CSS, an optional script, and a schema that declares every setting the markup reads. That is the whole format. ## Start here 1. **[How the builder works](https://storelib.com/developers/builder)**. Themes, pages, sections and blocks, what is stored where, and what happens between saving a file and a visitor seeing it. 2. **[Sections](https://storelib.com/developers/sections)**. The `.storelib` file and the template language: output, conditions, loops, filters, and what the compiler refuses. 3. **[Blocks](https://storelib.com/developers/blocks)**. Repeatable content inside a section, and the rules for declaring, rendering and limiting it. 4. **[Schema](https://storelib.com/developers/schema)**. Every setting type, every key a schema can carry, and the order a value is resolved in. 5. **[Styling](https://storelib.com/developers/styling)**. How CSS is scoped, container queries, colour schemes and the theme's type scale. 6. **[JavaScript and forms](https://storelib.com/developers/javascript)**. What a section may do without script, how forms and embeds work, and the scripting API. 7. **[Examples](https://storelib.com/developers/examples)**. Complete sections, each compiled by the test suite on every change. ## Building with an AI agent Point the agent at [storelib.com/llms.txt](https://storelib.com/llms.txt). It is a map of this hub in the plain format agents read, and [llms-full.txt](https://storelib.com/llms-full.txt) is every page in one file. The [AI guide](https://storelib.com/developers/ai) is written for the agent itself: the rules it must follow, the checks its output has to pass, and the exact reference the builder's own AI is given. ## The framework in numbers | Limit | Most allowed | | --- | --- | | One section file | 512 KB | | A section's CSS | 128 KB | | A section's script | 64 KB | | Settings in one section | 120 | | Blocks in one section | 50 | | Sections on one page | 60 | | One asset | 15 MB | | Files in a theme package | 2000 | | A theme package | 50 MB | Changes to the framework are recorded in the [changelog](https://storelib.com/developers/changelog). --- # How the builder works A Storelib website is a **theme**: a set of source files that say how things look and behave, and a set of pages that say what is on them. The website builder is an editor over those two things, and the storefront is a renderer over them. This page is the map; the rest of the hub is the detail. ## Source and content Everything in a theme is one of two kinds, and the split is the whole design. | Kind | What it is | Where it lives | Who changes it | | --- | --- | --- | --- | | **Source** | Section files: markup, CSS, schema, optional script. One file per section type. | `sections/.storelib` | A developer, the code editor, an AI agent | | **Content** | Pages: which sections they hold, in what order, with what settings and blocks. Never markup. | `templates/.json` | The creator, in the builder | Change a section file and every page using that section changes how it looks; nobody's content moves. Change a page and one page's content changes; no section changes how it works. There is no file that does both, which is why a section can be rewritten without losing a single word a creator typed. ## A theme on disk The same layout is used in the database, in the code editor's file tree and inside an exported theme, so it only has to be learned once. ```text my-theme/ ├── theme.json name, version, engine requirement ├── config/ │ └── settings.json theme-wide settings: colour schemes, fonts, radius ├── layout/ │ └── theme.storelib the page shell, and the one place CSS is not scoped ├── templates/ │ ├── index.json the home page: its sections, in order │ ├── product.json │ └── page.about.json a page of its own, at /about ├── sections/ │ ├── hero.storelib one file per section type │ └── features.storelib └── assets/ └── 3f2a…c9.png files, named by the SHA-256 of their bytes ``` Rules the importer and the code editor enforce: - A section file is `sections/.storelib` and its schema's `type` is the same word. A file whose schema disagrees with its name is refused, because two names for one thing is how a rename loses data. - A section type is lowercase letters, digits, `-` and `_`. - Paths are relative to the theme root. A path may not begin with `/` or contain `..`. - An asset is referenced as `asset://`, never by URL. See [Schema](https://storelib.com/developers/schema#assets). ## The hierarchy ```text Theme ├─ Theme settings colour schemes, fonts, text styles, spacing, radius └─ Pages └─ Sections an instance of a section type, with its own settings └─ Blocks repeatable children: a question, a slide, a logo ``` A **section instance**, as the builder stores it: ```json { "id": "sec_9k2m", "type": "faq_accordion", "name": "FAQ", "settings": { "heading": "Questions" }, "blocks": [ { "id": "blk_8f2a", "type": "question", "settings": { "question": "Do you ship abroad?" } }, { "id": "blk_c31d", "type": "question", "settings": { "question": "Returns?" } } ], "hidden": false } ``` - Ids are minted once and never change. Reordering moves an instance; duplicating mints a new id. - `settings` holds only what the creator changed. Everything else comes from the schema's defaults, so a later change to a default reaches everyone who never overrode it. - A setting the schema no longer declares is kept, not deleted. Updating a section never destroys content. ## Draft and published Every page and every theme setting has a draft and a published copy. The builder writes drafts as you work; **Publish** copies the drafts over the published columns in one step. Visitors only ever see published values, and the builder only ever shows drafts, so nothing you try in the editor reaches a visitor until you choose. ## What happens when you save a section file 1. **Parse.** The file is split into its four blocks, each with the line it starts on. 2. **Validate the schema.** Every setting type, id, default and option is checked against the control registry. 3. **Compile the template.** The markup becomes a tree. Every name the template reads is checked against the schema beside it, so `{{ settings.headng }}` is an error with a line number, not a blank space on the page. 4. **Scope the CSS.** Every selector is rewritten to apply to this section's instances only. 5. **Check the script.** Forbidden names and undeclared capabilities are refused. If any step fails, the file is not saved, and each error is shown with its file and line. A section that reached the page has already compiled. See [Sections](https://storelib.com/developers/sections#errors) for the error format. ## What happens when a visitor opens a page The storefront reads the published page, resolves each section's settings (saved value, then schema default, then the control's own fallback), renders the compiled template to HTML on the server, and sends that HTML with each section's scoped CSS. A visitor's browser receives finished markup and never downloads the template engine. A hidden section is not rendered. A section whose file does not compile is left out of the published page rather than breaking it, and shown in the builder as a card naming the file and the line. ## Two kinds of section The library is written in the framework, and so is anything you or an AI write. A few long-standing sections, such as the header and footer, are still drawn by the platform's own React components. Both kinds are placed, reordered, hidden and edited in exactly the same way, and both read the same colour schemes and text styles, so a creator cannot tell them apart. Everything you write is the first kind. ## What keeps a site safe A theme can be exported to a single `.storelib-theme` file and imported into another account, and themes are becoming something creators share. So the framework treats every section as code somebody else might have written. - **Markup is escaped.** `{{ }}` always HTML-escapes. The only way to emit markup is the `raw` filter, and only on a `richtext` setting, whose value is cleaned against an allow list on save, on import and again on every read. - **CSS cannot leave its section.** Scoping is done by the compiler, not by convention. - **No inline script.** ` JSON THE TEMPLATE LANGUAGE IS NOT VUE, REACT OR JSX. v-if, @click, :class and JSX braces are refused by the compiler. It is: {{ settings.heading }} print a value, HTML-escaped {% if x %} … {% elsif y %} … {% else %} … {% endif %} {% for block in blocks %} … {% else %} … {% endfor %} {# a comment, which never reaches the page #} It can read: settings, blocks, section (.id .type .settings .blocks), theme, scheme, page (.template, .in_editor), products, and forloop inside a loop. settings and section.settings are the same thing. EVERY NAME MUST BE DECLARED. {{ settings.foo }} compiles only when the schema declares a setting with id "foo". The same for block settings. The compiler checks every path the template reads against the schema beside it, so a typo is an error with a line number, not a blank space on the page. FILTERS, after a pipe, argument after a colon: default upcase downcase capitalize strip size first last join truncate append prepend replace plus minus times divided_by round json escape raw url embed asset alpha url on every href. raw only on a richtext setting. asset on images. SETTING TYPES: text textarea richtext number toggle checkbox select radio range color color_scheme font_picker alignment image_picker image_gallery video_picker file_picker icon_picker url page_picker product_picker community_picker header paragraph divider REPEATED CONTENT IS BLOCKS, never question_1 / question_2. Declare a block type in the schema with its own settings, and loop over `blocks` in the template. Put data-block-id="{{ block.id }}" on each one so clicking it in the builder selects it. A preset with two or three blocks in it is what makes the section arrive with something in it rather than empty. Block settings are read as block.settings. and must be declared on that block type. COLOUR COMES FROM THE SCHEME. Declare a color_scheme setting and read the scheme in the template and CSS. The keys are: background, background_secondary, text, text_muted, heading, accent, link, border, primary_button_background, primary_button_text, primary_button_border, secondary_button_background, secondary_button_text, secondary_button_border, input_background, input_text, input_border. Older themes also read the shorter aliases bg, paragraph, primary_btn_bg and primary_btn_text, which still resolve. The built-in schemes are white, light, dark, black and highlight, shown in the editor as Light, Soft, Dark, Brand and Accent, and a creator can add more. Never hardcode a hex value for something the scheme already answers: a hardcoded colour stops responding to the creator's theme. RESPONSIVE IS WRITTEN WITH CONTAINER QUERIES, NOT MEDIA QUERIES. A section is as wide as the column it is in, which in the builder's phone preview is not the width of the window, so @media asks the wrong question and a section built on it looks correct in the preview and wrong in the editor. Put container-type: inline-size on the outermost element, write the phone layout as the base rules, then @container (min-width: 640px) and @container (min-width: 1024px) for wider ones. A SECTION'S CSS IS SCOPED AUTOMATICALLY, to that section's instances and nothing else. You do not write the scope and you cannot escape it. html, body and :root are rewritten to point at the section root, so a rule written against them does not do what it looks like it does; do not write them. The CSS may read settings with {{ }} the same way the template does. AN EMPTY STATE BELONGS BEHIND {% if page.in_editor %}, so it prompts the creator in the builder and never reaches a visitor. The schema's preset is what a section arrives with: fill it, so adding the section produces something finished rather than a shell. A SECTION CAN BE ON A PAGE MORE THAN ONCE. Nothing in it may assume it is alone: no literal id="..." in the markup, because two instances would then share one id. Build ids from {{ section.id }}, and have the script query inside root rather than the document. A SECTION'S