feat(surfaces): deck → WordPress + email + letter + CLI/ASCII from one ForgeBlock spec #33
No reviewers
Labels
No labels
priority
P1
priority
P2
priority
P3
priority
P4
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Toilville/toilville-design!33
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/deck-to-surface-pipeline"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
One ForgeBlock spec → four static surfaces
This wires the design system's ForgeBlock JSON through to WordPress FSE patterns, transactional email, letter email, and a CLI/ASCII floor — the same JSON the Rituals app (SwiftUI) and Flutter already render. Tokens bind per surface: WP presets (editable swatches), email inline-hex, ASCII none. All 30
forgeblock.ymlblocks render on every surface, guarded bytest_block_coverage.py(95 tests green;just checkdrift-gated).Artifact frames: see the generated
udg/products/<brand>/wp-preview/(patterns, email, letter, cli) for all 5 brands.👋 @ville — design decisions that need your sign-off
None of these are locked; I've made provisional calls so the pipeline runs end-to-end, clearly quarantined so nothing lands in the DTCG source until you confirm. Please check the boxes or redline:
1. Token gap fill-ins —
udg/products/TOKEN_GAP_PROPOSALS.mdDiffing each landing against its DTCG surfaced colors the landings use that have no token. Highest-priority new hues:
text.secondary#A0A0A0,accent.success#2BBC8A(the SETTLED badge — the one blocker),text.on-accent#3A0E0Etext-secondary#5A5A5A,white#FFFFFFborder#E4E4EA,primary-hover/primary-active,secondary-hoversurface.tint#ECEAE8(+ needs asecondaryslug — buttons currently fall back uncolored)Confirm values (or supply your own) → they move into each brand's DTCG source and the provisional sidecar is deleted.
2. Explicit vs. derived — the control policy
Recommendation in the doc: borders become explicit palette tokens (so they're editable swatches in the FSE Site Editor — derived
rgba()is invisible to the designer), while hover/active shades stay derived from a globalstate.hover-shiftconstant.3. Border α-ladder
Four of five brands independently reinvent
text @ ~16%/~12%hairlines. Proposal: define oneborder.default/border.subtleladder, resolved per brand astext @ opacity.border, emitted as explicit swatches.4. New surface profiles —
udg/config/surface_profiles.ymlAdded
deck.landing,email.transactional,email.letter, each with regions +allowed_blocks. Email excludesinput(static surface).5. Cross-surface vocabulary drift (design call)
The Swift
ForgeBlockenum has 33 cases (incl.video,appleContactCard,appleCalendarSlots);forgeblock.ymldeclares 30 (hasmedia, notvideo). They should be one vocabulary.forgeblock.yml, or drop them?Not blocking, but flagged
*Email.dc.html/*Letter.dc.htmlare scaffolds with placeholder copy (fux is the written exemplar) — authoring task, not sign-off.wp-preview/artifacts are committed and drift-gated (just check); say the word if you'd rather they be gitignored.How to review the output
Docs:
docs/UDG_LABELING_GRAMMAR.md,docs/DESIGN_TO_WP.md.Render one ForgeBlock JSON to four static surfaces, binding each brand's theme.json palette its own way (WP presets, inline hex, none for ASCII): - dc_html_to_forgeblock.py — label-aware .dc.html → ForgeBlock JSON (data-block/data-token/data-bg grammar overrides the heuristic) - forgeblock_pattern.py — full 30-block coverage (+ section background, status color override, generic programmatic fallback) - forgeblock_email.py — transactional + letter email (tokens inlined as hex) - forgeblock_ascii.py — 80-column 7-bit ASCII floor (cli.80col profile) - build_surfaces.py — orchestrator; wired into `just build`/`just check` - surface_profiles.yml — +deck.landing, email.transactional, email.letter - test_block_coverage.py — 30 blocks × {WP, email, letter, ASCII} Also: email/letter templates for all 5 brands, fux+pardner wp-style.json palette maps, generated wp-preview artifacts, and docs (UDG_LABELING_GRAMMAR, DESIGN_TO_WP, TOKEN_GAP_PROPOSALS).@ville — decisions to sign off on, enumerated. Reply per number (👍 to accept my recommendation, or redline). Nothing here is in the DTCG source yet; all provisional bits are quarantined until you confirm.
D1 — fux
accent.success=#2BBC8AThe SETTLED position badge. The one hard blocker: fux has no success token, so the badge can't normalize until this lands.
Recommend: accept
#2BBC8A.D2 — fux
text.secondary=#A0A0A0Most-used color on the fux landing (18×) with no token today.
Recommend: accept.
D3 — fux
text.on-accent=#3A0E0EInk on the red thesis band (text on
#E63535).Recommend: accept.
D4 — spelwork
text-secondary=#5A5A5A+white=#FFFFFFmutedis green (#587C6D), not the body grey; 16 unmapped uses.whiteis the raised card surface vsbackground #FEFEFE.Recommend: accept both.
D5 — pardner:
border#E4E4EA,primary-hover#9C90EE,primary-active#5C4ECB,secondary-hover#FF9B85Recommend: accept
border; treat the hover/active as candidates for D8's derived approach instead of explicit hex — your call.D6 — peterswimm needs a
secondaryslugSecondary buttons currently render uncolored (no slug). Also proposed
surface.tint#ECEAE8.Recommend: pick a
secondaryhue; acceptsurface.tint.D7 — Border α-ladder, shared + explicit
Four of five brands reinvent
text @ ~16%/~12%hairlines. Define oneborder.default/border.subtleladder, resolved astext @ opacity.border, emitted as explicit palette swatches (so they're editable in the FSE Site Editor — a rawrgba()is invisible to the designer).Recommend: adopt.
D8 — Explicit vs. derived policy
Borders + brand hues = explicit tokens (editor-addressable). Hover/active states = derived from a global
state.hover-shiftconstant (one knob, consistent across brands).Recommend: adopt.
D9 — New surface profiles (
udg/config/surface_profiles.yml)Added
deck.landing,email.transactional,email.letterwith regions +allowed_blocks. Email excludesinput(static surface).Decision: do the regions + allowed-block sets match how you'd author these surfaces?
D10 — Cross-surface vocabulary drift
Swift
ForgeBlock= 33 cases (incl.video,appleContactCard,appleCalendarSlots);forgeblock.yml= 30 (hasmedia, notvideo). Should be one vocabulary.Decision: which is canonical — fold Swift's extras into the manifest, or drop them?
Non-blocking (FYI, no sign-off needed): the 8 brand
*Email/*Letter.dc.htmlare scaffolds with placeholder copy (fux is written out);wp-preview/artifacts are committed + drift-gated.@ville — decisions to sign off on, enumerated. Reply per number (👍 to accept my recommendation, or redline). Nothing here is in the DTCG source yet; all provisional bits are quarantined until you confirm.
D1 — fux
accent.success=#2BBC8AThe SETTLED position badge. The one hard blocker: fux has no success token, so the badge can't normalize until this lands.
Recommend: accept
#2BBC8A.D2 — fux
text.secondary=#A0A0A0Most-used color on the fux landing (18×) with no token today.
Recommend: accept.
D3 — fux
text.on-accent=#3A0E0EInk on the red thesis band (text on
#E63535).Recommend: accept.
D4 — spelwork
text-secondary=#5A5A5A+white=#FFFFFFmutedis green (#587C6D), not the body grey; 16 unmapped uses.whiteis the raised card surface vsbackground #FEFEFE.Recommend: accept both.
D5 — pardner:
border#E4E4EA,primary-hover#9C90EE,primary-active#5C4ECB,secondary-hover#FF9B85Recommend: accept
border; treat the hover/active as candidates for D8's derived approach instead of explicit hex — your call.D6 — peterswimm needs a
secondaryslugSecondary buttons currently render uncolored (no slug). Also proposed
surface.tint#ECEAE8.Recommend: pick a
secondaryhue; acceptsurface.tint.D7 — Border α-ladder, shared + explicit
Four of five brands reinvent
text @ ~16%/~12%hairlines. Define oneborder.default/border.subtleladder, resolved astext @ opacity.border, emitted as explicit palette swatches (so they're editable in the FSE Site Editor — a rawrgba()is invisible to the designer).Recommend: adopt.
D8 — Explicit vs. derived policy
Borders + brand hues = explicit tokens (editor-addressable). Hover/active states = derived from a global
state.hover-shiftconstant (one knob, consistent across brands).Recommend: adopt.
D9 — New surface profiles (
udg/config/surface_profiles.yml)Added
deck.landing,email.transactional,email.letterwith regions +allowed_blocks. Email excludesinput(static surface).Decision: do the regions + allowed-block sets match how you'd author these surfaces?
D10 — Cross-surface vocabulary drift
Swift
ForgeBlock= 33 cases (incl.video,appleContactCard,appleCalendarSlots);forgeblock.yml= 30 (hasmedia, notvideo). Should be one vocabulary.Decision: which is canonical — fold Swift's extras into the manifest, or drop them?
Non-blocking (FYI, no sign-off needed): the 8 brand
*Email/*Letter.dc.htmlare scaffolds with placeholder copy (fux is written out);wp-preview/artifacts are committed + drift-gated.D1 👍 — accept accent.success = #2BBC8A for fux-capacity. Unblocks the SETTLED badge.
D2 👍 — accept text.secondary = #A0A0A0 for fux-capacity.
D3 👍 — accept text.on-accent = #3A0E0E for fux-capacity.
D4 👍 — accept spelwork text-secondary = #5A5A5A + white = #FFFFFF. The existing muted = #587C6D is a green accent, not body grey — correctly separate.
D5 👍 — accept all four pardner tokens (border #E4E4EA, primary-hover #9C90EE, primary-active #5C4ECB, secondary-hover #FF9B85). On hover/active: going explicit per brand rather than derived. Each brand owns its own values; D8 covers the policy.
D6 👍 — peterswimm secondary = #C68B3E (warm gold, complements the green text.accent on the paper surface). Also accept surface.tint = #ECEAE8.
D7 👍 — adopt the border α-ladder. Note: spelwork's existing border = #E1B659 is the gold accent underline, so the neutral hairline tokens need distinct slugs (border-default / border-subtle) alongside it.
D8 👍 — adopt explicit vs. derived policy. Borders + brand hues = explicit; hover/active = derived from state.hover-shift going forward. D5's pardner tokens are pre-policy hand-crafted values that land close enough (secondary-hover is exact; primary-hover ±1%).
D9 — redline on footer: email.transactional.footer should allow actions. Unsubscribe / manage-preferences links are standard transactional email footer content, and actions in email renders as text links (static surface), so the no-input rule isn't violated. Rest of the profile shapes look right. ✅
D10 — this feels like an engineering call rather than a design sign-off. Flagging back to you: which do you want as canonical?
@peterswimm