Developer docs  /  Themes

Theme anatomy

A theme is a flat set of files under seven fixed top-level folders (enforced byThemeV2FileStore.SanitizeFilePath — anything else is rejected):

themes/origin/
├── layouts/ main.fluid (required), embed.fluid (iframe wrapper)
├── templates/ one entry point per route: home, spaces, space-detail,
│ locations, location, contact, attributes, page, 404,
│ embed-spaces, cart
├── sections/ builder-managed blocks, each with an inline {% schema %}
│ (hero, faq, space-grid, testimonials, cta, map, ...)
├── snippets/ small reusable includes (space-card, section-style,
│ space-listing, button, money, attribute-tile, ...)
├── partials/ page chrome (header, footer, announcement-bar, top-bar,
│ quote-modal)
├── assets/ theme.css + theme.js — inlined into the layout at render
│ time (only .css/.js are loaded for rendering)
└── schema/ settings.json — theme-wide design settings (builder panel)
theme.json — manifest: name + version (seeder only; its
section list is informational — the builder
discovers sections from the files themselves)
attribute-icons.json — SVG icon map for the attr_icon filters

File-type roles, as the admin editor infers them (InferFileType): layout, template,section, snippet, partial, schema, asset.

  • Layouts wrap every page. main.fluid owns the <head> (SEO meta, fonts, analytics, inlined CSS/JS, the CSS-variable block) and the chrome includes. embed.fluid is the chrome-less iframe variant (§6.4).
  • Templates are route entry points. Most are thin: they render route-specific markup (breadcrumbs, listing, detail) and/or loop the Sections list (§2.2).
  • Sections are the units the theme builder shows, reorders, and configures. Each carries its settings schema inline in a {% schema %} block (§5).
  • Snippets/partials are plain includes. The split is convention (snippets = small reusable pieces, partials = page chrome); the include resolver searches both.
  • Assets are not linked, they are inlined: the renderer passes theme.css and theme.js to the layout as theme_css / theme_js strings.
  • Schema files are metadata, never rendered.

{% include %} resolution order

Includes resolve through an in-memory file provider (ThemeFileProvider at the bottom ofThemeV2RenderService.cs). Any .fluid/.liquid extension on the include name is stripped,then:

1) Name contains a folder prefix ("sections/cta") → sections/cta.fluid, then the raw name
2) Plain name ("space-card") → snippets/space-card.fluid
3) → partials/header.fluid
4) → sections/cta.fluid

So {% include 'header' %} finds partials/header.fluid (no snippet by that name), and{% include Section.Type %} finds the matching file in sections/. If two folders hold thesame name, snippets win.