# Build Theme

> Build a new NUMU V3 storefront theme end-to-end with the current toolchain — @numueg/theme-cli (scaffold/dev/validate), @numueg/theme-plugin (federated vite build), @numueg/theme-sdk 0.10+ (hooks/components/soft-nav), @numueg/theme-kit (headless helpers). Use when creating a theme, adding sections to one, or porting a design into the NUMU theme engine.

- **Type:** Skill
- **Install:** `agentstack add skill-yahiasherif002-claude-skills-build-theme`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Yahiasherif002](https://agentstack.voostack.com/s/yahiasherif002)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Yahiasherif002](https://github.com/Yahiasherif002)
- **Source:** https://github.com/Yahiasherif002/claude-skills/tree/master/build-theme

## Install

```sh
agentstack add skill-yahiasherif002-claude-skills-build-theme
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Building a NUMU V3 Theme

The four packages and their roles — never blur them:

| Package | Role | Reaches the theme how |
|---|---|---|
| `@numueg/theme-cli` (≥0.7.0) | scaffold, dev server, validate, publish | dev dependency, `numu-theme` bin |
| `@numueg/theme-plugin` (≥0.6.0) | vite build → `dist/theme.js` + `import-map.json` + manifest | `numuTheme({ federate: true })` in vite.config |
| `@numueg/theme-sdk` (≥0.10.0) | React runtime: hooks, components, contexts | **externalized** — the host storefront serves it via import map; the bundle never inlines it |
| `@numueg/theme-kit` (≥0.1.0) | React-free helpers: settings guards, i18n pick, money, image | **inlined** into the bundle at build; pure functions, no runtime coupling |

## 1. Scaffold

```bash
npx @numueg/theme-cli init    # or: numu-theme init
```

The scaffold already includes: all required templates, the standard 5-color + 2-font
`settings_schema.json` block (wired to `--theme-*` CSS vars), Header/Footer +
~15 sections, vite.config with `numuTheme({ federate: true })`, bilingual patterns.

**Non-negotiable rule: component filename = schema section type.** A section whose
schema `type` is `featured_collection` lives in `src/sections/featured_collection.tsx`.
The registry is built by filename convention; a mismatch = section silently never renders.

## 2. Dependencies

```jsonc
// package.json — the split matters
"dependencies":    { "@numueg/theme-kit": "^0.1.0" },          // inlined
"devDependencies": { "@numueg/theme-sdk": "^0.10.0",           // externalized at build
                     "@numueg/theme-plugin": "^0.6.0",
                     "@numueg/theme-cli": "^0.7.0" }
```

## 3. Settings access — theme-kit, never hand-rolled guards

Merchant settings arrive as untyped JSON. Do NOT write local `asString`/`localized`
helpers (that was the pre-kit copy-paste era). Import from the kit:

```ts
import {
  localized,        // localized(locale, en, ar) — ar-aware picker
  asString, asNumber, asBool, asArray, asRecord,   // type guards w/ fallbacks
  asImageUrl, asImageAlt,                          // image-setting readers
  readBlocks, pickItems,                           // block-container readers
  formatMoney, centsToMajor,                       // money formatting
  asImageTransform, applyImageTransform,           // focal-point/crop transforms
} from "@numueg/theme-kit";

const title = asString(s.title) || localized(locale, "New arrivals", "وصل حديثاً");
```

If a helper is missing from the kit, add it TO the kit (PR + release), don't fork it locally.

## 4. SDK usage — what each new feature gives you for free

- **Navigation**: always `` from the SDK. Since 0.10 it
  soft-navigates (client-side transition, no reload/remount) when the host supports it
  and falls back to a full nav otherwise. Programmatic: `requestNavigate(href)`.
  Never use `next/link`, `window.location`, or raw `` for internal paths.
- **Money**: `` or kit `formatMoney`.
  NEVER hand-divide `/100` or hardcode `"EGP"`/`"ج.م"` — multi-currency is live.
  ⚠ Pitfall: `variant.price.amount` is **cents**; `product.price` is **major** units.
- **Global sections**: `useSectionGroup("header")` / `"footer"` returns the ordered
  instances from `themeSettings.section_groups`; render them through your own registry.
  Themes that do this render their chrome on EVERY route consistently.
- **Template overrides**: `usePage().template` carries `product.` etc. The host
  resolves `template_suffix` (Shopify OS 2.0-style variants) — render whatever template
  key you're handed; never hardcode "the product template".
- **Data**: `useCachedResource(key, fetcher)` for theme-custom data (SWR-style dedup +
  cross-instance sync). Catalog basics come from `useShop/useProduct/useCollection/
  useProducts/useCart/useCustomer/useNavigation/useSearch`.
- **Variants**: `useVariantSelection(product)` — it publishes the live picker axes to the
  selection registry so `addItem` labels cart lines ("Black, L") even for legacy products.
  Custom add-to-cart buttons: `publishVariantSelection`/`readVariantSelection`.
- **Checkout/account**: `useCheckout`, `useShippingRates`, `useOrders`, `useCustomerAddresses`,
  `useReorder`, `useGiftCardBalance` — themes own these UIs.
- **Rich text from merchants**: SDK `` only (sanitizes). Never `dangerouslySetInnerHTML`.
- **Entry**: `defineThemeEntry(ThemeRoot)` — gives `mount` (client) + `createApp` (SSR
  string render). Both must work: SSR parity is validated.

## 5. i18n / RTL — bilingual is mandatory

Every user-facing string ships en + ar. Fixed chrome strings: `const t = useT()`-style
via SDK `useLocale`, or kit `localized(locale, en, ar)`. Merchant content: bilingual
settings (`heading_en`/`heading_ar` or i18n maps) read with `localized`. Layout must
survive `dir="rtl"` — use logical CSS properties (`margin-inline-start`, not `margin-left`).

## 6. Validate + dev loop

```bash
numu-theme dev        # local dev server against a store
numu-theme check      # schema/manifest validation (single-source: SDK /validation)
numu-theme lint       # section conventions
npm run build         # vite + plugin → dist/theme.js, import-map.json, manifest
```

Build output must show `federate: true` and the current `sdk_compat_minor` in
`dist/import-map.json`, with `react`/`@numueg/theme-sdk` externalized (grep dist/theme.js
for `from"react"` — it must be an import, not inlined source).

- The host gates on `sdk_compat_minor`: a bundle built against a NEWER SDK minor than
  the host runtime serves is refused with a clear error. Build against the published
  SDK version the storefront runtime serves.
- If the theme renders its own header/footer chrome via section groups, the manifest
  flag `renders_global_sections` (plugin ≥0.6.0 emits it) tells the host not to
  double-render fallback chrome.

## 7. Ship

1. **Bump `theme.json` version** — the marketplace seed is idempotent by slug+version;
   an unbumped version silently overwrites in place and merchants never see an update.
2. Commit to `V3-themes` on a feature branch → PR → merge to `main` (triggers the R2
   deploy + registry seed for test + prod).
3. Stores are never auto-switched — merchants adopt the new version from the hub.

## Pitfalls checklist (each one has bitten us)

- [ ] filename = schema type for every section
- [ ] no local guard helpers — kit imports only
- [ ] no `/100`, no hardcoded currency strings; `` everywhere
- [ ] `variant.price.amount` = cents, `product.price` = major
- [ ] SDK `` for ALL internal nav (soft nav is free; raw `` forfeits it)
- [ ] header/footer read from `useSectionGroup`, not hardcoded
- [ ] render `page.template` as handed (template overrides)
- [ ] bilingual en/ar + RTL-safe CSS on every section
- [ ] `` for merchant HTML
- [ ] SSR parity: `createApp` renders without window/document access at module top level
- [ ] `theme.json` version bumped before merge
- [ ] built against the SDK minor the host runtime currently serves

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Yahiasherif002](https://github.com/Yahiasherif002)
- **Source:** [Yahiasherif002/claude-skills](https://github.com/Yahiasherif002/claude-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-yahiasherif002-claude-skills-build-theme
- Seller: https://agentstack.voostack.com/s/yahiasherif002
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
