Terroir · promotion note

How NAGORI was promoted.

The accepted single-origin matcha storefront, restructured so its commerce is real: product tins driven by a content collection, the provenance essay in markdown, the survey map compiled at build time. One island survives, the foam hero. Everything else ships zero JavaScript.

Back to the shop

01 · The brief

Promote the accepted piece; make its content editable.

The commerce vertical of the portfolio, promoted from static to Astro. The delta is the deliverable: preserve a director-accepted design to the pixel while turning its hardcoded storefront into real, client-editable content, the exact thing a small commerce engagement buys.

Register
The Quiet Page + The Stroke (unchanged)
Field
Bone #f2efe6
Stroke
Acid matcha #a8c421 (carries every action)
Type
Fraunces display, full optical range · Archivo
Island budget
One, the reaction-diffusion foam hero
Delta
Products, essays, and ritual become typed content collections; survey map compiles to SVG; everything but the foam ships zero JS
Growth path
This is the Astro stage; Next.js only if a cart is ever real

02 · The promotion delta

Hardcoded markup became a content graph.

Every repeating thing on the page is now a typed collection with a schema, so a client edits a markdown file, not a component, and the design holds. The foundry stills, when they land, drop into each product's img slot through the documented --product-img convention with no template change.

src/content/
  products/   4 entries   name, index, grade, cultivar, harvest,
              (markdown)  grind, weight, price, tasting[], shade,
                          featured, kit, img (--product-img slot), alt
  essays/     2 entries   eyebrow, heading, kind, facts[], survey[],
              (markdown)  fieldNote, + the argument itself as the body
  steps.json  4 entries   n, title, body   (the ritual, one repeating type)

products  ->  Shop / ProductCard      essays  ->  Season, Provenance
steps     ->  Ritual                  (foundry still drops into img, no edit)
Three collections feed the page. The tins the director accepted are now rows a shopkeeper can edit.

Two things that used to run in the browser no longer do. The reveal choreography and the header's transparent-to-solid state are pure CSS scroll-driven animations; the provenance survey is drawn once at build time and shipped as inert SVG. The result: the page runs exactly one script, the foam.

// The survey map used to be a canvas the browser ran on every visit. Now the
// same marching-squares scan runs ONCE, at build time, in Node. The page
// ships inert SVG. Deterministic (layered sines, no RNG), byte-identical each
// build, matched to the accepted composition.
export function buildContour() {
  for (let L = 0; L < levels; L++) {
    const iso = min + step * (L + 0.5);
    // ... classic marching-squares edge interpolation, per cell ...
    (emphasise ? inked : faint).push(seg.join(''));
  }
  return { faint, inked, ticks, well };  // -> inline <path> data
From src/lib/contour.js, run at build time. Compile, do not script.

03 · The signature technique

The hero is a whisked bowl of matcha, simulated, and preserved.

The macro-liquid field behind the headline is a Gray-Scott reaction-diffusion system on a small grid, upscaled with smoothing so the cells read as soft foam, coloured through a lookup table from dark tea to acid matcha to a pale foam lift. Moving the pointer seeds fresh foam and leaves a soft acid glow, the way a whisk lifts froth. The promotion carries it across untouched, including the settled-at-rest governor from the fix batch.

// The one island: Gray-Scott reaction-diffusion, ported verbatim from the
// accepted track-1 build. Two chemicals diffuse and react on a torus grid;
// the "coral" regime grows froth that fills the field. Coloured through a LUT
// that runs dark tea .. acid matcha .. foam lift.
var reaction = av * bv * bv;
a2[i] = clamp01( av + (dA*lapA - reaction + feed*(1 - av)) );
b2[i] = clamp01( bv + (dB*lapB + reaction - (kill + feed)*bv) );

// Settled-at-rest governor (preserved from the fix batch): 1 step/frame idle,
// up to 8 on scroll or whisk, easing back, full rate only when it earns it.
var steps = IDLE_STEPS + Math.round((MAX_STEPS - IDLE_STEPS) * activity);
for (var k = 0; k < steps; k++) step();
activity *= 0.95;
From src/scripts/foam.js. The same routine runs ~1500 steps once for the reduced-motion still, so the static page keeps its foam instead of going blank.

04 · The critique passes

Three passes, each one hostile.

Every pass rendered the page at desktop and mobile, diffed it against the live track-1 finals, read the screenshots like an unimpressed art director, fixed what it found, then added one deliberate deepening.

Pass one

Found
Built the promotion, then diffed it against the live track-1 page by rendered word-rag and by eye: the hero, sections and rhythm matched to the pixel, and the only text that changed was intentional. One real defect surfaced in the grid, though: the starter set spec read "Tin 30 g tin", the weight doubling its own unit because the schema carried "30 g tin" where the set wanted a bare "30 g".
Changed
Corrected the set weight to "30 g" so the spec reads "Tin 30 g", faithful to the accepted card.
Upgrade
Tasting-note chips, drawn straight from the new products schema: the promotion earning its collection by showing flavour data track 1 never carried.

Pass two

Found
Rendered the season, provenance and this guide page. The site itself came back clean, but the guide had let em-dashes creep into its own prose, which the house copy doctrine bans outright. A second rag diff confirmed every remaining delta from track 1 was deliberate: cultivar names, tasting notes, and honest ordering copy in, a fake cart and a fake newsletter out.
Changed
Swept every em-dash from the guide copy back to the plain register, commas and colons doing the work instead.
Upgrade
A deterministic, build-time powder texture seeded per tin, so no two tins show the same grind: every tin is one cut from one terrace, and now it looks it.

Pass three

Found
Probed both motion paths and the mobile composition. The headless reduced-motion default is machine-dependent, so neither path could be assumed: the reduced branch had to be verified as a dignified still, and the animated branch as genuinely alive. The mobile footer composed cleanly, no dead zone under the note.
Changed
Verified each path with real input: the reduced branch paints one grown foam frame and holds a solid legible masthead; the no-preference branch grows froth under a whisk sweep and settles back to calm at rest (measured canvas luminance range 165, not a flat wash).
Upgrade
The order affordance became a real, useful mailto: the letter arrives pre-filled with the tin, its cultivar, weight and price, so an order is a genuine transaction rather than a button that pretends.