{"_id":"@augeo/smelt","_rev":"6-67639771fec697c01a9f23ba09be7e3d","name":"@augeo/smelt","dist-tags":{"latest":"2.1.0"},"versions":{"1.2.2":{"name":"@augeo/smelt","version":"1.2.2","license":"MIT","_id":"@augeo/smelt@1.2.2","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"bin":{"smelt":"dist/cli.mjs"},"dist":{"shasum":"65b40de8b13cf621f8c289c7351f9037c6dc7610","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-1.2.2.tgz","fileCount":152,"integrity":"sha512-ttTWUQHIipCqnlVjSXqHXAdGzh2RVGColP9VlyhY+qCB6fgzmx/esPKrnD10vp7aHCLm5eRr13XdmCMmPOObcw==","signatures":[{"sig":"MEUCICuDYkbO1ZERCsvhjqR1HYCOIzcluGJ/DEnoZDvIwE7jAiEAqXMWHN7NjGTsq8XI4YjZnCALMTbGu5Jx0/X9/HggrtU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1935608},"type":"module","volta":{"npm":"11.6.2","node":"24.11.0"},"engines":{"npm":"11.6.2","node":"24.11.0"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"}},"gitHead":"64df3b4c3b95d2aaea0224a38d10e33f337c2aba","scripts":{"lint":"biome check && prettier --check --cache .","test":"vitest run","build":"tsdown","verify":"npm run lint:fix && npm run typecheck","prepare":"npm run build","pretest":"npm run build","lint:fix":"biome check --write && prettier --write --cache .","prebuild":"npm run schema:codegen","test:all":"npm test && npm test --prefix example","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","build:watch":"tsdown --watch","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prepublishOnly":"npm run build","schema:codegen":"tsx scripts/codegen-schema.ts"},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"_npmVersion":"11.6.2","description":"Library + CLI for building Shopify themes from a colocated component tree","directories":{},"_nodeVersion":"24.11.0","dependencies":{"citty":"^0.2.2","esbuild":"^0.28.0","chokidar":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","tsdown":"^0.22.1","vitest":"^4.1.7","prettier":"^3","typescript":"^6.0.3","@types/node":"^25.9.1","@augeo/assay":"^1.3.0","@shopify/cli":"^3","@biomejs/biome":"^2.4.16","json-schema-to-typescript":"^15.0.4","@vitest/browser-playwright":"^4.1.7","@shopify/prettier-plugin-liquid":"^1"},"_npmOperationalInternal":{"tmp":"tmp/smelt_1.2.2_1781730104170_0.3563792913990802","host":"s3://npm-registry-packages-npm-production"}},"1.2.3":{"name":"@augeo/smelt","version":"1.2.3","license":"MIT","_id":"@augeo/smelt@1.2.3","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"bin":{"smelt":"dist/cli.mjs"},"dist":{"shasum":"8224d5c408bece5238cd453259cd2f783d1e7502","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-1.2.3.tgz","fileCount":152,"integrity":"sha512-D1OQMaADbWCDRSodbg9bODadTynuAuLKKCrT/A3RzfbTAcgZy2n9igEQzdC41KEWi9IM0wDqTp1Mpo+SIIMufQ==","signatures":[{"sig":"MEUCIGPwTZ6GHeNGKXT0SQG9OA+mQFwD4XTxd1UxwfKkT18qAiEA5EeUn9hGWkJrqD+5Ti44QSPtryNiIMvAlkO7y6MNo9g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1936161},"type":"module","volta":{"npm":"11.6.2","node":"24.11.0"},"engines":{"npm":"11.6.2","node":"24.11.0"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"}},"gitHead":"0258ca6bb32c287c40ff7ab11b757afab1b29ad8","scripts":{"lint":"biome check && prettier --check --cache .","test":"vitest run","build":"tsdown","verify":"npm run lint:fix && npm run typecheck","prepare":"npm run build","pretest":"npm run build","lint:fix":"biome check --write && prettier --write --cache .","prebuild":"npm run schema:codegen","test:all":"npm test && npm test --prefix example","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","build:watch":"tsdown --watch","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prepublishOnly":"npm run build","schema:codegen":"tsx scripts/codegen-schema.ts"},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"_npmVersion":"11.6.2","description":"Library + CLI for building Shopify themes from a colocated component tree","directories":{},"_nodeVersion":"24.11.0","dependencies":{"citty":"^0.2.2","esbuild":"^0.28.0","chokidar":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","tsdown":"^0.22.1","vitest":"^4.1.7","prettier":"^3","typescript":"^6.0.3","@types/node":"^25.9.1","@augeo/assay":"^1.3.0","@shopify/cli":"^3","@biomejs/biome":"^2.4.16","json-schema-to-typescript":"^15.0.4","@vitest/browser-playwright":"^4.1.7","@shopify/prettier-plugin-liquid":"^1"},"_npmOperationalInternal":{"tmp":"tmp/smelt_1.2.3_1781731286262_0.6567188958263794","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@augeo/smelt","version":"1.3.0","license":"MIT","_id":"@augeo/smelt@1.3.0","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"bin":{"smelt":"dist/cli.mjs"},"dist":{"shasum":"3bbfd97f40e5606c8174e95c2007faba3d2a6ae0","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-1.3.0.tgz","fileCount":154,"integrity":"sha512-t2c98HSV8RJ2wfar+RbjoGaozZqVtp+yTW5xbtsLcRjq2oJ0Rsh2SoGIs9l5+Smf95rWB4WnevCqySHTb8fiKA==","signatures":[{"sig":"MEQCIElxPtKS6c3ysYZDI1umGPR9AWurVkir8TY8YNbzRv1uAiAcMbAjAAI3w/wsP34HdGp1ONWpOnQodMGwsaUKW74BJg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1956503},"type":"module","volta":{"npm":"11.6.2","node":"24.11.0"},"engines":{"npm":"11.6.2","node":"24.11.0"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"}},"gitHead":"8367b37c9488ae349f76518778b109a396529f7c","scripts":{"lint":"biome check && prettier --check --cache .","test":"vitest run","build":"tsdown","verify":"npm run lint:fix && npm run typecheck","prepare":"npm run build","pretest":"npm run build","lint:fix":"biome check --write && prettier --write --cache .","prebuild":"npm run schema:codegen","test:all":"npm test && npm test --prefix example","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","build:watch":"tsdown --watch","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prepublishOnly":"npm run build","schema:codegen":"tsx scripts/codegen-schema.ts"},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"_npmVersion":"11.6.2","description":"Library + CLI for building Shopify themes from a colocated component tree","directories":{},"_nodeVersion":"24.11.0","dependencies":{"citty":"^0.2.2","esbuild":"^0.28.0","chokidar":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","tsdown":"^0.22.1","vitest":"^4.1.7","prettier":"^3","typescript":"^6.0.3","@types/node":"^25.9.1","@augeo/assay":"^1.3.0","@shopify/cli":"^3","@biomejs/biome":"^2.4.16","json-schema-to-typescript":"^15.0.4","@vitest/browser-playwright":"^4.1.7","@shopify/prettier-plugin-liquid":"^1"},"_npmOperationalInternal":{"tmp":"tmp/smelt_1.3.0_1782412672962_0.2267001903695891","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@augeo/smelt","version":"2.0.0","license":"MIT","_id":"@augeo/smelt@2.0.0","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"bin":{"smelt":"dist/cli.mjs"},"dist":{"shasum":"a6df5b5b9faf0570dac801772d9cad336edcdf6b","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-2.0.0.tgz","fileCount":154,"integrity":"sha512-WGOQQoCuayoPZk5QIy2ROU4uPsIVsWM4HoxG5b11BiOFnfVs075AHwPz+5QzlcjTJuVktmBJXfA6k6eP+dUl8g==","signatures":[{"sig":"MEQCIHL3dOBV0yVF3jjArJhPRWaR/potrkVXnePo7wvLAJAHAiBrfC46hLmO6ZMOyzgn6jqgP/tueImyT4t312MiOK/G2g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1963051},"type":"module","volta":{"npm":"11.6.2","node":"24.11.0"},"engines":{"npm":"11.6.2","node":"24.11.0"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"}},"gitHead":"4d99d1fbe970d4c8cd0430adb0261bfef040b132","scripts":{"lint":"biome check && prettier --check --cache .","test":"vitest run","build":"tsdown","verify":"npm run lint:fix && npm run typecheck","prepare":"npm run build","pretest":"npm run build","lint:fix":"biome check --write && prettier --write --cache .","prebuild":"npm run schema:codegen","test:all":"npm test && npm test --prefix example","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","build:watch":"tsdown --watch","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prepublishOnly":"npm run build","schema:codegen":"tsx scripts/codegen-schema.ts"},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"_npmVersion":"11.6.2","description":"Library + CLI for building Shopify themes from a colocated component tree","directories":{},"_nodeVersion":"24.11.0","dependencies":{"citty":"^0.2.2","esbuild":"^0.28.0","chokidar":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","tsdown":"^0.22.1","vitest":"^4.1.7","prettier":"^3","typescript":"^6.0.3","@types/node":"^25.9.1","@augeo/assay":"^1.3.0","@shopify/cli":"^3","@biomejs/biome":"^2.4.16","json-schema-to-typescript":"^15.0.4","@vitest/browser-playwright":"^4.1.7","@shopify/prettier-plugin-liquid":"^1"},"_npmOperationalInternal":{"tmp":"tmp/smelt_2.0.0_1782516303281_0.8522618732086862","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@augeo/smelt","version":"2.0.1","license":"MIT","_id":"@augeo/smelt@2.0.1","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"bin":{"smelt":"dist/cli.mjs"},"dist":{"shasum":"f4f7fee1245d09ad1ef633b87a22a5767b09a937","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-2.0.1.tgz","fileCount":154,"integrity":"sha512-JTtV11VBN6Hk8PosXA/YF4aL5BHfr69t9/pmYAwlZztnLY6cbrU/R0vuxtrNEWaOWTil2oWqE+EM44PueUCkrA==","signatures":[{"sig":"MEYCIQChksUiwpWeCD+wmZw1gsE62bhGCC8T8Y1ryLvNeSYQBAIhAOg7/jsie56j+UxJzJuKRf1UZFAQCBFe/NKiPWYrdR3y","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1965083},"type":"module","volta":{"npm":"11.6.2","node":"24.11.0"},"engines":{"npm":"11.6.2","node":"24.11.0"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"}},"gitHead":"9e62b42ed39e89655a46ee564ac9b9767354549f","scripts":{"lint":"biome check && prettier --check --cache .","test":"vitest run","build":"tsdown","verify":"npm run lint:fix && npm run typecheck","prepare":"npm run build","pretest":"npm run build","lint:fix":"biome check --write && prettier --write --cache .","prebuild":"npm run schema:codegen","test:all":"npm test && npm test --prefix example","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","build:watch":"tsdown --watch","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prepublishOnly":"npm run build","schema:codegen":"tsx scripts/codegen-schema.ts"},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"_npmVersion":"11.6.2","description":"Library + CLI for building Shopify themes from a colocated component tree","directories":{},"_nodeVersion":"24.11.0","dependencies":{"citty":"^0.2.2","esbuild":"^0.28.0","chokidar":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","tsdown":"^0.22.1","vitest":"^4.1.7","prettier":"^3","typescript":"^6.0.3","@types/node":"^25.9.1","@augeo/assay":"^1.3.0","@shopify/cli":"^3","@biomejs/biome":"^2.4.16","json-schema-to-typescript":"^15.0.4","@vitest/browser-playwright":"^4.1.7","@shopify/prettier-plugin-liquid":"^1"},"_npmOperationalInternal":{"tmp":"tmp/smelt_2.0.1_1783561412838_0.0723323418013826","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@augeo/smelt","version":"2.1.0","description":"Library + CLI for building Shopify themes from a colocated component tree","license":"MIT","type":"module","bin":{"smelt":"dist/cli.mjs"},"exports":{"./schema":{"types":"./dist/schema.d.mts","import":"./dist/schema.mjs"},"./testing":{"types":"./dist/testing.d.mts","import":"./dist/testing.mjs"}},"engines":{"node":"24.11.0","npm":"11.6.2"},"volta":{"node":"24.11.0","npm":"11.6.2"},"scripts":{"schema:codegen":"tsx scripts/codegen-schema.ts","docs:update":"git submodule update --remote vendor/theme-liquid-docs","prebuild":"npm run schema:codegen","build":"tsdown","build:watch":"tsdown --watch","lint":"biome check && prettier --check --cache .","lint:fix":"biome check --write && prettier --write --cache .","typecheck":"npm run schema:codegen && tsc --noEmit && tsc --noEmit -p src","verify":"npm run lint:fix && npm run typecheck","pretest":"npm run build","test":"vitest run","test:all":"npm test && npm test --prefix example","prepare":"npm run build","prepublishOnly":"npm run build"},"devDependencies":{"@augeo/assay":"^1.3.0","@biomejs/biome":"^2.4.16","@shopify/cli":"^3","@shopify/prettier-plugin-liquid":"^1","@types/node":"^25.9.1","@vitest/browser-playwright":"^4.1.7","json-schema-to-typescript":"^15.0.4","prettier":"^3","tsdown":"^0.22.1","tsx":"^4.22.3","typescript":"^6.0.3","vitest":"^4.1.7"},"dependencies":{"@noble/hashes":"^2.2.0","chokidar":"^5.0.0","citty":"^0.2.2","esbuild":"^0.28.0"},"gitHead":"6b5eb70a5ecc00236549f4648ae64c39f441a3f6","_id":"@augeo/smelt@2.1.0","_nodeVersion":"24.11.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-2Oq+mG+1QOT2uI+haMZXBtMppIhJnDQQYLRUM7mMocjRO1WfaJ9C6CqFlO4a7G1hHs8a/MPS+Cx920eoG/Ozkw==","shasum":"719cec1772942368548c5771c87e633d0e091620","tarball":"https://registry.npmjs.org/@augeo/smelt/-/smelt-2.1.0.tgz","fileCount":164,"unpackedSize":1982635,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDns+2PvYyDZvkxTwTI5C5lnkU/GiMIZnrzLB7LFLlijwIgbMSMVTfTJuAO5HzFEZD1fu4G/0WVPiDeRgbyjSkApHI="}]},"_npmUser":{"name":"seanhealy","email":"s@xib.ca"},"directories":{},"maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/smelt_2.1.0_1783626344352_0.8714857830595633"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-17T21:01:43.990Z","modified":"2026-07-09T19:45:44.661Z","1.2.2":"2026-06-17T21:01:44.396Z","1.2.3":"2026-06-17T21:21:26.461Z","1.3.0":"2026-06-25T18:37:53.208Z","2.0.0":"2026-06-26T23:25:03.447Z","2.0.1":"2026-07-09T01:43:32.997Z","2.1.0":"2026-07-09T19:45:44.524Z"},"license":"MIT","description":"Library + CLI for building Shopify themes from a colocated component tree","maintainers":[{"name":"seanhealy","email":"s@xib.ca"}],"readme":"# Smelt\n\n[![Verify](https://github.com/AugeoCorp/smelt/actions/workflows/verify.yml/badge.svg)](https://github.com/AugeoCorp/smelt/actions/workflows/verify.yml)\n\nBuild Shopify themes from colocated components. Author your `button/` directory\nonce (`button.liquid`, `button.ts`, `button.css`, `button.test.ts`,\n`button.schema.ts`), and Smelt compiles it into the flat, namespaced files\nShopify expects.\n\n## Why\n\n- **Colocation.** Every component lives in one directory. Liquid markup,\n  TypeScript behavior, CSS, tests, and schema are authored side-by-side instead\n  of scattered across `sections/`, `snippets/`, and `assets/`.\n- **Layering.** Smelt ships with a baseline component library; your theme\n  shadows any file. Drop in a `button.css` to restyle without touching markup,\n  TS, or schema. Same pattern as Nuxt Layers or Gatsby shadowing.\n- **Typed schemas.** Author `{% schema %}` blocks in TypeScript with\n  autocomplete derived from Shopify's authoritative JSON Schemas. The build\n  executes the file and injects the result.\n- **Private blocks for free.** Nest a `blocks/` directory under a section or\n  block, and its children become private theme blocks, emitted with Shopify's\n  `_` prefix and auto-merged into the parent's schema. No manual filename\n  mangling.\n- **Additive build.** Only files prefixed `built--` (or `_built--` for private\n  blocks) are written or cleaned. Hand-written theme files are preserved, so you\n  can adopt incrementally.\n\n---\n\n## Contents\n\n- [Example](#example)\n- [Install](#install)\n- [Authoring](#authoring)\n- [Schemas](#schemas)\n- [Private blocks](#private-blocks)\n- [Block faces](#block-faces)\n- [Layering](#layering)\n- [Build](#build)\n- [Learn More](#learn-more)\n- [Future Plans](#future-plans)\n\n---\n\n## Example\n\nA consumer theme writes one directory per component:\n\n```\nsrc/\n├── sections/\n│   └── hero/\n│       ├── hero.liquid\n│       ├── hero.css\n│       └── hero.schema.ts\n└── components/\n    └── card/\n        ├── card.liquid\n        └── card.css\n```\n\n`src/sections/hero/hero.liquid`:\n\n```liquid\n<section class=\"tr-hero\">\n\t<h2>{{ section.settings.heading }}</h2>\n\t{% render '@/components/card', title: 'Hello', body: 'World' %}\n</section>\n```\n\n`src/sections/hero/hero.schema.ts`:\n\n```typescript\nimport { defineSchemaSection } from \"@augeo/smelt/schema\";\n\nexport const schema = defineSchemaSection({\n\tname: \"Hero\",\n\tsettings: [\n\t\t{ type: \"text\", id: \"heading\", label: \"Heading\", default: \"Welcome\" },\n\t],\n\tpresets: [{ name: \"Hero\" }],\n});\n```\n\nCompile:\n\n```bash\nsmelt build\n```\n\nOutputs `sections/built--sections--hero.liquid`,\n`snippets/built--components--card.liquid`, etc. They're flat and namespaced, the\nway Shopify wants.\n\nSee the [📄 `example/`](./example) directory for a working consumer theme.\n\n## Install\n\n```bash\nnpm install -D @augeo/smelt\n```\n\nThis installs the `smelt` CLI and the `@augeo/smelt/schema` import for schema\nauthoring.\n\n## Authoring\n\nEach component is a directory under `src/<type>/<name>/` where `<type>` is\n`sections`, `blocks`, or `components`. Files inside share the directory name:\n\n| File               | Role                                         |\n| ------------------ | -------------------------------------------- |\n| `<name>.liquid`    | Markup (required; anchors the component)     |\n| `<name>.ts`        | Bundled and injected into `{% javascript %}` |\n| `<name>.css`       | Injected into `{% stylesheet %}`             |\n| `<name>.schema.ts` | Typed schema (sections + blocks only)        |\n| `<name>.test.ts`   | Colocated test file, picked up by vitest     |\n\nComponents reference other components with the `@/` alias:\n\n```liquid\n{% render '@/components/button', label: 'Continue' %}\n```\n\n`@/` resolves through the merged layer tree, so a consumer's `button.liquid`\nautomatically shadows the baseline.\n\n## Schemas\n\nAuthor schemas in TypeScript with full type inference:\n\n```typescript\nimport { defineSchemaSection } from \"@augeo/smelt/schema\";\n\nexport const schema = defineSchemaSection({\n\tname: \"Hero\",\n\tsettings: [\n\t\t{ type: \"text\", id: \"heading\", label: \"Heading\" },\n\t\t{\n\t\t\ttype: \"select\",\n\t\t\tid: \"alignment\",\n\t\t\tlabel: \"Alignment\",\n\t\t\toptions: [\n\t\t\t\t{ value: \"left\", label: \"Left\" },\n\t\t\t\t{ value: \"center\", label: \"Center\" },\n\t\t\t],\n\t\t\tdefault: \"center\",\n\t\t},\n\t],\n});\n```\n\nTypes are codegen'd from Shopify's authoritative schemas in\n[`theme-liquid-docs`](https://github.com/Shopify/theme-liquid-docs). Update via\n`npm run docs:update`.\n\nInline `{% schema %}` blocks in `.liquid` files are a build error: a single\nsource of truth.\n\n## Private blocks\n\nShopify treats theme block files prefixed with `_` as **private**: hidden from\nthe merchant's block picker, renderable only via a parent's\n`{% content_for \"blocks\" %}`. Smelt expresses this structurally: a `blocks/`\ndirectory nested under a section or block emits its children with the `_` prefix\nautomatically.\n\n```\nsrc/sections/hero/\n├── hero.liquid\n├── hero.schema.ts\n└── blocks/\n    └── feature/\n        ├── feature.liquid\n        └── feature.schema.ts\n```\n\nCompiles to:\n\n```\nsections/built--sections--hero.liquid\nblocks/_built--sections--hero--blocks--feature.liquid\n```\n\nThe parent's schema auto-merges discovered children into its `blocks: []` array,\nsorted by directory name and prepended; any explicit entries you list (e.g.\nglobally-shared block types) appended after. Nesting is recursive: a private\nblock can have its own `blocks/` subdir.\n\nTop-level `src/blocks/*` files remain public (no `_` prefix).\n\n## Block faces\n\nA `src/components/*` component compiles to a snippet — reusable through\n`{% render %}`, but invisible to the theme editor. A **block face** also exposes\nthat same component as a theme block a merchant can drop onto a page, without\nduplicating it. Declare one with a singular `block/` directory inside the\ncomponent:\n\n```\nsrc/components/card/\n├── card.liquid          # the reusable snippet\n├── card.css\n└── block/\n    └── card.schema.ts   # the block face's schema\n```\n\nCompiles to **both**:\n\n```\nsnippets/built--components--card.liquid   # the snippet, unchanged\nblocks/built--components--card.liquid      # the block face\n```\n\nWith just a schema (no `block/card.liquid`), the face is **mechanical**: the\nbuild synthesizes the wrapper for you — rendering the component, mapping each\nsetting to a render arg of the same name, and passing `shopify_attributes`\nthrough. So name your component's props to match the setting `id`s.\n\n```liquid\n{% # blocks/built--components--card.liquid (generated) %}\n{% render 'built--components--card',\n\ttitle: block.settings.title,\n\tbody: block.settings.body,\n\tshopify_attributes: block.shopify_attributes\n%}\n{% schema %}…{% endschema %}\n```\n\nWhen the wrapper isn't mechanical — derived props, conditional logic, or passing\n`children: block.blocks` — add a `block/card.liquid` and the build uses it as\nthe body verbatim (renders rewritten, schema injected). The face is then just a\nnormal block component living in `block/`, so it can carry its own\n`block/card.ts` / `block/card.css` too.\n\nFaces are **components-only**: sections and blocks don't get them. A block face\ncan own private child blocks by nesting a `blocks/` directory inside `block/` —\nsee [`docs/build-spec.md`](./docs/build-spec.md) for that and the full rules.\n\n## Layering\n\nSmelt walks an ordered list of layers and merges them per-file. The default is:\n\n1. **Consumer:** your theme's `src/` (`process.cwd()`).\n2. **`@augeo/smelt`:** the package's baseline `src/`.\n\nFor each component slot (`liquid`, `ts`, `css`, `schema`), the first layer that\nhas the file wins. Drop just a `button.css` in your consumer to override styles;\nthe baseline's `button.liquid` and `button.ts` are inherited.\n\n## Build\n\n```bash\nsmelt build\n```\n\nRun from the theme root. Outputs go to `sections/built--*.liquid`,\n`blocks/built--*.liquid`, and `snippets/built--*.liquid`, prefixed so they\ncoexist with hand-written files in the same directories.\n\n### Watch mode\n\n```bash\nsmelt dev\n```\n\nRuns an initial build, then watches each layer's `src/` and rebuilds on file\nchanges (add, edit, delete). Build failures log and keep the watcher alive. Pair\nwith `shopify theme dev` (in another terminal or via\n[`concurrently`](https://www.npmjs.com/package/concurrently)): `smelt dev`\nwrites the built files; `shopify theme dev` uploads them.\n\n### Committing the output\n\nShopify imports themes from git, so `built--*` files (and `_built--*` for\nprivate blocks) need to be **committed** alongside source. Two configs keep the\nnoise down:\n\n`.gitattributes` marks output as generated so GitHub collapses it in PR diffs\nand excludes it from language stats:\n\n```\nsections/built--*.liquid linguist-generated=true\nsnippets/built--*.liquid linguist-generated=true\nblocks/built--*.liquid linguist-generated=true\nblocks/_built--*.liquid linguist-generated=true\n```\n\n`.prettierignore` skips the output so Prettier doesn't reformat it between\nbuilds:\n\n```\nsections/built--*.liquid\nsnippets/built--*.liquid\nblocks/built--*.liquid\nblocks/_built--*.liquid\n```\n\n### CI: verify the build is committed\n\nBecause the `built--*` files are committed, they can drift from source: someone\nedits a component but forgets to rebuild, or commits a stale build. Catch it in\nCI by rebuilding and failing if the working tree is dirty: a clean tree means\nthe committed output already matches source.\n\n`.github/workflows/verify.yml`:\n\n```yaml\nname: Verify\n\non:\n  push:\n    branches: [main]\n  pull_request:\n\njobs:\n  verify:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v5\n\n      - uses: actions/setup-node@v5\n        with:\n          node-version-file: \"package.json\"\n          cache: \"npm\"\n\n      - run: npm ci\n\n      - name: Build\n        run: npm run build # → smelt build\n\n      - name: Check built files match source\n        run: |\n          if [ -n \"$(git status --porcelain)\" ]; then\n            echo \"::error::Build produced uncommitted changes. Did you forget to commit a rebuild?\"\n            git status --porcelain\n            git diff\n            exit 1\n          fi\n```\n\nThe build is [additive](#build) and deterministic: it only writes `built--*`\nfiles, so a rebuild on a current tree produces no diff. Any change to\n`git status` means the commit is missing a rebuild.\n\nIf you run other checks (tests, `shopify theme check`), put the build step\n**first** so the job fails fast when the committed output is stale. There's no\npoint linting and testing a tree you already know is out of date. See this\nrepo's own [`verify.yml`](./.github/workflows/verify.yml) for the full pattern,\nincluding git submodules and a Playwright browser for the test suite.\n\n## Learn More\n\n- [📄 Build Spec](./docs/build-spec.md): pipeline, alias rules, conventions\n- [📄 Testing Conventions](./docs/TESTING.md): how to write tests against the\n  built output\n- [`@augeo/assay`](https://www.npmjs.com/package/@augeo/assay): the test runner\n  Smelt uses\n\n## Future Plans\n\n- **`smelt.config.ts`:** consumer-defined layer list, enabling N-layer\n  composition (e.g., a community component pack between consumer and baseline).\n- **More baseline components.** Currently just `button` demo. Expanding to a\n  real default set.\n","readmeFilename":"README.md"}