diff --git a/CHANGELOG.md b/CHANGELOG.md
index d8c543c..f69fe2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,28 @@ All notable changes follow [Keep a Changelog](https://keepachangelog.com/) and t
## [Unreleased]
+### Added
+
+- Shopify-native component CSS and JavaScript in the reference storefront through `{% stylesheet %}` and `{% javascript %}` tags.
+- Theme-block-first product composition with merchant-reorderable vendor, title, price, purchase, description, `@theme`, and `@app` blocks.
+- Shopify standard storefront view events for product, collection, recommendation, and cart surfaces, plus cart mutation through `Shopify.actions.updateCart()` with the native product form retained as the no-JavaScript fallback.
+- Shopify `color_palette` design tokens and `` customer-account integration in the fresh reference theme.
+- A documented compiled-branch/deployment-repository workflow and opt-in GitHub Actions recipe for Shopify GitHub theme integration.
+- A complete Shopify 2026 modernization plan covering architecture, compatibility constraints, implementation order, and real-store acceptance criteria.
+
+### Changed
+
+- Fresh projects now default to Shopify-native static/component assets with `viteConfig: false` instead of requiring a Vite/Tailwind storefront bundle.
+- Vite and Tailwind remain supported framework integrations but are now documented as explicit optional asset strategies rather than the framework's product identity.
+- The reference product, header, predictive search, collection, featured collection, and cart surfaces now demonstrate current Shopify-native platform primitives.
+- The embedded `create-liquid-loom` starter stays byte-for-byte synchronized with the modernized reference storefront and targets Shopify CLI 4.8+ for new projects.
+- README, recipes, and roadmap now describe Liquid Loom as a deterministic engineering layer for Shopify Liquid themes and sequence platform modernization after the `0.3` project-intelligence work.
+
+### Removed
+
+- The fresh starter's default global Vite entrypoint, Tailwind stylesheet source, and bundled `theme.js`/`style.css` architecture.
+- The obsolete default Vite configuration from the reference project and embedded starter. Existing projects that explicitly enable Vite remain supported.
+
## [0.2.0] - 2026-09-09
### Added
diff --git a/README.md b/README.md
index f09408c..3ffe3f4 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-
A deterministic engineering layer for Shopify themes, from legacy adoption to agent-readable architecture.
+
A deterministic engineering layer for Shopify Liquid themes, from legacy adoption to agent-readable architecture.
@@ -15,9 +15,9 @@
Liquid Loom gives Shopify theme development a safer, source-first engineering layer while keeping Shopify's runtime completely standard.
-Use it to organize new code by feature, add modern tooling to an existing client theme without a rewrite, migrate gradually when it is worth it, understand source ownership before an agent edits the project, and still ship a normal Shopify theme through Shopify CLI.
+Use it to organize theme code by feature, adopt better tooling inside an existing client theme without a rewrite, migrate source gradually, inspect project ownership before a developer or coding agent edits it, and still ship a conventional Shopify theme through Shopify CLI.
-It does **not** replace Liquid, Online Store 2.0, Shopify CLI, or Shopify's runtime model. Vite and Tailwind are first-class integrations for fresh projects, not abstractions that Liquid Loom depends on for its identity.
+Liquid Loom does **not** replace Liquid, Online Store 2.0, Shopify CLI, the Theme Editor, or Shopify's storefront runtime.
## Start with the theme you already have
@@ -29,7 +29,7 @@ npx liquid-loom@latest init
Liquid Loom shows the complete setup plan before writing anything. Existing Shopify source is not moved.
-After setup, keep the current theme exactly as it is:
+You can keep the theme exactly as it is:
```text
assets/
@@ -39,19 +39,19 @@ snippets/
templates/
```
-and put only new work into organized source when you want to:
+and put only new work into organized source when that helps:
```text
src/theme/sections/product/upsell.liquid
src/theme/snippets/product/upsell-price.liquid
```
-Both become one normal deployable theme:
+Both source layers become one normal deployable theme:
```text
existing Shopify source ----+
|
-organized Liquid Loom source +--> deterministic ownership plan --> dist/theme --> Shopify CLI
+organized Liquid Loom source +--> ownership plan --> dist/theme --> Shopify CLI
```
Build with the namespaced script added by `init`:
@@ -60,9 +60,9 @@ Build with the namespaced script added by `init`:
npm run loom:build
```
-Use your preferred package manager. `init` detects npm, pnpm, Yarn, or Bun and supports `--package-manager`, `--no-install`, `--dry-run`, `--theme-dir`, and `--yes`.
+`init` detects npm, pnpm, Yarn, or Bun and supports `--package-manager`, `--no-install`, `--dry-run`, `--theme-dir`, and `--yes`.
-Read the full [existing-theme adoption guide](docs/EXISTING_THEME_ADOPTION.md).
+Read [Existing-theme adoption](docs/EXISTING_THEME_ADOPTION.md) for the full zero-migration workflow.
## Or start a new theme
@@ -71,101 +71,136 @@ corepack enable
pnpm create liquid-loom@latest my-storefront
cd my-storefront
pnpm build
-```
-
-Then preview against a Shopify development store:
-
-```bash
pnpm dev
```
-The scaffolder supports `--package-manager npm|pnpm|yarn|bun` and `--no-install`.
+A fresh project uses Shopify-native component CSS and JavaScript by default. Vite and Tailwind remain supported integrations when a project actually needs bundling, module graphs, or utility-first CSS.
## Why Liquid Loom
-Liquid Loom targets the parts of custom theme development that become painful as projects, teams, and coding agents grow:
+Liquid Loom targets the engineering problems that become painful as custom themes, teams, and coding agents grow:
- **Adopt incrementally.** Existing themes do not need an up-front rewrite.
- **Feature-oriented source.** Organize authored Liquid by feature without inventing a new runtime.
- **Dual-source builds.** Native Shopify source and organized Liquid Loom source can coexist safely.
-- **No silent precedence.** Every Shopify output path has exactly one owner.
-- **No silent overwrites.** Destination collisions fail before a new build is published.
-- **Last-known-good output.** Failed builds do not replace the previous working theme.
-- **Transactional migration.** Preview first, preserve Shopify output identity, and roll back completed moves if a later move fails.
+- **One output, one owner.** No silent overlay or last-write-wins behavior.
+- **Transactional builds.** Failed builds never replace the last-known-good theme.
+- **Safe migration.** Preview ownership transfers before moving source and preserve Shopify output identity.
- **Project intelligence.** `explain` turns ownership and provable static relationships into deterministic human- and machine-readable data.
-- **Preview-aware, not preview-dependent.** Shopify developer-preview Liquid is explicit and observable instead of silently becoming a production requirement.
-- **Optional Vite + Tailwind.** Fresh projects get the modern asset workflow; existing themes can keep their current pipeline.
-- **Portable behavior.** Collision checks are case-insensitive and Unicode-normalized across filesystems.
+- **Shopify-native defaults.** Theme blocks, app blocks, component asset tags, color palettes, customer accounts, and standard storefront interoperability stay visible as Shopify concepts.
+- **Optional advanced assets.** Vite and Tailwind remain available without defining the framework's architecture.
+- **Portable behavior.** Destination collisions are case-insensitive and Unicode-normalized across filesystems.
- **Useful diagnostics.** `doctor`, `check`, `analyze`, Theme Check, and performance budgets make failures explainable.
-- **Standard Shopify output.** `dist/theme` remains inspectable, pushable, and debuggable with Shopify's own tooling.
+- **Standard output.** `dist/theme` remains inspectable, pushable, and debuggable with Shopify's own tools.
-## Understand the theme before editing it
+## Shopify-native fresh-project architecture
-Liquid Loom can describe the source model without requiring a build first:
+The reference storefront now demonstrates Shopify's 2026-native theme model instead of loading one application bundle for ordinary theme behavior.
-```bash
-liquid-loom explain
-liquid-loom explain product
-```
-
-Coding agents and CI can request deterministic JSON:
+A fresh source tree can look like:
-```bash
-liquid-loom explain --json
-liquid-loom explain product --json
+```text
+src/
+├── public/
+│ └── theme.css
+└── theme/
+ ├── blocks/
+ │ ├── product-title.liquid
+ │ ├── product-price.liquid
+ │ └── product-purchase.liquid
+ ├── sections/
+ │ ├── products/main-product.liquid
+ │ └── global/header.liquid
+ ├── snippets/
+ ├── templates/
+ └── layout/theme.liquid
```
-The model reports source ownership, semantic feature groups, static snippet/section/block/asset relationships, JSON-template section references, preview partial regions, preview-tag usage, and unresolved static references.
+Component-local behavior lives with the Liquid component when practical:
-It does not evaluate Liquid or guess dynamic dependencies. The goal is a smaller truthful architecture model, not a second Liquid interpreter.
+```liquid
+{% stylesheet %}
+ .product-purchase { ... }
+{% endstylesheet %}
-Read [Project model](docs/PROJECT_MODEL.md) for the complete contract and recommended agent workflow.
+{% javascript %}
+ customElements.define(...)
+{% endjavascript %}
+```
-## The source model
+Shopify can then process component assets through its own render-aware pipeline. Global CSS is reserved for genuinely global concerns such as base styles, design tokens, accessibility defaults, and shared layout primitives.
-A fresh Liquid Loom project can look like this:
+The output stays conventional:
```text
-src/theme/sections/home/hero.liquid
-src/theme/sections/product/recommendations.liquid
-src/theme/snippets/product/price.liquid
-src/entrypoints/theme.js
-src/styles/theme.css
+dist/theme/
+├── assets/theme.css
+├── blocks/product-title.liquid
+├── blocks/product-price.liquid
+├── blocks/product-purchase.liquid
+├── sections/main-product.liquid
+├── snippets/
+├── templates/product.json
+└── layout/theme.liquid
```
-Liquid Loom produces:
+## Theme-block-first composition
+
+The reference product page is composed from Shopify theme blocks rather than hard-coding all product information into one monolithic section.
```text
-dist/theme/sections/hero.liquid
-dist/theme/sections/recommendations.liquid
-dist/theme/snippets/price.liquid
-dist/theme/assets/theme.js
-dist/theme/assets/style.css
+Main product
+├── Product media
+└── Merchant-reorderable blocks
+ ├── Vendor
+ ├── Title
+ ├── Price
+ ├── Purchase controls
+ ├── Description
+ ├── @theme
+ └── @app
```
-An adopted project may simultaneously contain:
+This keeps customization inside Shopify's Theme Editor and makes the structure understandable to merchants, developers, apps, and coding agents without adding a Liquid Loom component runtime.
-```text
-sections/header.liquid
-assets/legacy-theme.css
-src/theme/sections/product/upsell.liquid
+## Storefront interoperability
+
+The reference storefront adopts Shopify's standard storefront events and actions where the theme owns the interaction.
+
+Examples include:
+
+- standardized product, collection, recommendation, and cart view events through `s-view-event` and `standard_event_data`;
+- cart mutation through `Shopify.actions.updateCart()` with the native product form retained as the no-JavaScript fallback;
+- merchant-configurable `` integration in the header;
+- `color_palette` as the source for semantic CSS design tokens.
+
+The goal is interoperability with Shopify, apps, and agents, not a Liquid Loom-specific browser protocol.
+
+## Understand the theme before editing it
+
+Liquid Loom can describe the project without evaluating Liquid or requiring a build first:
+
+```bash
+liquid-loom explain
+liquid-loom explain product
```
-and produce:
+Coding agents and CI can request deterministic JSON:
-```text
-dist/theme/sections/header.liquid
-dist/theme/sections/upsell.liquid
-dist/theme/assets/legacy-theme.css
+```bash
+liquid-loom explain --json
+liquid-loom explain product --json
```
-Shopify still receives the conventional structure it expects.
+The model reports source ownership, semantic feature groups, static snippet/section/block/asset relationships, JSON-template section references, preview partial regions, preview-tag usage, and unresolved static references.
+
+It intentionally does not guess dynamic Liquid relationships. Read [Project model](docs/PROJECT_MODEL.md) for the complete contract.
## One output, one owner
There is intentionally no "new source wins" rule.
-This fails:
+This is invalid:
```text
sections/hero.liquid
@@ -178,13 +213,13 @@ because both map to:
sections/hero.liquid
```
-Liquid Loom validates the global ownership plan before changing the last-known-good output and tells you which sources collide.
+Liquid Loom plans the complete ownership map before publishing a build and reports the conflicting owners instead of silently overwriting one of them.
-The same ownership model includes generated asset reservations when Vite is enabled.
+Generated Vite outputs participate in the same ownership map when Vite is enabled.
## Migrate only when it helps
-Preview migration of one file:
+Preview a migration:
```bash
liquid-loom migrate sections/hero.liquid
@@ -196,7 +231,7 @@ Apply it:
liquid-loom migrate sections/hero.liquid --apply
```
-Organize it during migration:
+Organize it while preserving its Shopify identity:
```bash
liquid-loom migrate sections/hero.liquid \
@@ -204,141 +239,85 @@ liquid-loom migrate sections/hero.liquid \
--apply
```
-The Shopify output must remain `sections/hero.liquid`. If the requested destination would change the deployable path, Liquid Loom refuses the migration.
+The deployable path must remain `sections/hero.liquid`. Liquid Loom rejects a migration that would silently rename Shopify output.
-Migrate a directory:
+Bulk migration remains optional:
```bash
liquid-loom migrate sections --apply
-```
-
-Or preview/apply all remaining native theme source:
-
-```bash
liquid-loom migrate --all
liquid-loom migrate --all --apply
```
-Liquid Loom never invents your feature taxonomy during bulk migration.
+Liquid Loom never invents a feature taxonomy for existing source.
-## Existing asset pipelines are allowed
+## Asset strategies
-Existing-theme initialization defaults to:
+### Shopify-native default
-```js
-import { defineConfig } from "liquid-loom";
+Fresh projects default to `viteConfig: false` and use static global assets plus `{% stylesheet %}` / `{% javascript %}` for component-local code.
-export default defineConfig({
- shopifySourceDir: ".",
- sourceDir: "src",
- outputDir: "dist/theme",
- viteConfig: false,
- performance: false
-});
-```
-
-That means native `assets/*` pass through unchanged and your existing Sass/PostCSS/Webpack/Vite process can keep running independently.
-
-Fresh projects still use Liquid Loom's Vite + Tailwind workflow by default. Tailwind remains an integration choice rather than part of the source-ownership contract.
-
-If `src/entrypoints` exists while Vite is disabled, `doctor` warns that those files are not being compiled.
+### Existing pipeline
-## Shopify mapping contract
-
-| Authoring source | Deployable Shopify path | Rule |
-| ----------------------------------------------- | -------------------------------------- | ------------------------------------- |
-| `sections/hero.liquid` | `sections/hero.liquid` | Native Shopify identity mapping |
-| `src/theme/sections/home/hero.liquid` | `sections/hero.liquid` | Organized source flattens by filename |
-| `src/theme/snippets/product/price.liquid` | `snippets/price.liquid` | Organized source flattens by filename |
-| `src/theme/config/editor/settings_schema.json` | `config/settings_schema.json` | Flatten by filename |
-| `src/theme/locales/markets/en.default.json` | `locales/en.default.json` | Flatten by filename |
-| `src/theme/templates/catalog/product.json` | `templates/product.json` | Feature folders flatten |
-| `templates/customers/account.json` | `templates/customers/account.json` | Preserve Shopify-supported nesting |
-| `src/theme/templates/metaobject/book.json` | `templates/metaobject/book.json` | Preserve Shopify-supported nesting |
-| `src/public/icons/cart.svg` | `assets/cart.svg` | Flatten passthrough assets |
-| `src/entrypoints/theme.js` + `src/styles/*.css` | `assets/theme.js` + `assets/style.css` | Vite-generated outputs when enabled |
-
-Framework validation checks Shopify's upload minimum from the final ownership plan: `layout/theme.liquid` must exist in deployable output, regardless of which source layer owns it.
-
-For Shopify's canonical directory rules, see the official [theme architecture documentation](https://shopify.dev/docs/storefronts/themes/architecture).
-
-## Build guarantees
+An adopted theme can keep Sass, PostCSS, Webpack, Vite, Tailwind, or another existing pipeline unchanged. Native `assets/*` pass through as Shopify assets.
-### Complete planning before publish
+### Optional Vite and Tailwind
-Source discovery, Shopify path validation, traversal guards, collision detection, and generated-output reservations happen before a new output is promoted.
+Projects that need bundling can explicitly enable Vite and reserve stable generated Shopify asset names. Tailwind remains available through the native Tailwind Vite plugin.
-### Last-known-good output
+The framework still validates static and generated outputs in one collision map.
-Static mapping and optional Vite bundling happen in isolated staging paths. Output and cache are promoted together only after the build succeeds.
+See [Recipes](docs/RECIPES.md) for setup examples.
-### Safe concurrent builds
+## Shopify GitHub deployment
-Independent CLI processes serialize through a recoverable project lock. An abandoned lock from a terminated process is detected and removed.
+A Liquid Loom source branch contains development files that Shopify's GitHub theme integration does not treat as the deployable theme root.
-### Migration-safe caching
-
-Hybrid manifests track source-layer identity. Moving ownership from:
-
-```text
-sections/hero.liquid
-```
-
-to:
+For GitHub-connected themes, use a generated `shopify-production` branch or a separate deployment repository containing only the canonical Shopify theme directories:
```text
-src/theme/sections/home/hero.liquid
+main
+ |
+ | validate + build
+ v
+shopify-production
+ |
+ v
+Shopify GitHub integration
```
-does not cause `sections/hero.liquid` to be removed as stale.
-
-### Consumer-shaped release validation
+The repository includes an opt-in deployment recipe that publishes compiled output without force-pushing and avoids deployment loops from Shopify-originated commits.
-CI packs the actual npm artifacts, installs both CLIs into independent temporary projects, validates `explain` from the packed package, validates a fresh scaffold, and validates an existing-theme `init -> hybrid build -> migrate -> build` flow.
+Read [Shopify GitHub deployment](docs/GITHUB_DEPLOYMENT.md).
-Releases use npm Trusted Publishing with GitHub OIDC and signed provenance.
+## Shopify Liquid preview mode
-## Configuration
+Shopify's July 2026 `{% block %}` / `{% partial %}` developer preview is never enabled implicitly.
-Fresh project example:
+Projects intentionally targeting it can declare:
```ts
-import { defineConfig } from "liquid-loom";
-
export default defineConfig({
- sourceDir: "src",
- outputDir: "dist/theme",
- performance: {
- maxBuildMs: 10_000,
- maxThemeBytes: 5_000_000,
- maxAssetBytes: 500_000
- }
+ shopifyLiquidMode: "july-2026-preview"
});
```
-Existing theme in a monorepo:
+This records project intent for diagnostics and project intelligence. It does not enable the preview on a Shopify store.
-```ts
-export default defineConfig({
- shopifySourceDir: "theme",
- sourceDir: "src",
- outputDir: "dist/theme",
- viteConfig: false,
- performance: false
-});
-```
+Read [Shopify Liquid July 2026 developer preview](docs/LIQUID_JULY_2026_PREVIEW.md).
-All paths remain project-relative and portable.
+## Build guarantees
-Shopify's July 2026 Liquid developer-preview syntax is never enabled implicitly. Projects intentionally targeting that preview can declare:
+Liquid Loom keeps the existing engineering guarantees regardless of asset strategy:
-```ts
-export default defineConfig({
- shopifyLiquidMode: "july-2026-preview"
-});
-```
+1. discover all managed source;
+2. map the complete Shopify ownership plan;
+3. validate paths, collisions, and Shopify's upload minimum;
+4. build in isolated staging;
+5. optionally run Vite and performance budgets;
+6. atomically promote output and cache together.
-This only declares project intent to Liquid Loom; it does not enable the preview on a Shopify development store. See [Shopify Liquid July 2026 developer preview](docs/LIQUID_JULY_2026_PREVIEW.md).
+A failed build leaves the previous deployable output intact. Independent CLI processes serialize through a recoverable project lock.
## Commands
@@ -358,58 +337,64 @@ This only declares project intent to Liquid Loom; it does not enable the preview
Scaffolded projects expose package-manager scripts for the same commands. Existing-theme `init` uses namespaced `loom:*` scripts so it does not replace a project's existing `build` or `dev` commands.
+## Reference storefront
+
+The fresh-project scaffold is a merchant-neutral reference theme that demonstrates:
+
+- Shopify theme blocks and app blocks;
+- merchant-reorderable product information and purchase controls;
+- Shopify-native component CSS and JavaScript;
+- standard storefront view events and cart actions;
+- `color_palette` design tokens;
+- `` customer-account integration;
+- JSON templates and editable header/footer section groups;
+- storefront filtering and predictive search;
+- variant URL state, selling plans, quantities, and progressive enhancement;
+- responsive images, semantic navigation, skip links, visible focus states, reduced-motion support, and no-JavaScript fallbacks.
+
+It is a reference implementation. The product is Liquid Loom's engineering layer and workflow.
+
## Who it is for
Liquid Loom is a good fit when you:
-- maintain a custom or client Shopify theme and want better tooling without rewriting it;
+- maintain a custom or client Shopify theme and want stronger tooling without rewriting it;
- want new theme work organized by feature rather than only by Shopify's flat directories;
-- want deterministic build ownership and explicit collision behavior;
-- want coding agents to query a conservative architectural model before editing source;
-- expect modern frontend build and CI guarantees from the rest of your stack.
+- need deterministic ownership and collision behavior;
+- want coding agents to inspect a conservative architectural model before editing source;
+- want Shopify-native theme capabilities without giving up modern engineering guarantees.
It is probably not the right starting point when:
- the theme is tiny and needs no build pipeline;
- you are building a headless storefront rather than a Shopify Liquid theme;
-- your primary goal is Shopify Theme Store submission, where Shopify's official starting points and policies should remain authoritative.
-
-## Reference storefront
-
-The fresh-project scaffolder includes a merchant-neutral Online Store 2.0 reference theme with theme blocks, JSON templates, editable header/footer groups, storefront filtering, predictive search, variant URL state, selling plans, responsive images, semantic navigation, reduced-motion support, visible focus states, and no-JavaScript fallbacks.
-
-It is a reference implementation. The product is the tooling and workflow.
-
-## Validation and feedback
-
-Liquid Loom is being validated against real Shopify workflows, not just repository metrics.
+- your primary goal is Shopify Theme Store submission, where Shopify's official starting points and policies remain authoritative.
-Useful evidence includes:
+## Validation
-- a successful public-package install;
-- a real Shopify development-store preview;
-- existing-theme adoption without source migration;
-- incremental migration on a real client-style repository;
-- coding-agent use of the deterministic project model;
-- developers independently choosing the workflow again.
+Protected CI validates:
-If you try it, feedback about what is confusing, slower, or worse is especially useful.
+- unit and integration tests with coverage thresholds;
+- transactional clean builds;
+- zero-offense Shopify Theme Check;
+- Linux/Node 22, Windows/Node 24, and macOS/Node 24 portability;
+- packed-package installation and fresh-scaffold smoke tests;
+- Dependency Review and CodeQL;
+- a non-blocking Node 26 canary.
-- [Run the first-project test](docs/FIRST_PROJECT.md)
-- [Read the existing-theme adoption guide](docs/EXISTING_THEME_ADOPTION.md)
-- [Share first-project feedback](https://github.com/yotamon/Liquid-Loom/issues/new?template=early_adopter_feedback.yml)
-- [Report a bug](https://github.com/yotamon/Liquid-Loom/issues/new?template=bug_report.yml)
-- [Start a discussion](https://github.com/yotamon/Liquid-Loom/discussions)
+Real-store validation remains separate from public CI so contributors do not need Shopify credentials.
## Documentation
+- [Shopify 2026 platform modernization](docs/SHOPIFY_2026_MODERNIZATION.md) - architecture decisions and acceptance criteria
- [Existing-theme adoption](docs/EXISTING_THEME_ADOPTION.md) - zero-migration setup, hybrid source, and safe migration
- [Project model](docs/PROJECT_MODEL.md) - deterministic architecture queries for developers, agents, and CI
- [Shopify Liquid July 2026 developer preview](docs/LIQUID_JULY_2026_PREVIEW.md) - explicit preview-mode contract and safety boundaries
+- [Shopify GitHub deployment](docs/GITHUB_DEPLOYMENT.md) - compiled deployment branches and write-back constraints
- [First project](docs/FIRST_PROJECT.md) - short evaluation from public install to a real source edit
- [Architecture](docs/ARCHITECTURE.md) - ownership, transactions, cache, and migration invariants
- [Validation](docs/VALIDATION.md) - real-user and real-store validation plan
-- [Recipes](docs/RECIPES.md) - entrypoints, static assets, private-term policies, and budgets
+- [Recipes](docs/RECIPES.md) - native assets, optional bundling, private-term policies, and budgets
- [Troubleshooting](docs/TROUBLESHOOTING.md) - collisions, locks, Shopify CLI, and build failures
- [Benchmarks](docs/BENCHMARKS.md) - reproducible build measurements
- [Releasing](docs/RELEASING.md) - provenance-backed npm release process
@@ -421,12 +406,12 @@ If you try it, feedback about what is confusing, slower, or worse is especially
- Adopt tooling before forcing migration.
- Source ownership must be explicit.
- Shopify's runtime contract stays visible.
-- Integrate with Shopify primitives instead of duplicating them.
+- Prefer Shopify primitives over competing abstractions.
- Generated output is disposable; authored source is the product.
- Prefer provable project intelligence over guessed relationships.
- Fail early, explain specifically, and preserve the last-known-good build.
- Treat Vite and Tailwind as replaceable integrations, not the framework's durable moat.
-- Prefer a dependable core over speculative abstractions.
+- Keep preview APIs explicit until Shopify stabilizes them.
- Add framework surface only after real users demonstrate the need.
diff --git a/ROADMAP.md b/ROADMAP.md
index 6791d29..c5b3987 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -73,7 +73,38 @@ Now proving:
See [Project model](docs/PROJECT_MODEL.md) and [Shopify Liquid July 2026 developer preview](docs/LIQUID_JULY_2026_PREVIEW.md).
-## 0.4 - Extension surface, if earned
+## 0.4 - Shopify 2026 platform modernization
+
+Modernize fresh-project defaults and the reference storefront around Shopify's current native theme capabilities without weakening the `0.2` ownership/migration guarantees or the `0.3` project-intelligence model.
+
+Implemented in the modernization PR:
+
+- [x] make Shopify-native `{% stylesheet %}` / `{% javascript %}` component assets the preferred fresh-project path where practical;
+- [x] keep Vite and Tailwind as explicit, tested optional asset strategies rather than Liquid Loom's product identity;
+- [x] make theme blocks and merchant-reorderable composition central to the reference storefront, especially product information and purchase surfaces;
+- [x] implement relevant Shopify standard storefront view events and cart actions in the reference theme;
+- [x] move the reference color system to `color_palette` plus semantic CSS custom properties;
+- [x] adopt the `` component with a merchant-configurable account menu;
+- [x] add a documented compiled branch/deployment-repository workflow and opt-in GitHub Actions recipe for Shopify GitHub integration;
+- [x] target Shopify CLI 4.8+ in fresh scaffolds and document disposable dev-store validation;
+- [x] preserve explicit `stable` / `july-2026-preview` modes and keep preview syntax outside the stable release gate;
+- [x] preserve zero-migration adoption and existing asset pipelines for established themes;
+- [x] add automated capability tests and keep the reference storefront byte-for-byte synchronized with the embedded starter.
+
+Still requiring real Shopify evidence before calling the milestone complete:
+
+- [ ] preview the modernized fresh scaffold on a Shopify development store;
+- [ ] verify product-block reordering and app-block placement in Theme Editor;
+- [ ] verify `` with customer accounts enabled and disabled;
+- [ ] verify palette editing through Theme Editor;
+- [ ] verify standard storefront event/action behavior in a real browser session;
+- [ ] verify the compiled deployment branch against Shopify GitHub integration and confirm Shopify-originated commits do not create a deployment loop;
+- [ ] run the modernization against at least one established client-style theme without changing its existing asset pipeline;
+- [ ] extend project intelligence only if those real workflows expose new statically provable relationships worth modeling.
+
+See [Shopify 2026 platform modernization](docs/SHOPIFY_2026_MODERNIZATION.md) for the full architecture decisions, compatibility constraints, implementation order, and acceptance criteria.
+
+## 0.5 - Extension surface, if earned
Only after repeated consumer needs justify a public extension API:
@@ -97,5 +128,6 @@ Only after repeated consumer needs justify a public extension API:
- Requiring migration before an existing theme can receive value from Liquid Loom.
- Guessing dynamic Liquid relationships in order to make the project model look more complete.
- Making developer-preview Liquid syntax the default before Shopify stabilizes it.
+- Introducing a second storefront runtime to imitate headless frameworks.
See [Validation](docs/VALIDATION.md) for the evidence expected before broadening the public API.
diff --git a/docs/GITHUB_DEPLOYMENT.md b/docs/GITHUB_DEPLOYMENT.md
new file mode 100644
index 0000000..34c2f53
--- /dev/null
+++ b/docs/GITHUB_DEPLOYMENT.md
@@ -0,0 +1,62 @@
+# Shopify GitHub deployment
+
+Liquid Loom intentionally keeps authored source separate from deployable Shopify output. Shopify's GitHub theme integration, however, expects the connected branch to contain Shopify's canonical theme directories.
+
+For repositories that use `src`, tests, and build tooling, connect Shopify to a **compiled deployment branch** or a separate deployment repository rather than to the authored branch.
+
+## Recommended topology
+
+```text
+main
+├── src/
+├── tests/
+├── liquid-loom.config.ts
+└── package.json
+ |
+ | CI: install -> validate -> build
+ v
+shopify-production
+├── assets/
+├── blocks/
+├── config/
+├── layout/
+├── locales/
+├── sections/
+├── snippets/
+└── templates/
+ |
+ v
+Shopify GitHub integration
+```
+
+The deployment branch is generated output. `main` remains the source of truth.
+
+## Safe CI policy
+
+Use a workflow triggered only by authored branches. Never trigger the build from `shopify-production` itself; that prevents a Shopify-originated commit on the connected branch from creating a deployment loop.
+
+When publishing:
+
+1. fetch the current `shopify-production` head;
+2. create a worktree from that head so the new deployment is a fast-forward commit;
+3. replace only the canonical Shopify theme directories with `dist/theme`;
+4. commit only when the compiled output changed;
+5. push without `--force`.
+
+A concurrent Shopify write will make the push fail rather than silently overwrite history. Re-run only after reviewing the branch state.
+
+See [`docs/examples/shopify-deploy.yml`](examples/shopify-deploy.yml) for an opt-in workflow recipe.
+
+## Theme Editor writes
+
+A compiled branch can't automatically translate Theme Editor changes back into organized source. Choose one of these policies explicitly:
+
+- **Source-authoritative:** Theme Editor changes on the deployment branch are temporary and the next successful source deployment may replace them. Keep history so drift can be reviewed first.
+- **Reconciliation workflow:** review Shopify-originated commits and manually port intentional changes into authored source before the next deployment.
+- **Separate deployment repository:** use this when you want stronger operational separation between authored source and generated theme output.
+
+Do not pretend two-way synchronization is lossless when a build step changes source shape.
+
+## Development stores
+
+For protected integration CI, Shopify CLI 4.8+ can create a disposable dev store, preview the built theme, run browser smoke tests, and remove the store afterwards. Public CI should continue to run without Shopify credentials.
diff --git a/docs/RECIPES.md b/docs/RECIPES.md
index bb3ffdb..7c10150 100644
--- a/docs/RECIPES.md
+++ b/docs/RECIPES.md
@@ -8,21 +8,53 @@ Place a file anywhere under `src/public/`. Its basename becomes the Shopify asse
src/public/icons/cart.svg → dist/theme/assets/cart.svg
```
-Basenames must be unique across the entire public tree and cannot be `theme.js` or `style.css` unless generated-output configuration changes with matching Vite output.
+Basenames must be unique across the entire public tree. When Vite is enabled, static assets also cannot collide with any configured generated output.
-## Add a section or snippet
+## Add component CSS or JavaScript
-Organize by feature; Shopify’s destination remains flat:
+Fresh Liquid Loom projects prefer Shopify-native component assets:
+
+```liquid
+{% stylesheet %}
+ .product-card {
+ display: grid;
+ }
+{% endstylesheet %}
+
+{% javascript %}
+ customElements.define('product-card', class extends HTMLElement {});
+{% endjavascript %}
+```
+
+Keep truly global styles in a static file such as `src/public/theme.css`. Liquid doesn't render inside `{% stylesheet %}` or `{% javascript %}` tags, so pass dynamic values through markup, data attributes, or CSS custom properties.
+
+## Add a section, block, or snippet
+
+Organize by feature; Shopify's destination remains flat:
```text
src/theme/sections/editorial/story.liquid → dist/theme/sections/story.liquid
+src/theme/blocks/product/title.liquid → dist/theme/blocks/title.liquid
```
Run `pnpm build` immediately after adding the file. Portable collisions fail before the output changes.
-## Add another Vite entrypoint
+## Opt into Vite or Tailwind
+
+The fresh starter uses Shopify-native assets by default, but the framework still supports Vite and Tailwind. Add a Vite config and enable it explicitly:
+
+```ts
+export default defineConfig({
+ viteConfig: "vite.config.js",
+ reservedOutputs: ["assets/theme.js", "assets/style.css"]
+});
+```
+
+Install the asset tooling your project needs and configure stable output names. Generated outputs participate in the same ownership/collision plan as authored Shopify assets.
+
+## Deploy compiled output through Shopify GitHub integration
-Extend `rollupOptions.input` and give its output a stable name in `vite.config.js`. Add that output to `reservedOutputs` in `liquid-loom.config.ts` so a public asset cannot overwrite it.
+If your source repository contains `src`, tests, and build tooling, connect Shopify to a generated branch or separate deployment repository that contains only canonical Shopify theme directories. See [GitHub deployment](GITHUB_DEPLOYMENT.md).
## Scan for organization-specific terms
diff --git a/docs/SHOPIFY_2026_MODERNIZATION.md b/docs/SHOPIFY_2026_MODERNIZATION.md
new file mode 100644
index 0000000..ac675a2
--- /dev/null
+++ b/docs/SHOPIFY_2026_MODERNIZATION.md
@@ -0,0 +1,404 @@
+# Shopify 2026 platform modernization
+
+Liquid Loom's core architecture still fits Shopify theme development in 2026: it keeps Liquid and Shopify CLI authoritative, produces a canonical Shopify theme, makes output ownership explicit, and lets established themes adopt tooling without an up-front rewrite.
+
+The next modernization step is therefore not a framework rewrite. It is a change in **defaults and reference architecture** so that fresh Liquid Loom projects demonstrate Shopify's strongest current theme primitives instead of treating Vite + Tailwind as the center of the product.
+
+This plan builds on the `0.3` project-intelligence work. The deterministic project model, `explain`, explicit `shopifyLiquidMode`, and preview-aware diagnostics remain part of the foundation.
+
+## Decision
+
+Liquid Loom should be described as:
+
+> A deterministic engineering layer for Shopify Liquid themes: safer source architecture, incremental adoption, agent-readable project understanding, modern Shopify-native composition, and optional advanced asset tooling.
+
+Vite and Tailwind stay supported. They stop being the default explanation for why Liquid Loom exists.
+
+## Core invariants that do not change
+
+1. Liquid remains the storefront runtime.
+2. Shopify CLI remains the canonical preview/deploy tool.
+3. `dist/theme` remains a normal, inspectable Shopify theme.
+4. Every deployable Shopify path has exactly one source owner.
+5. Ownership is planned and validated before publish.
+6. Failed builds never replace the last-known-good output.
+7. Existing themes can adopt Liquid Loom without moving source.
+8. Migration remains preview-first and preserves Shopify output identity.
+9. Existing Sass/PostCSS/Webpack/Vite/Tailwind pipelines remain valid for adopted themes.
+10. The project model reports provable relationships rather than evaluating or guessing Liquid.
+11. Developer-preview Shopify syntax never becomes a stable requirement implicitly.
+
+## Target architecture
+
+```text
+authored Shopify/Liquid source
+ |
+ +-- native component assets
+ +-- theme blocks / app blocks
+ +-- optional Vite or Tailwind assets
+ +-- explicit stable/preview Liquid mode
+ |
+ v
+Liquid Loom
+ |
+ +-- ownership plan
+ +-- project intelligence
+ +-- diagnostics
+ +-- transactional build
+ +-- migration safety
+ |
+ v
+canonical Shopify theme
+ |
+ +-- Shopify CLI preview/push
+ +-- compiled GitHub deployment branch/repo
+```
+
+## 1. Shopify-native component assets become the fresh-project default
+
+Shopify supports `{% stylesheet %}` and `{% javascript %}` in sections, blocks, and snippets. Shopify now subsets stylesheet-tag CSS by the current page render tree, making component-local CSS a real platform feature rather than just a source-organization convention.
+
+### Target
+
+Fresh projects should prefer component-local assets for component-local behavior:
+
+```liquid
+{% stylesheet %}
+ .product-card { ... }
+{% endstylesheet %}
+
+{% javascript %}
+ customElements.define(...)
+{% endjavascript %}
+```
+
+Global CSS should remain only for genuinely global concerns such as base styles, typography, design tokens, shared layout primitives, accessibility defaults, and intentionally global utilities.
+
+### Vite and Tailwind
+
+Vite and Tailwind remain first-class supported integrations, but they become explicit asset strategies instead of the architectural default.
+
+A future scaffolder can expose a small choice such as:
+
+```text
+native Shopify-native component assets + minimal global assets
+vite Vite for projects that need bundling/modules
+ tailwind Tailwind + Vite for teams that intentionally choose it
+```
+
+Do not introduce a generic asset plugin API merely to support these three paths.
+
+### Acceptance criteria
+
+- a default fresh scaffold builds without requiring a storefront Vite bundle;
+- component CSS/JS is colocated with its Liquid component where practical;
+- global assets are intentionally small and documented;
+- Vite and Tailwind remain tested supported paths;
+- existing-theme `init` continues to preserve the current asset pipeline.
+
+Reference:
+
+## 2. Theme blocks become the primary reference composition model
+
+Liquid Loom already understands root `blocks/*.liquid`, block references, app blocks, and preview block relationships. The reference storefront should now demonstrate that model deeply rather than treating blocks as a small flexible-content example.
+
+### Product page target
+
+Move the product page toward merchant-reorderable components:
+
+```text
+Main product
+|
++-- Product media
++-- Product information group
+| +-- Vendor
+| +-- Title
+| +-- Price
+| +-- @app
++-- Variant picker
++-- Purchase group
+| +-- Quantity
+| +-- Buy buttons
+| +-- @app
++-- Description
+```
+
+The decomposition should stay intentionally small and Shopify-native. Liquid Loom should not invent its own component runtime or schema abstraction.
+
+### Acceptance criteria
+
+- merchants can reorder the supported product information blocks in Theme Editor;
+- expected surfaces accept `@app` blocks;
+- reusable content primitives are theme blocks where reuse creates merchant value;
+- source continues to map through the existing organized-source ownership contract;
+- no-JavaScript fallbacks and accessible markup remain part of the reference theme.
+
+## 3. Standard storefront events and actions
+
+Shopify now provides a standard communication layer between Liquid storefronts, apps, and agents. The reference storefront should speak that protocol rather than forcing integrations to inspect custom DOM or intercept requests.
+
+### Stable scope
+
+Implement the relevant documented events for interactions owned by the reference storefront, including appropriate page, product, collection, search, and cart events.
+
+Use Shopify standard actions as the integration contract. Override an action only when the reference theme can provide a better local UI than Shopify's safe default behavior.
+
+These events are not an analytics system. Analytics stays on Shopify Web Pixels.
+
+### Acceptance criteria
+
+- events follow Shopify's documented payload contracts;
+- action overrides retain Shopify-compatible fallback behavior;
+- integrations do not depend on undocumented DOM conventions or global `fetch` interception;
+- event/action behavior is included in real-store/browser smoke coverage.
+
+References:
+
+-
+-
+-
+
+## 4. Adopt `color_palette` for the reference design-token model
+
+Shopify recommends `color_palette` for new themes and is focusing future color-system development there.
+
+### Target
+
+The reference theme should define one semantic palette in `settings_schema.json`, for example:
+
+```json
+{
+ "type": "color_palette",
+ "id": "colors",
+ "default": {
+ "background": "#F8F7F2",
+ "foreground": "#111820",
+ "surface": "#FFFFFF",
+ "accent": "#176C5B",
+ "accent_contrast": "#FFFFFF"
+ }
+}
+```
+
+Section/block color controls can reference palette entries as defaults while remaining locally overrideable.
+
+CSS custom properties remain the runtime design-token bridge. This keeps the rendered theme inspectable and works equally well with native CSS, Vite, or Tailwind.
+
+Reference:
+
+## 5. Modern customer accounts
+
+The reference header should use Shopify's `` storefront component whenever customer accounts are enabled.
+
+### Target
+
+- render the component in a location available on desktop and mobile;
+- expose the menu through a merchant setting with `customer-account-main-menu` as the default;
+- customize only through supported CSS variables, parts, and slots;
+- render nothing account-specific when customer accounts are disabled.
+
+Reference:
+
+## 6. First-class compiled GitHub deployment workflow
+
+Liquid Loom repositories can contain authored `src`, tests, package metadata, configuration, and build tooling. Shopify's GitHub theme integration only connects correctly to a branch that already has canonical Shopify theme structure.
+
+That constraint should become a supported Liquid Loom workflow instead of tribal knowledge.
+
+### Target model
+
+```text
+main / feature branches
+|
++-- authored source
++-- Liquid Loom config
++-- tests and tooling
+|
++-- CI: validate + build
+ |
+ v
+shopify-production branch (or deployment repo)
+|
++-- assets/
++-- blocks/
++-- config/
++-- layout/
++-- locales/
++-- sections/
++-- snippets/
++-- templates/
+ |
+ v
+Shopify GitHub integration
+```
+
+### Deliverables
+
+- documented deployment-branch and deployment-repository strategies;
+- an opt-in generated GitHub Actions workflow or maintained recipe;
+- validation before publishing compiled output;
+- loop protection for Shopify-originated commits on a connected branch;
+- explicit guidance for teams that allow Theme Editor/code-editor changes to write back into GitHub;
+- no hosted Liquid Loom deployment service.
+
+Reference:
+
+## 7. Shopify CLI 4.8+ development-store workflow
+
+Shopify CLI 4.8 added `shopify store` commands for creating, listing, inspecting, and deleting dev stores. Liquid Loom should align its real-store validation guidance with that workflow.
+
+### Target
+
+Document and optionally script an opt-in flow such as:
+
+```text
+shopify store create dev --demo-data
+ |
+ v
+liquid-loom build
+ |
+ v
+shopify theme dev --path dist/theme
+ |
+ v
+browser smoke
+ |
+ v
+shopify store delete
+```
+
+Public CI must continue to work without Shopify credentials. Real-store automation belongs in protected/opt-in workflows.
+
+Reference:
+
+## 8. Agent-friendly contracts build on `0.3`, not around Shopify
+
+PR #25 added the deterministic project model, `explain`, JSON output, preview-aware relationships, and explicit `shopifyLiquidMode`. The modernization should extend that strategy rather than create a separate agent framework.
+
+### Target
+
+- keep `doctor`, `check`, and `explain` deterministic and script-friendly;
+- ensure new block/component/deployment concepts appear truthfully in the project model where statically provable;
+- add architectural diff/report features only if real agent or CI workflows demonstrate the need;
+- prefer standard Shopify primitives so agents can use Shopify's own documentation and AI tooling;
+- keep generated deployment output visibly disposable and authored source visibly authoritative.
+
+A Liquid Loom-specific AI runtime or agent SDK is out of scope.
+
+## 9. July 2026 Liquid preview remains explicit and experimental
+
+Liquid Loom already supports explicit `stable` and `july-2026-preview` project modes and can report preview block/partial usage.
+
+That is the correct policy for the modernization release.
+
+### Policy
+
+- do not scaffold `{% block %}` or `{% partial %}` by default;
+- do not make preview syntax a stable build requirement;
+- continue allowing a project to declare preview intent through `shopifyLiquidMode`;
+- keep preview relationships visible to `explain` and diagnostics;
+- validate preview recipes separately from stable release gates;
+- reconsider the default only after Shopify publishes a stable contract.
+
+Reference:
+
+## 10. Existing-theme adoption must remain boring and safe
+
+None of the platform modernization should force an established theme to refactor.
+
+For existing themes:
+
+- `liquid-loom init` still moves zero Shopify source files;
+- current Vite/Tailwind/Sass/PostCSS/Webpack pipelines remain valid;
+- native component asset tags can be adopted file-by-file;
+- palettes remain optional;
+- block refactors are never automatic;
+- standard event/action integration is opt-in per interaction the project owns;
+- migration continues to preserve output identity;
+- stable mode remains the default unless preview intent is explicit.
+
+This compatibility rule is non-negotiable.
+
+## Implementation order for one modernization PR
+
+The implementation should land as one coherent PR, but be built internally in dependency order so every commit remains understandable:
+
+1. update platform-alignment docs, roadmap, and acceptance criteria;
+2. update the supported Shopify CLI development-tool floor;
+3. modernize palette/design-token and customer-account primitives;
+4. refactor the reference storefront toward theme-block-first composition;
+5. move appropriate component CSS/JS to Shopify-native tags;
+6. preserve Vite/Tailwind as explicit tested asset paths;
+7. implement standard storefront events/actions;
+8. add compiled GitHub deployment workflow/recipe;
+9. update project intelligence where new static relationships need representation;
+10. expand tests, package smoke, and opt-in real-store/browser validation;
+11. keep July-preview validation separate from the stable release gate.
+
+## Compatibility rules for that PR
+
+The implementation must not:
+
+- change the deployable Shopify path for existing organized source;
+- invalidate `0.2`/`0.3` projects merely because they use Vite or Tailwind;
+- require migration in adopted themes;
+- require Shopify credentials for normal unit/package CI;
+- depend on preview-only Liquid syntax for stable fixtures;
+- change source ownership precedence silently;
+- introduce a second storefront runtime;
+- hide the generated canonical Shopify theme;
+- regress the deterministic project model or `explain --json` contract without an explicit versioning decision.
+
+Any unavoidable breaking public API change requires an explicit migration note before merge.
+
+## Validation matrix
+
+### Public/local automated validation
+
+- default fresh scaffold builds and passes Theme Check;
+- optional Vite path builds and participates in generated-output collision checks;
+- optional Tailwind path builds and participates in generated-output collision checks;
+- reference and embedded starter remain synchronized;
+- existing-theme `init -> hybrid build -> migrate -> build` remains green;
+- packed-package smoke exercises the actual published artifact shape;
+- native `{% stylesheet %}` / `{% javascript %}` content survives organized-source mapping unchanged;
+- `explain --json` remains deterministic across repeated runs;
+- stable fixtures require no Shopify developer preview.
+
+### Real Shopify validation
+
+- fresh scaffold previews against a dev store;
+- product, cart, collection, and search flows work in the browser;
+- required no-JavaScript fallbacks remain usable;
+- product blocks can be reordered in Theme Editor;
+- app blocks work in the intended surfaces;
+- `` works when accounts are enabled and disappears cleanly when disabled;
+- palette edits propagate through semantic CSS tokens;
+- standard storefront event payloads match Shopify contracts;
+- the compiled deployment branch/repo is accepted by Shopify GitHub integration;
+- Shopify-originated writes do not cause deployment loops.
+
+### Adoption validation
+
+Run the modernization against at least one established client-style theme while leaving its current asset pipeline untouched. The upgrade must provide value without requiring block, palette, native-asset, or preview migrations.
+
+## Success criteria
+
+The modernization is successful if a developer can accurately describe the project as:
+
+> Shopify-native Liquid theme development with deterministic source ownership, safe adoption, agent-readable architecture, and modern platform defaults.
+
+The next release should feel **more native to Shopify**, not more dependent on Liquid Loom-specific abstractions.
+
+## Deferred work
+
+Keep these deferred unless real usage earns them:
+
+- broad plugin/hook systems;
+- arbitrary source/mapping plugins;
+- hosted deployment infrastructure;
+- headless/Hydrogen support;
+- React/Vue/Svelte storefront runtimes;
+- a custom analytics layer;
+- a Liquid Loom-specific AI agent runtime;
+- stable defaults based on developer-preview Liquid syntax.
diff --git a/docs/examples/shopify-deploy.yml b/docs/examples/shopify-deploy.yml
new file mode 100644
index 0000000..7ddf210
--- /dev/null
+++ b/docs/examples/shopify-deploy.yml
@@ -0,0 +1,61 @@
+name: Build Shopify deployment branch
+
+on:
+ workflow_dispatch:
+ push:
+ branches: [main]
+
+permissions:
+ contents: write
+
+concurrency:
+ group: shopify-theme-deployment
+ cancel-in-progress: false
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 24
+ cache: pnpm
+
+ - run: corepack enable
+ - run: pnpm install --frozen-lockfile
+ - run: pnpm validate
+
+ - name: Prepare compiled branch
+ shell: bash
+ run: |
+ set -euo pipefail
+ deploy_dir="$RUNNER_TEMP/shopify-production"
+ if git ls-remote --exit-code --heads origin shopify-production >/dev/null 2>&1; then
+ git fetch origin shopify-production:refs/remotes/origin/shopify-production
+ git worktree add --detach "$deploy_dir" origin/shopify-production
+ else
+ git worktree add --detach "$deploy_dir" HEAD
+ find "$deploy_dir" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
+ fi
+
+ for directory in assets blocks config layout locales sections snippets templates; do
+ rm -rf "$deploy_dir/$directory"
+ if [ -d "dist/theme/$directory" ]; then
+ cp -R "dist/theme/$directory" "$deploy_dir/$directory"
+ fi
+ done
+
+ git -C "$deploy_dir" checkout -B shopify-production
+ git -C "$deploy_dir" config user.name "github-actions[bot]"
+ git -C "$deploy_dir" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git -C "$deploy_dir" add -A
+ if git -C "$deploy_dir" diff --cached --quiet; then
+ echo "No deployable theme changes."
+ exit 0
+ fi
+ git -C "$deploy_dir" commit -m "Deploy Shopify theme from ${GITHUB_SHA}"
+ git -C "$deploy_dir" push origin HEAD:shopify-production
diff --git a/liquid-loom.config.ts b/liquid-loom.config.ts
index a5790ef..16c3c11 100644
--- a/liquid-loom.config.ts
+++ b/liquid-loom.config.ts
@@ -1,6 +1,7 @@
import { defineConfig } from "liquid-loom";
export default defineConfig({
+ viteConfig: false,
performance: {
maxAssetBytes: 500_000,
maxBuildMs: 10_000,
diff --git a/package.json b/package.json
index 494bf81..678b360 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "liquid-loom",
"version": "0.2.0",
- "description": "A deterministic engineering layer for Shopify themes: source architecture, safe incremental adoption, Vite, and Tailwind CSS.",
+ "description": "A deterministic engineering layer for Shopify Liquid themes: safe adoption, explicit ownership, project intelligence, and modern platform defaults.",
"type": "module",
"license": "MIT",
"bin": {
diff --git a/packages/create-liquid-loom/template/README.md b/packages/create-liquid-loom/template/README.md
index 79041d9..8bf3b65 100644
--- a/packages/create-liquid-loom/template/README.md
+++ b/packages/create-liquid-loom/template/README.md
@@ -2,6 +2,8 @@
A Shopify storefront built with [Liquid Loom](https://github.com/yotamon/Liquid-Loom).
+The starter uses Shopify-native component CSS/JavaScript by default and keeps Vite/Tailwind optional.
+
## Start
```bash
@@ -9,4 +11,4 @@ pnpm install
pnpm dev
```
-Use `pnpm build` for a deployable theme in `dist/theme`, `pnpm doctor` for environment diagnostics, and `pnpm validate` before shipping.
+Use `pnpm build` for a deployable theme in `dist/theme`, `pnpm explain -- --json` for the deterministic project model, `pnpm doctor` for environment diagnostics, and `pnpm validate` before shipping.
diff --git a/packages/create-liquid-loom/template/liquid-loom.config.ts b/packages/create-liquid-loom/template/liquid-loom.config.ts
index a5790ef..16c3c11 100644
--- a/packages/create-liquid-loom/template/liquid-loom.config.ts
+++ b/packages/create-liquid-loom/template/liquid-loom.config.ts
@@ -1,6 +1,7 @@
import { defineConfig } from "liquid-loom";
export default defineConfig({
+ viteConfig: false,
performance: {
maxAssetBytes: 500_000,
maxBuildMs: 10_000,
diff --git a/packages/create-liquid-loom/template/package.json b/packages/create-liquid-loom/template/package.json
index 4dfc899..fb7abc0 100644
--- a/packages/create-liquid-loom/template/package.json
+++ b/packages/create-liquid-loom/template/package.json
@@ -15,6 +15,7 @@
"clean": "liquid-loom clean",
"dev": "liquid-loom dev",
"doctor": "liquid-loom doctor",
+ "explain": "liquid-loom explain",
"format": "prettier --write .",
"format:check": "prettier --check .",
"shopify:push": "shopify theme push --path dist/theme",
@@ -24,12 +25,10 @@
"watch": "liquid-loom watch"
},
"devDependencies": {
- "@shopify/cli": "^4.6.0",
+ "@shopify/cli": "^4.8.0",
"@shopify/prettier-plugin-liquid": "^1.11.0",
- "@tailwindcss/vite": "^4.3.3",
"liquid-loom": "^0.2.0",
"prettier": "^3.9.6",
- "tailwindcss": "^4.3.3",
"typescript": "^7.0.2"
}
}
diff --git a/packages/create-liquid-loom/template/src/entrypoints/theme.js b/packages/create-liquid-loom/template/src/entrypoints/theme.js
deleted file mode 100644
index fd16943..0000000
--- a/packages/create-liquid-loom/template/src/entrypoints/theme.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import "../styles/theme.css";
-
-class MenuDisclosure extends HTMLElement {
- connectedCallback() {
- this.button = this.querySelector("button");
- this.panel = this.querySelector("[data-menu-panel]");
- if (!this.button || !this.panel) return;
-
- this.button.addEventListener("click", () => this.toggle());
- this.addEventListener("keydown", (event) => {
- if (event.key === "Escape" && this.isOpen()) {
- this.close();
- this.button.focus();
- }
- });
- }
-
- isOpen() {
- return this.button.getAttribute("aria-expanded") === "true";
- }
-
- toggle() {
- this.isOpen() ? this.close() : this.open();
- }
-
- open() {
- this.button.setAttribute("aria-expanded", "true");
- this.panel.removeAttribute("hidden");
- document.documentElement.classList.add("menu-open");
- }
-
- close() {
- this.button.setAttribute("aria-expanded", "false");
- this.panel.setAttribute("hidden", "");
- document.documentElement.classList.remove("menu-open");
- }
-}
-
-class QuantityInput extends HTMLElement {
- connectedCallback() {
- this.input = this.querySelector("input[type='number']");
- this.querySelectorAll("button").forEach((button) => {
- button.addEventListener("click", () => this.change(button.dataset.quantityAction));
- });
- }
-
- change(action) {
- if (!this.input) return;
- const step = Number(this.input.step) || 1;
- const minimum = Number(this.input.min) || 1;
- const current = Number(this.input.value) || minimum;
- this.input.value = String(Math.max(minimum, current + (action === "increase" ? step : -step)));
- this.input.dispatchEvent(new Event("change", { bubbles: true }));
- }
-}
-
-class PredictiveSearch extends HTMLElement {
- connectedCallback() {
- this.input = this.querySelector("input[type='search']");
- this.results = this.querySelector("[data-predictive-search-results]");
- if (!this.input || !this.results) return;
- this.input.addEventListener("input", () => {
- clearTimeout(this.timer);
- this.timer = setTimeout(() => this.search(), 180);
- });
- }
-
- async search() {
- const query = this.input.value.trim();
- this.controller?.abort();
- if (query.length < 2) {
- this.results.replaceChildren();
- this.input.setAttribute("aria-expanded", "false");
- return;
- }
-
- this.controller = new AbortController();
- try {
- const url = `/search/suggest?q=${encodeURIComponent(query)}&resources[type]=product§ion_id=predictive-search`;
- const response = await fetch(url, { signal: this.controller.signal });
- if (!response.ok) throw new Error(`Search request failed: ${response.status}`);
- const document = new DOMParser().parseFromString(await response.text(), "text/html");
- const content = document.querySelector(".predictive-search__results");
- this.results.replaceChildren(...(content ? [content] : []));
- this.input.setAttribute("aria-expanded", content ? "true" : "false");
- } catch (error) {
- if (error.name !== "AbortError") console.error(error);
- }
- }
-}
-
-class ProductForm extends HTMLElement {
- connectedCallback() {
- this.select = this.querySelector("[data-variant-select]");
- this.submit = this.querySelector("button[type='submit']");
- const data = this.querySelector("[data-product-variants]");
- if (!this.select || !data) return;
- this.variants = JSON.parse(data.textContent);
- this.select.addEventListener("change", () => this.variantChanged());
- }
-
- variantChanged() {
- const variant = this.variants.find(({ id }) => String(id) === this.select.value);
- if (!variant) return;
- this.submit?.toggleAttribute("disabled", !variant.available);
- const url = new URL(window.location.href);
- url.searchParams.set("variant", variant.id);
- window.history.replaceState({}, "", url);
- }
-}
-
-if (!customElements.get("menu-disclosure")) customElements.define("menu-disclosure", MenuDisclosure);
-if (!customElements.get("quantity-input")) customElements.define("quantity-input", QuantityInput);
-if (!customElements.get("predictive-search")) customElements.define("predictive-search", PredictiveSearch);
-if (!customElements.get("product-form")) customElements.define("product-form", ProductForm);
-
-document.documentElement.classList.remove("no-js");
-document.documentElement.classList.add("js");
diff --git a/src/styles/theme.css b/packages/create-liquid-loom/template/src/public/theme.css
similarity index 72%
rename from src/styles/theme.css
rename to packages/create-liquid-loom/template/src/public/theme.css
index 3ee152c..69995dd 100644
--- a/src/styles/theme.css
+++ b/packages/create-liquid-loom/template/src/public/theme.css
@@ -1,6 +1,3 @@
-@import "tailwindcss";
-@source "../theme/**/*.liquid";
-
:root {
--color-background: #f8f7f2;
--color-foreground: #111820;
@@ -185,80 +182,6 @@ textarea {
text-align: center;
}
-.site-header {
- position: sticky;
- top: 0;
- z-index: 40;
- border-bottom: 1px solid color-mix(in srgb, var(--color-border) 75%, transparent);
- background: color-mix(in srgb, var(--color-background) 88%, transparent);
- backdrop-filter: blur(18px);
-}
-
-.site-header__inner {
- display: grid;
- min-height: 4.8rem;
- grid-template-columns: 1fr auto 1fr;
- align-items: center;
- gap: 1rem;
-}
-
-.site-header__brand {
- justify-self: center;
- font-size: 1.1rem;
- font-weight: 800;
- letter-spacing: -0.03em;
- text-decoration: none;
-}
-
-.site-header__logo {
- width: auto;
- max-height: 2.3rem;
-}
-
-.site-header__nav,
-.site-header__actions {
- display: flex;
- align-items: center;
- gap: 1.25rem;
-}
-
-.site-header__nav a,
-.site-header__actions a {
- font-size: 0.9rem;
- font-weight: 650;
- text-decoration: none;
-}
-
-.site-header__actions {
- justify-self: end;
-}
-
-.site-header__menu-button {
- display: none;
- border: 0;
- background: transparent;
- cursor: pointer;
- padding: 0.5rem;
-}
-
-.mobile-menu {
- border-top: 1px solid var(--color-border);
- background: var(--color-background);
- padding: 1rem;
-}
-
-.mobile-menu[hidden] {
- display: none;
-}
-
-.mobile-menu a {
- display: block;
- padding: 0.8rem;
- font-size: 1.15rem;
- font-weight: 700;
- text-decoration: none;
-}
-
.hero {
position: relative;
overflow: hidden;
@@ -394,80 +317,32 @@ textarea {
text-decoration: line-through;
}
-.product {
- display: grid;
- grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr);
- gap: clamp(2rem, 7vw, 7rem);
-}
-
-.product__gallery {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 1rem;
-}
-
-.product__gallery img {
- width: 100%;
- border-radius: var(--radius-md);
-}
-
-.product__details {
- align-self: start;
-}
-
-.product__details .price {
- display: block;
- margin-block: 1rem;
- font-size: 1.2rem;
-}
-
-.field {
- display: grid;
- gap: 0.45rem;
- margin-block: 1rem;
+.collection-header {
+ max-width: 48rem;
+ margin-bottom: 3rem;
}
-.field label {
- font-size: 0.85rem;
- font-weight: 700;
+.facets {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: start;
+ gap: 0.75rem;
+ margin-bottom: 2rem;
}
-.field input,
-.field select,
-.field textarea {
- width: 100%;
- min-height: 3rem;
+.facet {
+ position: relative;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-surface);
- padding: 0.7rem 0.85rem;
+ padding: 0.65rem 0.8rem;
}
-.quantity {
+.facet__options {
display: grid;
- width: 9rem;
- grid-template-columns: 2.6rem 1fr 2.6rem;
- border: 1px solid var(--color-border);
- border-radius: 999px;
- background: var(--color-surface);
-}
-
-.quantity button,
-.quantity input {
- min-height: 2.8rem;
- border: 0;
- background: transparent;
- text-align: center;
-}
-
-.quantity input {
- width: 100%;
- appearance: textfield;
-}
-
-.collection-header {
- max-width: 48rem;
- margin-bottom: 3rem;
+ min-width: 14rem;
+ gap: 0.55rem;
+ padding-top: 0.75rem;
}
.cart-table {
@@ -525,53 +400,6 @@ textarea {
border-radius: var(--radius-lg);
}
-.facets {
- display: flex;
- flex-wrap: wrap;
- align-items: start;
- gap: 0.75rem;
- margin-bottom: 2rem;
-}
-
-.facet {
- position: relative;
- border: 1px solid var(--color-border);
- border-radius: var(--radius-sm);
- background: var(--color-surface);
- padding: 0.65rem 0.8rem;
-}
-
-.facet__options {
- display: grid;
- min-width: 14rem;
- gap: 0.55rem;
- padding-top: 0.75rem;
-}
-
-.predictive-search__results {
- border: 1px solid var(--color-border);
- border-radius: var(--radius-md);
- margin-top: 0.5rem;
- background: var(--color-surface);
- box-shadow: var(--shadow-soft);
- padding: 1rem;
-}
-
-.predictive-search__results ul {
- display: grid;
- gap: 0.65rem;
- margin: 0;
- padding: 0;
- list-style: none;
-}
-
-.predictive-search__results a {
- display: flex;
- justify-content: space-between;
- gap: 1rem;
- text-decoration: none;
-}
-
.empty-state {
max-width: 38rem;
margin-inline: auto;
@@ -626,24 +454,8 @@ textarea {
}
@media (max-width: 900px) {
- .site-header__inner {
- grid-template-columns: 1fr auto 1fr;
- }
-
- .site-header__nav {
- display: none;
- }
-
- .site-header__menu-button {
- display: inline-flex;
- }
-
- .hero__grid,
- .product {
- grid-template-columns: 1fr;
- }
-
.hero__grid {
+ grid-template-columns: 1fr;
padding-block: 4rem;
}
@@ -669,12 +481,7 @@ textarea {
width: min(calc(100% - 1.25rem), var(--page-width));
}
- .site-header__actions a:not([href*="cart"]) {
- display: none;
- }
-
.product-grid,
- .product__gallery,
.site-footer__grid {
grid-template-columns: 1fr;
}
diff --git a/packages/create-liquid-loom/template/src/theme/blocks/product-description.liquid b/packages/create-liquid-loom/template/src/theme/blocks/product-description.liquid
new file mode 100644
index 0000000..fd4725d
--- /dev/null
+++ b/packages/create-liquid-loom/template/src/theme/blocks/product-description.liquid
@@ -0,0 +1,4 @@
+{%- if product.description != blank -%}
+