Skip to content

v1.2: new themes, variants v2 with the corner dock, and the three-harness pivot - #54

Draft
Luffixos wants to merge 58 commits into
mainfrom
v1.2
Draft

v1.2: new themes, variants v2 with the corner dock, and the three-harness pivot#54
Luffixos wants to merge 58 commits into
mainfrom
v1.2

Conversation

@Luffixos

@Luffixos Luffixos commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Hallmark v1.2, one release

Everything on this branch ships together as v1.2: the catalog grows to 24 themes, variants becomes a fast progressive loop with a corner dock, the skill goes deep on the three terminals that matter, and a round of anti-sameness improvements lands across the rulebook.

Themes and rules

  • Four new themes (Grid, Field, Ledger, Arcade), catalog 20 to 24, wired through tokens, all main.js maps, axes, genre clusters, and canonical examples; Arcade carries a tightly scoped gate-47 carve-out.
  • Spec files for all 24 themes, grounded in real token values, new ones capped at 150 lines.
  • Catalog de-duplication: Coral moves to General Sans and Aurora to Sora with a teal-green signal (no more axis twins), Almanac and Riso occupy the previously empty mid paper band, and the structural fingerprint table covers all 24 themes.
  • Hero postures: six named fold geometries (Settled, Banner, Poster, Ledge, Corridor, Stage) replace the single silhouette; posture rotates and is stamped and logged.
  • Section deck: the fixed SaaS section sequence becomes a deck that must deviate twice per deal (drop one, promote a wildcard or reorder meaningfully).
  • Sharper enforcement: one accent budget (5%) with a mechanical estimator (static + render), pre-emit critique with anchored scores and a required named weakness, the mirror test against category defaults, budgeted verification rounds, rotation memory deepened to last-3 with six-axis fingerprints in the log.

Variants v2 + the corner dock

Progressive reveal, parallel sketch-depth drafts, thumbnails, compositional grafts, section-zoom, a decisions log, scoped Vite/Astro/SvelteKit preview injection. Every control surface is now one bottom-right corner dock over the full-bleed page (picker single view, on-page chip, injection overlay, static compare), shadow-DOM isolated, state-fed so riffed directions stay reachable.

Tooling

  • Edit-time lint hook: sloplint on every artifact write via PostToolUse, advisory only.
  • Image hook: opt-in Together-backed generation with cache-by-hash and graceful no-key fallback; the imagery kit is honest about being a composition playbook until real assets ship.
  • Tier A harness: eval/gen-cli.mjs drives the real Claude Code binary for conformance runs.
  • Three harnesses, one core: per-harness adapters for Claude Code, Codex CLI, and OpenCode, plus an installer that syncs a lean payload into every detected harness and refreshes stale copies.

Verification

Mechanical checks green across the board: all examples sloplint-clean, hook fixtures pass, installer idempotent, corner dock verified end-to-end in the browser, consistency scripts assert the axes/fingerprint/routing invariants. Open items needing a logged-in terminal: Tier A conformance runs, the variants speed bench, one live image generation.

Round 2: the capability layers

  • Finish layer (finish.md, every build): heading measure by size, typeset punctuation, text-wrap balance/pretty, one filled primary, button height budget, icon discipline, concentric radii, mobile-runs-larger, motion finish. Backed by a new F-tier in sloplint (F1-F9): nine mechanical polish checks that report beside the gates without ever counting in the 58 (fake-avatar hotlinks are the tier's one FAIL).
  • Surface escalation ladder: whitespace to hairline to tinted well to card, with cards reserved for independently interactive content; gate 9 names it as the fix vocabulary and F7 flags container monotony.
  • Scroll choreography (scroll-choreography.md): four earned patterns (pinned chapter, scrub-linked headline, progress spine, sticky diptych) with Baseline-2025 progressive-enhancement recipes, one per page, replacing a blanket ban that contradicted the craft tier.
  • Texture system (texture.md): grain, halftone, misregistration, scanline, and deckle as budgeted, tokened recipes earned by theme lineage.
  • Dark-mode protocol (dark-mode.md): parity by per-token re-derivation, dual-block emission on request, dark shadow discipline.
  • Data-viz reference (data-viz.md): form heuristic, hand-built SVG mark specs, one-accent series colour, one y-axis never dual, honesty tied to gate 46.
  • Brand truth (brand-truth.md): real brands get fetched values recorded to a provenance spec, never memory hex.
  • The imagery kit is real: 39 committed assets under site/imagery/ (16 QC'd photoreal placeholder avatars with paired unisex names, washes, brush gestures, marks, textures, three token-true app-screen frames with sources), a filled manifest as the URL allowlist, and the fake-avatar services banned by check.
  • Harness adapters gained their per-model tic sections (a round-1 item that had slipped the execution order).

Verification: the full example sweep holds at the round-1 baseline, an F-tier fixture trips all nine checks with exact grades and lines, every new reference is wired into SKILL.md's load lists, and the four documented contradictions (scroll ban vs craft tier, e7 parallax knob, hero-discipline's texture misattribution, color.md's dark-band disagreement) are resolved.

Luffixos added 25 commits July 23, 2026 12:40
…t and craft into index-then-pick files

- SKILL.md 559 to 331 lines: critical floor, flow skeleton, one Rotation
  block, one Picks block, fast mode, per-step Do lines
- anti-patterns.md becomes a 120-line pre-emit list; audit reporting
  moves to verbs/audit.md
- hero-enrichment.md and custom-craft.md become slim indexes over new
  references/enrichment/ and references/craft/ per-pick files
- Core-15 sweep named in slop-test.md for component scope
- pointer cleanup in macrostructures.md and component-cookbook.md;
  tokens.css header count fixed
…ls.md, no-vision study path

- scripts/sloplint.mjs: zero-dep checker for the M-class gates, optional
  render tier, fixtures; calibrated to 0 FAIL on shipped examples
- slop-test.md: every gate tagged M / M-R / R-J / J, numeric fallbacks
  for gates 35 and 44, posture clause on gate 23
- SKILL.md: critical floor, flow skeleton, script-first Step 7,
  harness-neutral phrasing, models.md dispatch, v1.2.0
- references/models.md: per-family quirks, loaded only off-Claude
- study.md: capability check before image mode, fetch-tool neutral wording
- color.md: Colour postures; responsive.md: mechanical-equivalent pointers
…tion contract

- custom-theme.md: reflex check at two altitudes, spent defaults, a
  seven-entry slate, the deterministic draw with wildcards, the scene
  sentence, four colour postures, a five-block direction contract with
  a promise-by-promise finish review; loosened triggers; reworked
  worked examples
- scripts/seed.mjs: reproducible draw (FNV-1a over brief + date + reroll)
- references/direction-atlas.json: 41 design-history lineages dealt as
  wildcards
…ntinue

- scripts/variants/{core,serve,start,await}.mjs: zero-dep picker server
  (loopback only, port walk-up, polling, atomic request queue, idle
  self-shutdown), scaled-iframe grid + single view + keyboard flow,
  chip.js overlay for generated routes, static compare fallback
- references/verbs/variants.md: context detection, per-framework route
  recipes, shared ceremony + direction-plan table, divergence rules,
  the poll ladder, pick-and-continue, riff
…-judge scoring, compare gallery

Arms: Anthropic baseline, GLM on Together, Kimi on OpenRouter (DeepSeek
and Qwen staged, disabled). Six briefs incl. metric-temptation,
component-scope, and vision-probe probes. Floor-only vs full skill packs
to measure prompt bloat. run-matrix orchestrates gen, shots, score,
judge, report; the repair loop feeds sloplint FAILs back to the model.
…urfaced

- one canonical top-of-file order: stamp, critique line, direction contract
- theme-axes.md: the 20-row Rotation lookup now ships inside the skill
- tier taxonomies unified by name; craft tiers keep construction letters
- S1 reworked to stacked-numbered (the old side-column head was gate 54's
  own auto-fail); carnival + lumen examples brought up to gates 54/55/24;
  sloplint: mask/filter exemption on gate 22, precision fix + FAIL grade
  on gate 54, 15-line stamp window
- variants playbook matches the scripts byte for byte (request ids, riff
  shape, fallback wording, flow order); draft-sweep exceptions written
  into slop-test, custom-theme, and SKILL
- study.md: italic roles diagnosed as-is, built roman; preview-examples
  regenerated for v1.2
Full-pack matrix on Claude, GLM (Together), and the Kimi stand-in:
zero mechanical FAILs everywhere after at most one repair round; the
floor-only pack collapses on open models (96 FAILs on GLM), so the full
skill is load-bearing, not bloat. No-vision probe: every model declined
cleanly. Zero invented metrics. Rotation held per arm.

judge.py: Together vision fallback chain + User-Agent fix; vision judge
itself pending API credit or an OpenRouter key. gen-direct: 64K output
ceiling (Claude needed 37K on one brief).
- five-themes cards open a complete full-page mockup per theme
- before/after cards open the actual generated pages (before from
  hallmark-lab, after from the eval runs), copied into _proposals/pages
- eval judge defaults to operator mode: no Anthropic key spend, the
  Claude Code operator scores from the screenshots; --provider together
  or anthropic for an automated pass
…ger, Arcade

Each is a complete self-contained landing page for a fictional brand in
the candidate theme's tokens, grounded in the reference sites (Aesop,
Vitra, Teenage Engineering, The Row, Notion, Mercury, Panic). All seven
pass sloplint clean (0 FAIL, 0 WARN). Linked from the theme cards via the
Open-full-page overlay.
- scripts/lint-hook.mjs: reads the PostToolUse payload, lints .html/.css
  Hallmark artifacts on write, feeds FAILs back via additionalContext,
  never blocks (exit 0 always), no-ops on non-artifacts
- scripts/install-hook.mjs: idempotent settings merge (--global/--print/
  --remove), preserves other hooks and permissions
- SKILL.md Step 7 note + README section; Claude-Code-only, degrades to
  the Step 7 sweep everywhere else
Lean specs (126-145 lines each, from the cobalt.md template) for specimen,
midnight, brutal, garden, atelier, newsprint, terminal, manifesto, almanac,
sport, studio, riso, bloom, coral, aurora, editorial. Each grounded in its
real [data-theme] tokens block and theme-axes row: signature moves,
anti-patterns, voice fixtures, macrostructure affinity, and honest
neighbour-differentiation. Loaded eagerly by Step 3 only when that theme is
picked, so zero cost to any build that picks a different theme. Also cleaned
em/en dashes from the 4 pre-existing specs.
…> 24)

- tokens.css: 4 [data-theme] blocks (full token set; Grid neutrals tinted
  to pass gate 22; Ledger/Arcade color-scheme dark; Arcade second accent)
- main.js: THEMES / ARCHETYPES / THEME_GENRES / COPY entries for all 4
- theme-axes.md: 4 rotation rows; SKILL.md Step 2.6 cluster list; genre
  files (Grid->editorial, Ledger->modern-minimal, Field+Arcade->playful)
- count strings bumped 20 -> 24 across skill, site, README; stale 57->58
  gate counts fixed in marketing copy
- Arcade gate-47 carve-out in slop-test + anti-patterns (pixel/scanline
  allowed; fake OS chrome still banned)
- site loads the 4 new themes' fonts; all 24 render in the live picker
- scripts/imagegen.mjs: opt-in generated-still hook via Together's images
  endpoint (FLUX.1.1-pro default, gemini-3-pro-image optional), cache by
  prompt hash, provenance sidecar. No key -> graceful exit 3, falls back
  to CSS-art / placeholder (verified). Wired into tier-e-generated.md +
  SKILL Step 4 as opt-in, never auto-fires.
- site/examples/{grid,field,ledger,arcade}-01: canonical builds from the
  proposal mockups, all sloplint 0-FAIL, referenced by each theme spec.
Lean specs (131-150 lines) grounded in each new [data-theme] block and its
mockup: signature moves, anti-patterns, voice fixtures, and honest
neighbour-differentiation (Ledger vs Cobalt/Midnight; Arcade vs
Terminal/Hum). Arcade spec states the gate-47 carve-out inline (scanlines,
starfield, pixel type, cursor are the sanctioned retro signal; fake OS
chrome stays banned) and keeps body copy in the readable sans. Catalog
token names throughout; page-decorative tokens noted as page-added.
Runs 'claude -p "/hallmark <brief>"' with the skill copied into a scratch
project, parses the stream-json transcript for conformance (skill loaded via
stamp, files written, reference-read count + load-order, cost), writes into
runs/<brief>/<arm>-cli/. Skills do not auto-trigger headless (measured), so
it invokes by name: a conformance harness, not an auto-trigger test. Claude
arm uses the subscription (no key); GLM/Kimi arms Anthropic-shaped and
disabled until their auth tokens exist. Plumbing validated against the real
binary here (spawn, stream-json parse both event shapes, run.json); a real
run needs a logged-in terminal.
…nce) + smoothness (grafts, section-zoom, decisions) + thumbnails + scoped injection

- scripts: core.mjs picker gains PNG-thumbnail grid (falls back to the
  scaled iframe), a Graft button + G key; serve.mjs adds /thumb + /inject
  routes and a graft action on /api/pick; new thumbs.mjs (dual-engine,
  zero-install); buildInjectJs for dev-only Vite/Astro/SvelteKit preview
  injection. All v1 behavior preserved (smoke-tested end to end + browser).
- verbs/variants.md v2 (280->423): progressive-first flow, parallel default
  + analysis-once + shared head, sketch-depth drafts by default (--full),
  optional --fast-drafts, compositional grafts, section-zoom after the pick,
  decisions.md log, thumbnail step, Vite/Astro/SvelteKit injection recipes.
- eval/variants-bench.{md,mjs}: speed-bench doc + a mechanical timing harness.
- site/_proposals/variants-demo.html: client-only progressive-picker demo
  (gradient text removed to stay on-brand); variants-vs.md head-to-head.

Verified in the browser: progressive fill (building -> thumbnail), labeled
counter, guarded arrows, Pick/Riff/Graft, live single-view iframe.
…, roadmap refresh

Skill and package to 1.3.0; preview-example version strings to v1.3.0;
README variants section rewritten for v2 (progressive reveal, parallel +
sketch-default, thumbnails, compositional grafts, section-zoom, scoped
injection); ROADMAP marks the five v1.3 items shipped.
- main.js: 4 stray '57 gates' marketing strings -> 58
- all-themes.html: visible H1 '20 themes' -> '24 themes'
- gen-cli.mjs header: correct arm ids (claude/glm/kimi) + token env names
  (ZAI_AUTH_TOKEN / MOONSHOT_AUTH_TOKEN)
- ledger spec: radius claim '8px tight' -> '12px card / 8px controls'
- arcade spec: note the starfield/scanline vars are page-local decorative
  tokens (define in :root per arcade-01), not catalog tokens
- tier-e stamp example uses the real imagegen default; hyphens
The example was ported from the proposal mockup with oklch(x% 0 0) neutrals;
the shipped Grid theme tokens carry a faint cool cast (0.003-0.010 at hue 255).
Bring the example's palette in line: 7 FAILs -> sloplint clean.
The picker's single view, the on-page chip, the injection overlay, and the
static compare page all wrapped or barred the page they were showing. Replace
all four chromes with one shared HmDock factory in core.mjs: a compact glass
bar pinned to the bottom-right corner (grid glyph, chevrons, direct number
jump with a dimmed pulse for still-generating directions, small-caps title,
Pick, and an expandable tray with tuple meta, Riff, Graft, and key hints).
The page itself now fills the viewport everywhere.

- chip/inject mount the dock in a shadow root so page CSS cannot touch it,
  and read /api/state to learn titles, meta, and the live direction count,
  so a riffed direction 4 is reachable even with a stale data-of (serve.mjs
  gains CORS on /api/state for the routes-mode cross-origin read)
- chip gains Graft parity and an optional data-title attribute
- single view cycles ready directions only; compare page swaps the fake Pick
  for an honest 'pick N' chip that copies the chat reply to the clipboard
- variants.md updated to the dock (chip contract, picker walkthrough, riff
  note, static-compare shape, poll-ladder wording); site demo mirrors it

Verified in the browser on a scratch run: grid, full-bleed single view,
tray, ready-only arrow cycling, pick queued and drained through await.mjs,
chip on a direct page, live count refresh, static compare, mobile.
Hallmark stops targeting open-weight models and goes deep on the three
terminals where design work happens: Claude Code, Codex CLI, and OpenCode.
Same core everywhere (SKILL.md standard), plus a per-harness adapter each
harness loads before Step 0.

- references/harnesses/codex.md: $hallmark invocation, workspace-write
  sandbox + network-off reality (picker server asks first, --static
  fallback), no hooks/subagents (sequential variants + progressive reveal),
  AGENTS.md as a Step 0 signal, batch-per-direction patches
- references/harnesses/opencode.md: /hallmark + skill-tool invocation,
  allow/ask/deny permission model, parallel variants via its subagents,
  formatter/LSP interplay, compatibility-path discovery
- references/models.md deleted; its harness-agnostic rules live on in both
  adapters. SKILL.md dispatch now routes by harness, not by model family
- agents/openai.yaml: Codex interface + implicit-invocation policy
- scripts/install.mjs: detects installed harnesses and installs a lean
  1.5MB payload (SKILL.md, references, scripts, agents, LICENSE - never
  site/ or eval/) to ~/.claude/skills, ~/.agents/skills (+ refreshes the
  stale legacy ~/.codex/skills copy), and leaves OpenCode to its
  compatibility discovery; --dry-run / --remove / idempotent
- README: 'Open models' section replaced by 'One skill, three harnesses'
  with the install matrix; ROADMAP and eval/README reframed (Tier B kept
  as archive only); version 1.4.0

Ran the installer live: all three locations now serve 1.4.0 with the
adapters in place (the Codex location previously held a 27MB v1.0.0 copy).
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hallmark Ready Ready Preview Aug 6, 2026 2:17pm

Request Review

Unify every version string: skill frontmatter and preview block, package.json,
the four preview-examples samples, the eval direction note, the ROADMAP opener,
and the site badges/captions (which were still stamped v1.1/v1.3). The PR is
retitled to match and sits as a draft on the renamed v1.2 branch.
Luffixos added 2 commits July 30, 2026 16:11
…ng dead links

- Seven theme specs (arcade, cobalt, field, garden, grid, ledger, riso) drop
  'canonical build to mirror' for 'reference build: match its register (tokens,
  voice, motion feel), never its composition; reusing its section order, hero
  geometry, or grid is a gate-32-grade repeat'
- Hum's .btn block becomes a recipe: press mechanics mandatory, skin free;
  the verbatim-copy mandate is gone. Spring easing scoped to micro press/pop
  only, and hero-discipline's bounce ban now says exactly that
- imagery-kit.md reframed: composition playbook today, hosted assets later;
  hard rule that no URL outside the (currently empty) manifest is ever emitted;
  the wash example now shows the constructed gradient equivalent
- hero-enrichment's Kit-led route renamed Composed-abstract (built in-page)
Every Hallmark hero shared one geometry (70-90% viewport, bottom-heavy 1.3x
padding). hero-discipline.md now opens with a posture table - Settled (the
old geometry, still the default), Banner, Poster, Ledge, Corridor, Stage -
each with its own min-height envelope, padding rule, alignment allowance,
H1-H9 pairings, and genre affinity. Mobile collapses to content height.

- hero-discipline.md loads on EVERY page hero now, not only enriched ones
  (SKILL.md Step 3 Always list), and the posture is picked at Step 2 with
  nav/footer, rotated (no non-Settled repeat back-to-back, Settled never
  three in a row), logged (hero: Stage/H2), stamped, and in the Picks block
- gate 6: the 100vh/100dvh ban is scoped outside a stamped Poster; the
  centred-element ceiling binds unchanged on all postures
- gate 44a: the padding check reads the stamped posture (Ledge inverts to
  top-heavy with base-anchored content, an anchored Poster waives it);
  44b fold-fit at 1280x800 stays posture-independent
- typography.md: define --text-display-s (referenced by the headline
  brackets but never declared): clamp(2.2rem, 4vw + 0.75rem, 4.2rem)

No script changes; absent stamp field = Settled, so every existing build
stays legal (canonical example dirs verified 0-FAIL).
Luffixos added 10 commits July 31, 2026 12:15
The round-1 plan included per-model tic bans for the harness adapters but
the item fell out of the execution order; landing it now. codex.md gains a
Model-tics-to-refuse section (ghost cards, sketchy SVG filler, feTurbulence
grain washes as filler, diagonal-stripe wallpaper, emoji bullets), and
opencode.md gets the symptom-keyed version since it runs many models, with
the standing line that the Critical floor and gates outrank any model's
taste. Refuse-by-default framing: the brief's own words can earn a pattern
back, the model's taste cannot. The grain line points at the forthcoming
texture.md so budgeted texture stays sanctioned while filler grain stays
refused.
The grain/halftone/misregistration/scanline recipes scattered across the
riso, carnival, and arcade specs (plus the assets.md feTurbulence recipe)
generalize into references/texture.md: five named artifacts with tokened
budgets (--texture-opacity caps, one artifact family per page, never
animated, pointer-events none), an affinity table (Riso/Carnival/Arcade/
faint-Newsprint earn it; Specimen/Atelier/modern-minimal stay banned), and
a custom-ritual hook (B.6b: print-lineage draws may take ONE artifact).

Rides along: e7's knob drops its scroll-linked-parallax option (it
contradicted the page-wide parallax ban), hero-discipline's grain note
stops claiming Specimen/Atelier carry texture (they ban it) and now names
the real carriers, and the starfield ban line gains the scoped Arcade
carve-out cross-reference so the two files stop arguing. Specs point at
the shared recipes; SKILL.md Step 3 loads texture.md conditionally.
motion.md banned scroll-scrubbed animation 'unless there is a specific
reason' while tier-c sanctioned animation-timeline outright - a live
contradiction with no vocabulary between them. references/
scroll-choreography.md now IS the specific reason: four named patterns
(pinned chapter, scrub-linked headline, progress spine, sticky diptych)
with Baseline-2025 recipes, each inside @supports + reduced-motion +
min-width guards so the base page is always the finished page. Two
correctness rules are baked in: the animation shorthand resets
animation-timeline (declare after), and pinned-pane children cannot drive
their own view() (steps ride a named timeline on the tall track).

Budget: one pattern per page (sloplint F8 will count), never on body
text, linear easing for scrub, hero orchestration untouched, JS fallback
is the IO reveal-once only. motion.md reroutes to the vocabulary, tier-c's
decision row defers to it, macros 14/16 and f2 point at it, and SKILL.md
loads it conditionally.
references/dark-mode.md: per-token re-derivation table (elevation gets
LIGHTER, accent chroma drops as lightness rises, hue never moves, body
weight -50), the exact dual-block emission shape ([data-mode=dark] plus a
prefers-color-scheme auto block guarded by :root:not([data-mode]), with
the no-flash toggle note and color-scheme), and the dark discipline:
shadows become lightness or inset rings (glow stays a THEME carve-out,
named), cards sit lighter than canvas, one heading colour, never CSS
invert on raster, kit multiply assets skip dark. Both modes run the full
gate sweep and the stamp records modes: light+dark.

color.md's recipe shrinks to a pointer and its 12-16 vs 12-18 paper
disagreement unifies at 12-18. Dual-mode stays strictly opt-in: a dark
theme is not a dual-mode page. SKILL.md gains the Step 6 bullet and the
conditional load entry.
references/data-viz.md: form heuristic first (one value = stat tile never
a one-bar chart, > 7 categories = a table, parts-of-whole = stacked bar
never pie/donut/gauge), hand-built SVG construction specs (bars <= 24px
baseline-zero, 2px lines, 1px solid gridlines never dashed, ONE y-axis
never dual), colour adapted to the one-accent discipline (lightness ramp
on the accent for multi-series, fixed order never cycled; labels never
wear the data colour), honesty riding gate 46 (zero baselines, annotated
zooms, internally consistent sample data), the dark note, and the
dashboard bar: one figure, one chart, one table - the six-gauge KPI wall
is the tell this file kills. Stat-Led, Ledger, Sport, and Almanac point
at it; SKILL.md loads it conditionally.
references/brand-truth.md: when a brief names a real company, the brand's
colours and fonts are captured mechanically (homepage + same-origin CSS
under study.md's remote-safety rules, meta theme-color, names-only font
CSS) into .hallmark/brand-spec.md with provenance and a derived-not-
guessed attestation, and theming anchors on the spec. Memory hex is a
named failure. The spec caches like preflight.json (90-day staleness,
design.md still outranks it), the no-fetch path asks once and otherwise
builds free of brand claims, and real logos are never redrawn or
hotlinked from strangers. Wired as pre-flight signal source 0.5, into the
Step 1 brand-colour signal, the conditional load list, and custom B.1's
anchor derivation.
references/finish.md joins the every-build list: heading measure by size
(ch caps ON the element, from ~20ch at display down to ~45ch at xl, body
envelope untouched), typeset punctuation (curly quotes, true ellipsis,
non-breaking unit pairs, tabular-nums on comparing numbers), text-wrap
balance/pretty, hanging punctuation on pull-quotes, one filled primary
per page, the button height budget threaded through the existing 44px
floor and 48px coarse-pointer rules via the hit-target expansion recipe,
icon discipline (one set, natural grid, no coloured coins, first-line
alignment), concentric radii (inner = outer - padding), the mobile-runs-
larger idiom (body-adjacent UI steps DOWN at 60rem; display clamps
exempt; 16px mobile floor), and motion finish (exits 60-75% of enters,
stagger bands 30-50/60-100ms).

Companions: typography.md gains the measure table at its sizing section,
motion.md's exit ratio widens from ~75% to the 60-75% band so it stops
disagreeing with microinteractions.md, responsive.md points at the
mobile-larger idiom. The F-tier checks land separately.
…move

layout-and-space.md gains § Surfaces directly above Depth: whitespace,
then a hairline seam, then a tinted well (paper-2/3, no border - the tint
IS the boundary), then a card, reserved for independently interactive or
fundamentally different content. Never straight to cards, never white
cards on a tinted page, and Depth now reads as the ladder's dressed top
rung. Gate 9 names the ladder as its fix vocabulary: different regions
climb different rungs. The F7 monotony check lands with the F-tier.
sloplint gains F1-F9, a tier that reports beside the gates without ever
counting in the 58: straight quotes and three-period ellipses caught on a
new position-preserving masked-prose view (code blocks, comments, and
tags space-padded so line numbers stay exact; entity-encoded quotes match
too, and doc.text now decodes quot/apos/hellip/mdash for future text
checks), missing text-wrap balance on display heads, more than one
filled-primary button, icon-in-coloured-circle coins, display-size
numerics without tabular figures, one container recipe stamped across
six-plus selectors, a second scroll-choreography pattern, and fake-human
avatar hotlinks (the tier's one FAIL) with person-keyword stock URLs as
the WARN half. gateSortKey groups F ids after the numbered gates;
component scope inherits F4/F5/F6/F9.

Verified: a fixture trips all nine with correct grades and lines; the
canonical examples stay 0-FAIL (their handful of new F-WARNs is the tier
working); the legacy sweep holds at exactly the 190-FAIL baseline.
…ore fake people

site/imagery/ now ships (serving at usehallmark.com/imagery/ on deploy):
16 photoreal placeholder avatars (768px, varied ages/skin/hair on neutral
studio grounds, natural texture, no smooth-mesh AI look; provenance JSON
sidecars committed; each paired deterministically with a unisex name so
gate 19 never meets another Jane Doe), 4 watercolor washes and 4 single-
colour brush gestures on white ground (composited via multiply - no faked
alpha; the category skips dark themes), 4 hand-built tileable texture
SVGs, 12 hand-built currentColor marks in four geometric families (inline
them - img cannot inherit currentColor; wordmarks are a composition of
mark + display-token text, since baked-text SVGs cannot use page fonts),
and 3 app-screen frames built on Hallmark tokens with their HTML sources
committed beside them for one-command re-render. Total 1.7MB, ~$1.06 of
Together spend, every generated file QC'd in the browser (two off-brief
brushes were regenerated single-colour and pixel-verified).

imagery-kit.md's manifest is now the real allowlist with provenance
columns; the categories table gains avatar/mark/screens rows and the
white-ground multiply contract; the placeholder ladder's tier 1 points at
the real kit and tier 4 loses person keywords (F9's territory); the
portrait row of the image-need table routes to kit avatars.
Luffixos added 3 commits July 31, 2026 12:37
…gh, usage capture

gen-cli.mjs learns --model and --effort (forwarded to the claude call),
a bare no-skill control arm (plain brief prompt, no skill copy), a $3
per-cell budget guard, and --setting-sources project on BOTH arms so the
user-scope hallmark install can neither leak into the control nor
version-skew the skill arm; stampPresent on a bare cell doubles as the
leak detector. The result event's usage lands in run.json (tokens
in/out/cacheRead, turns, stop subtype) with the camelCase modelUsage
fallback, and cells are named arm-effort-cli so effort variants coexist.
…minal

Running the harness from inside a Claude Code session leaks
ANTHROPIC_BASE_URL and the CLAUDE_CODE_* host vars into the spawned
claude, which then reports not-logged-in even in an authenticated
terminal. The child env now drops them alongside the API key. Also
removes the six dead cells that run recorded: headless subscription auth
needs a terminal login this environment cannot perform, so the A/B
results were produced with in-session subagents instead (disclosed in
the PR).
Two briefs (voice-cloning studio, pre-traction B2B SaaS) built twice
each, once with no skill and once running the Hallmark flow, same model
and same subscription. Artifacts, run records, and the skill's own state
files land under eval/runs so the comparison is auditable rather than
asserted: the two control pages carry 95 sloplint failures between them
(off-scale spacing, unowned colour literals, pure #fff surfaces,
layout-property transitions, no provenance stamp), the two skill pages
carry none, at roughly a third more tokens and a tenth more wall-clock.
Both arms respected the pre-traction brief's honesty constraint, so that
half of the test was a wash and each run.json records it that way, along
with the runner substitution and the effort setting actually used.
The eval run outputs, the internal design proposals, and a scratch QC
page for the imagery kit were all riding along in the PR while being
linked from nothing. They come out of tracking: eval/runs (the four A/B
cells from this session plus the older model-comparison artifacts, all
of it evidence rather than product), site/_proposals (44 files of
before/after and theme-exploration pages, preserved outside the repo),
and site/imagery/_qc.html (a scratch grid I used to eyeball the
generated assets). The eval harness itself stays so the tests are
re-runnable, and .gitignore now covers the pycache and the QC pages that
slipped past it.

The four theme examples added this round stay: arcade-01, field-01,
grid-01, and ledger-01 are the worked examples their own theme docs link
to, not stray test output.
Luffixos added 7 commits July 31, 2026 17:43
Hallmark was telling good models what to build. This splits it into a floor
that binds and a library that offers, and bans the eyebrow outright.

The eyebrow. Gate 54 goes from geometry to existence: short inert type before a
heading that announces it is banned in every arrangement, and no brief earns it
back. The detector inverts from CSS-first to DOM-first, so it now sees flex and
block stacks, heads declared inside a media query, class-less headings, and the
word "overline". Small type before a heading survives only when it carries a
fact, a destination, or an identifier, which keeps captions, field labels,
datelines, unit labels and linked chips legal. references/section-entry.md is the
replacement: twelve ways into a section, ten of them pointing at material the
skill already had.

Themes stay themes. A written contract in theme-axes.md says a theme carries
material and never a page plan, and all 24 are trimmed to it: 4,070 lines down to
2,861. Lumen loses a mandatory hero apparatus and a fixed section sequence; hum
loses 45 lines of global layout rules filed under a theme. Fake brands, invented
people and shippable taglines come out. Genre files stop mandating nav and footer
archetypes they disagreed with the themes about.

Tiers. All 58 gates gain one: 34 carry a Floor clause nothing ships through, 18
are Reflex gates a build with an argument can waive on the record, 6 never block.
Fifteen gates split so a real floor stops dragging a taste threshold behind it.
Gates 42 and 43 stop ordering a rotation through the catalog and instead ask that
the default be named rather than defaulted into. A waiver declares itself in the
stamp with guard evidence the linter re-derives; three per artifact, one per
gate, Floor never waivable, and an over-cap waiver lets its gate fire so waiving
twelve is worse than waiving none.

The catalogs stop being a mandatory pick. Step 2 asks for a designed page shape
stated in plain words; the named shapes are there when a starting point helps.
Anti-repetition moves from "rotate the codes" to "differ from your last three and
say how", which constrains sameness without constraining invention.

Contradictions. Display line-height had three ranges and now has one owner. The
outlier face was capped at two slots by one line and uncapped by the next. Gate
39 hard-coded 44px against finish.md's 32-40px allowance. Gate 14 banned padding
animation that floating-nav.md prescribes. Gate 57's theme list had drifted to 20
of 24. F3 and gate 51 fought over overflow-wrap; break-word settles it.

Evidence. 201 eyebrows removed across 38 example pages and 32 across the archived
test builds, each replaced with a real opening rather than deleted; aggregate
failures fell while doing it. The marketing site drops its own section labels and
moves hero labels below the lede. A cold build through the revised skill lands
0 FAIL / 0 WARN, names its own structure instead of picking a code, and argues
with a Reflex gate rather than waiving it.
…s are true again

Four things the last pass left open.

Reflex findings no longer masquerade as Floor failures. They report at a new
REFLEX grade which still blocks, so nothing drifts silently, but "0 FAIL" is now
a true statement about the floor even while a build owes an argument above it.
Across every committed page that distinction turns 230 reported failures into 56
real Floor findings and 174 arguable ones, which is the number that was hiding.

The waiver cap is gone. Three-per-artifact was the restraint the tier existed to
remove: a colour-field poster that wants a black stage, achromatic neutrals, a
long measure and one face doing everything is right, and it was being blocked for
being expressive. Guards, reason quality and the log are what keep waivers honest.
Past three the build gets a NOTE saying what it now is, a house style rather than
a set of exceptions, and pointing at design.md.

The Floor has two admission criteria instead of one embarrassed exception. Door 1
is "no admired page breaks this on purpose". Door 2 is a named house rule where
admired pages do break it but a language model reaches for it unprompted on every
section. Gate 54 is the only member, listed in a table that any future addition
has to join explicitly. The apology is gone; the reasoning is in the file.

Finish findings gained a record form. `answered <check> · <reason>` parses, so a
build that reasons its way past gate 38 leaves something the next run can read
instead of prose in a comment.

Also: the skill stops mandating em and en dashes in page copy, which had it
arguing with its own house rule. The Picks block and the Step 5 preview merge into
one recital, since the same decisions were being serialised four times. The font
catalog and the per-tone voice samples become skip-unless-needed, roughly 200
lines a build. Two waiver bugs found by a cold build are fixed: "intentional
design choice" was passing the boilerplate test, and a malformed two-field waiver
was being ignored in silence.

The 18 hero captures and 14 gallery thumbnails are regenerated against the live
pages, so the README and the homepage stop advertising eyebrows the skill bans.
…ould not have reached for

Every build now derives its own visual world. Silence used to route to the
catalog; it routes to the ritual instead, and the 24 themes become a fast path
you ask for by name, by --fast, by an existing design.md, or by component scope.
custom-theme.md is promoted and renamed to direction.md, trimmed from 336 lines
to 258, and the draw runs on every build rather than on a branch that almost
never fired.

Nine themes prescribed a display face that is a training-data default, one of
them (Source Serif, on Field) already on our own ban list. All nine are re-faced:
Specimen to Bodoni Moda, Studio to Erode, Atelier to Sentient, Newsprint to Zilla
Slab over Spectral, Sport to Saira Condensed, Editorial to Bricolage Grotesque
over EB Garamond, Cobalt to Familjen Grotesk, Hum to Chillax, Field to Literata.
Atelier moving off a Didone also settles the Specimen collision the rejection
table had been arbitrating by hand. The catalog keeps the saturated faces but
now says plainly that they are the first answer, and treats them the way R.2
treats any spent default.

Repairs the flip exposed. Gate 57 tested for the presence of a catalog name, so
a derived build stamped theme: custom and sailed past the exact failure the gate
exists to catch; it now tests the absence of studied-DNA. macrostructures.md
still ordered you to pick a shape before writing code. Colour posture was scoped
to custom builds only. Two gate exceptions in the playful genre were scoped to a
theme name that a derived build cannot claim, and are now scoped to the declared
property.

The tier map had a worse bug than any of those. Thirteen gates carry a Floor
clause and a Reflex clause under one number, and the linter held one tier per
number, so six Floor clauses were quietly waivable and seven Reflex clauses were
quietly unwaivable. tierOf() now resolves the exact clause first, and gates 7,
24, 38a, 47 and 55 emit the clause they actually found. Gate 47 was also
reporting WARN for a Floor violation that reads "fail, always".

That surfaced real defects in the corpus: seven italic emphasis words inside
roman headlines, the top AI tell, sitting in our own showcase pages. They are
now roman accent spans. Two improvised absolutes in the contact sheet use the
token that was already declared beside them. The study verb's output page had
six hand-written numerals above headings, missed by the eyebrow sweep; the list
is a real ol with a counter now.

Corpus: 56 findings down to 41, zero gate 54, Floor enforced honestly.
Read-set cost of the flip: +303 lines a run (+19.3%), down from +400 (+25.4%).
That is short of the +200 target and I am not closing the gap by gutting the
palette construction or the font guidance, which is where the remaining weight
sits and what makes a derived run worth taking.
.work is a two-column grid holding three items: the counter, the name, and the
description. With no placement the description auto-flowed into row 2 column 1,
so every project blurb rendered 96px wide and wrapped to seven lines. Pinning it
to column 2 puts it under the name where it belongs.

The row gap was a second bug hiding behind the first. .work__name already
declares an 8px bottom margin for exactly this pair, but the grid's 32px gap
stacked on top of it, so the two spacing systems fought and the name sat 40px
above its own description. The gap is now column-only, in both the base rule and
the narrow-viewport override, and the margin the author wrote is the one that
governs.

Checked at 1280px and 375px: name and description share a left edge, 8px apart,
no horizontal overflow. Still 0 FAIL.
Two mechanisms Phase 1 could not supply, both conditional, neither able to block.

Step 5.5 renders the first viewport before composing it in CSS. It fires only
when TOGETHER_API_KEY is present (signal 9); with no key the step does not exist
and nothing else changes. Two comps at 1280x800 built from the direction
contract rather than the brief, varied on one compositional axis so the
comparison means something, one approval point, then build. The prompt carries
the scene sentence, the paper and accent as plain colour words, the display
class rather than a face name, and one negative clause pushing off the category
default, because a prompt that reads like the brief returns the category default
in pixels and that is what R.1 already spent its budget refusing.

The comp gets no vote on the Floor. An image generator will hand back eyebrows,
a gradient ramp and a fake browser window because it has read none of the gates.
Same rule as an archive exemplar: take the composition, not the compliance.

Reproduction is the part that makes the step worth having. A model reliably
believes its recreation succeeded when it did not, and the belief is what stops
it looking, so the built hero is screenshot at the comp's own dimensions and
answered in writing on mass, interval and entry before anything below the fold
exists. Diverging from the comp deliberately is fine. Diverging without noticing
is the failure.

The medium inventory sits under it: every region gets a written implementation
medium before any of it is built, and the gate is that a CSS gradient is not a
texture. Writing CSS against woven cloth or printed grain is how a committed
comp silently becomes a flat page with the same section order.

Step 7 gains a reviewer with no inherited transcript. The thread that walks the
gates is the thread that formed every opinion it is grading and reads the page
as the thing it meant rather than the thing it made, which is the weakest
reviewer available and the one every build has used. The new one gets the
artifact, the screenshots, the contract and the Floor list, and nothing about
why. It answers the question no gate can reach: does the direction contract
describe the page in front of it. Every gate is local, so a page can pass all
fifty-eight while quietly not being what its own stamp claims.

Findings are then scored resolved, partial or unresolved rather than
re-reviewed, unresolved is a legitimate outcome, and two rounds is the ceiling.
Off Claude Code the review runs in-thread and says so, because the user is
entitled to know which one they got.

Read-set cost for a run with no key and no subagents: zero. comp.md loads on
signal 9 only, and the reviewer brief lives in slop-test.md, which already
loaded at Step 7.
The subagent brief told each draft to sweep the Floor tier, which contains the
eyebrow ban, while loading neither section-entry.md (the twelve other ways into
a section) nor hero-discipline.md (the hero rules, and a sketch-depth draft is
mostly hero) nor the genre file nor the direction ritual. Three drafts were
being asked to clear a bar with the manual withheld. All five are in the load
list now.

All three directions derive, the same as any other build. This also makes the
paper-band spread satisfiable for the first time: the catalog holds exactly two
mid-band themes, both cool and both grotesk, so a catalog-only run could not
fill the mid slot twice without colliding on a second axis, and with the last-3
rotation it could not fill it a third time at all. The rule was stated as
non-negotiable and was quietly impossible. A derived system lands wherever the
band needs it. A theme the user names for one direction still costs that
direction its ritual and not the others.

Sections 4 and 5 were in the reverse of execution order: the flow says serve the
skeleton picker first and generate into it, section 5 said "do this BEFORE the
directions finish", and it sat after section 4. Swapped, renumbered, and the
five cross-references repointed.

Smaller things. Promotion said "fix every FAIL or waive it on the record", which
is the pre-tier vocabulary; FAIL is the Floor and is never waivable, REFLEX is
the tier a waiver exists for. The port was assumed at 4180 and every file
rewritten when it turned out otherwise, while start.mjs prints the real one on
every start. SKILL.md advertised three full directions while the verb has
defaulted to sketch depth with --full as the override. The manifest example
still described a catalog pick.

Forty lines of Vite, Astro and SvelteKit dev-config move to
variants-injection.md, read only once the user has agreed to the config edit,
and one restated picker description collapses to a pointer.
…ping

Signal 8 used to mean "derive, but measure the reflex first": the build
called out for a consensus triple and argued with it. That put two design
systems in one page and neither one won.

It now means the opposite. A connected archive owns the brief, the
structure, the system and the code; Hallmark skips Steps 1 through 6 and
enters at Step 7 over whatever landed. The sweep infers the genre nobody
picked, fixes the material half in place, and prints the structural
findings it cannot repair without throwing away the page. Gate 20 learns
a second stamp so a swept page can record the sweep instead of claiming
a build it did not do.

The standalone path is untouched. No archive, no signal 8, and the flow
runs exactly as before.
…measuring the old skill

b1 names no theme, so it must derive, and it did: direction.md was the first
reference read, the stamp carries a real seed and a five-line direction
contract, and the derived world (the IPA vowel quadrilateral, plotted, on a
speech-lab plate) reaches the actual hero rather than stopping at the stamp.
Twelve reference reads, zero waste, in the right order. R.1's rejection is
legible in the genre note: it refused the radial blooms the atmospheric genre
would have allowed, because the reflex check had already spent that move.

b7 passes --fast and must not derive, and did not. It read two theme files and
never opened direction.md. No seed, no contract, no slate, no draw line. The
posture line still emits, which is the color.md repair working: posture is
universal now, not a derived-run field.

Both artifacts lint clean at 0 FAIL, 0 REFLEX, 0 WARN.

Three harness bugs, all of them the flip's doing. stampPresent scanned a fixed
filename list of index.html, styles.css and tokens.css, and a build that named
its stylesheet page.css scored skillLoaded=false with a correct stamp sitting in
it; its regex also demanded Hallmark immediately after the comment open, so
"/* Formant Studio · Hallmark derived system" missed too. It now scans every
emitted css and html and matches the marker anywhere in a leading comment.

The reference-read budget was ten, set when a run read one theme file. A derived
run reads direction.md and theme-axes.md in its place, so the floor moved up by
one, and a clean derived build measures twelve. Fourteen leaves room for two
conditionals and still catches the thing the check is for, which is defensive
pre-loading of a forty-file tree.

The cost cap was three dollars, hardcoded. A derived build on Opus lands near
three and stopped mid Step-7, which scored a complete artifact as
error_max_budget_usd and never exercised the gate sweep at all. It is --budget-usd
now, defaulting to five.

b7 also joins the brief set: the suite had no coverage of the catalog fast path
after that path stopped being the default.
…e bug

The runs archive copied a fixed filename list, index.html, tokens.css,
styles.css, and stampPresent scans that archive. A swept build whose stamp
lives in page.css scored skillLoaded=false with a correct stamp on disk,
which is the same stale assumption already fixed in stampPresent and in the
reference budget, one function lower. The archive now takes every top-level
html and css the build produced.

The three affected run.json files are rescored from the real artifacts:
only the buggy cell changed (inspo false to true); the bare control stays
false, which is the leak check holding. Also archives the second three-arm
run: bare 56 FAIL with the same six numbered eyebrows, both Hallmark arms
clean, and the control now provably offered zero MCP tools.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant