> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wpos.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Projects

> The fs-project layout: pages, parts, components, theme tokens, and page meta.

The canonical form of an elementor-jsx site is an **fs-project**: a directory
where the layout is the site wiring, and each file holds exactly one concern.
`exjsx build <dir>` discovers it, validates the whole layout up front, and
throws one error listing every problem with its fix.

```text theme={null}
mysite/
  site.config.mjs             (optional) project config only: { name?, template? }
  theme.mjs                   (optional) defineTheme tokens only: the one place brand values live
  pages/                      CONTENT: *.page.jsx files only (discovery errors on strays)
    home.page.jsx             default-exports a component; export const meta = {...} per page
    about-us.page.jsx         slug = filename (nested dirs join with '-'); meta.slug overrides
    locations/[city].page.jsx dynamic: export const data = () => [{slug, title, seo?, props?}]
  parts/                      CHROME: <type>.part.jsx, type in header|footer|single|archive|error404|popup
    header.part.jsx
  components/                 shared section components (imported by pages)
  data/                       data arrays, media.manifest.mjs, media-map.json
```

Pages hold content, parts hold chrome, theme holds tokens, `data()` holds data.
A file that mixes concerns still compiles; the layout exists so the seams stay
reviewable. Small sites may instead use a single `site.jsx` default-exporting
`defineSite`; it runs through the same pipeline.

## Page meta

Every `*.page.jsx` default-exports a component and may export `meta`:

```jsx theme={null}
export const meta = {
  title: 'About us',                     // page title
  slug: 'about',                          // optional; defaults to the filename
  seo: { title: 'About | Brand', description: '...' },  // ship this on every page
  template: 'elementor_canvas',           // or 'elementor_header_footer'
};

export default ({ theme }) => (
  <section>...</section>
);
```

* `slug` values must be unique and kebab-case (`exjsx lint` enforces both, rule
  ids `duplicate-page-slug` and `page-seo`).
* `template` defaults to `elementor_canvas` for standalone pages. When the
  project has `parts/` chrome, pages default to `elementor_header_footer`
  automatically; an explicit `meta.template` wins.

## Theme tokens

`theme.mjs` is the one place brand values live. Components receive it as the
`{ theme }` prop:

```jsx theme={null}
export default defineTheme({
  name: 'mysite',
  color: { ink: '#1A1A2E', primary: '#2563EB', paper: '#FAFAF7', muted: '#5B616E' },
  font: { head: 'Fraunces', body: 'Inter' },
  mode: 'literal',
});
```

```jsx theme={null}
export default ({ theme: t }) => (
  <h1 color={t.color.ink} font={t.font.head}>Never re-declare hex</h1>
);
```

`mode: 'literal'` emits colors and fonts directly and renders on every supported
Elementor version. `mode: 'var'` makes text color and font live-editable in
Elementor's Class Manager (variables); backgrounds degrade to literals
automatically on 4.1.4, and the compiler handles that for you. Start literal;
opt into `var` when you need live binding.

## The prelude: import nothing

The build auto-injects a curated authoring surface into every built file, so
components and pages usually need **zero imports**. `defineSite`, `defineTheme`,
`fontLoader`, `tabs`, `dyn`, the kit builders, and the component library all
resolve as free variables. Unused names tree-shake away, and your own binding of
a name always wins, so the prelude can never break explicit code.

Everything else comes from one bare specifier:

```jsx theme={null}
import { DIM, PDIM, node } from 'elementor-jsx'
```

Short generic names (`S`, `C`, `DIM`, `node`, `abs`, `hover`) are deliberately
not auto-injected: a typo silently resolving to a helper is worse than a
ReferenceError. They stay explicit-import-only.

<Warning>
  The prelude provides `Nav`, `Footer`, and `Layout` as built-in free variables.
  A project component named `Nav` gets silently shadowed by the built-in. Name
  yours `SiteNav` and `SiteFooter`, and import them explicitly from your
  `components/` directory.
</Warning>

## Component conventions

* Small, props-driven function components; theme arrives via context
  (`<Page theme={t}>` plus `useTheme()`), not prop-drilling.
* Any visual pattern used three or more times gets `cls="card"`: the dedup pass
  names the shared class, and the Class Manager shows `card`, not `c-1x9fq2`.
* Never reuse a kit-node instance (`tabs()`, `divider()` results). Shared
  instances mint duplicate ids and `assertTree` throws. Use a factory:
  `const Rule = () => divider({...})`.
* Three or more pages with the same shape: use `fromData(items, map)`, not
  copy-paste.

## Next

<CardGroup cols={2}>
  <Card title="Styling" icon="palette" href="/ultra/styling">
    tw, sx, and raw: the styling ladder.
  </Card>

  <Card title="Components" icon="puzzle-piece" href="/ultra/components">
    Intrinsics and kit helpers.
  </Card>
</CardGroup>
