Rituals: house-style views over ritual events, with user lenses #177

Closed
opened 2026-10-04 20:20:20 +00:00 by peterswimm · 5 comments
Owner

Revised 2026-10-04. The first version of this issue asked for one design per screen. The direction has changed: you design how each ritual event and entity looks in the house style, the API serves those designs as data, and people can swap in their own version (a "lens") for the things they look at most, like wishes and parlays.

How it fits together

Layer What it is Where it lives Who owns it
Events Facts like "wish created" or "status changed", already flowing through Kafka Kafka topic schemas, published in the API spec Engineering
Commands What someone can do next ("complete", "reopen", "approve"), each with its input fields The wish state machine, served by the API as available_commands Engineering
Views How an event or entity looks: list row, card, detail, timeline entry, command form block_specs, one per type and variant You design the house style. Users can fork it into a lens.
Theme Colours, type, spacing UDG tokens You. Users can remap them within the contrast tests.

In practice this means:

  • One look everywhere. macOS, Flutter, the web client and the CLI all render the same view spec. Nobody hand-builds a wish screen again.
  • You don't design status rules. The API says which commands are available right now, so a view only decides how commands are presented.
  • People can change a lot, but not everything. A lens can rearrange, restyle or hide most of a view. Some blocks are sealed and can't be removed: consent gates, safety ceremonies, tier locks and the lineage proof line. You decide what's sealed (new issue below).
  • Runs already stream as blocks. The ratified StreamEvent contract (rituals-api-spec PR #6) sends block_start/block_delta/block_end plus status, tier, rubric-gate and error events. The run issue is about how those look, not a new contract.

The work, in order

Wishes are the pilot because they have the most event plumbing already. Parlays come next, then runs.

Views (per event/entity type)

  • #180 Wish views: list row, card, detail, timeline
  • #181 Wish commands: how available commands and their forms are presented
  • #183 Parlay and approval views
  • #185 Run views: how each StreamEvent type looks
  • #188 Run result with lineage seal

Shared building blocks the views use

  • #178 Slot form (now also how command inputs render)
  • #179 Slot-fill (ask only for what's missing)
  • #182 Confirm, four severity levels
  • #184 Disambiguation
  • #186 Code and file output
  • #187 Diff, then apply

Customisation

  • #189 Lens guardrails: what's sealed, and how far a lens can move from the house style

Decided (ville, 2026-10-05; closed 2026-10-13. Where this differs from #189, #189's final decision governs.)

Block types. code, diff and progress are new block types. confirm is a composition of existing blocks, and it must keep CEREMONY intent and critical importance where they apply, so a renderer sees a confirmation and not just a section, a toggle and actions.

Framework: Grammar / Voice / Personality.

  • Grammar is fixed: semantics, reading and focus order, accessibility floors, reduced motion, sealed requirements.
  • Voice is the house style: the default look of each intent and importance level.
  • Personality is the person's bounded visual preferences: Density, Corners, Motion and Atmosphere (lower only). It belongs to the person, stays the same across modes and views, and never breaks Grammar. The limits are in #189.
  • Modes are capability, access and trust states, not Personality presets. A mode owns the Accent and the Atmosphere baseline. A lens can't replace the Accent or raise Atmosphere above the baseline. Warning, error, consent, success and trust colours stay protected.
  • View customisation is block arrangement and visibility, per view type, within the sealed constraints.
  • Resets: Reset personality and Reset view (#189). There is no "Reset to mode defaults".
  • Sealed baseline: consent gates, safety ceremonies and overrides, tier locks, lineage proof, destructive-action confirmations. It is extensible.
  • Hero is an optional semantic slot. It is never the only place important information lives, and its decoration collapses in compact, high-contrast and reduced-motion renderings. Which views get one is decided in #180 and the other concrete view issues.
  • Modalities need semantic equivalence, not visual equivalence: every renderer keeps meaning, importance, action hierarchy and sealed requirements.

What every view spec should include

Block composition; the fields it binds to (from the event schema); empty, loading, error and locked states; a visible way out of every waiting state; a compact layout; the CLI rendering; and token names only, no raw values.

Engineering track (not for you, just linked)

Toilville/rituals-api-spec#15 · Toilville/ritual-engine#832 · Toilville/ritual-engine#834 · Toilville/ritual-engine#835 · Toilville/ritual-engine#836 · toilville/toilville_rituals#496 · Toilville/forge-api#8

Related: #93 (design canon scope). Audit page: https://claude.ai/artifact/C3ANoqoEbXSR1NaywjMfx9

**Revised 2026-10-04.** The first version of this issue asked for one design per screen. The direction has changed: you design how each **ritual event and entity** looks in the house style, the API serves those designs as data, and people can swap in their own version (a "lens") for the things they look at most, like wishes and parlays. ## How it fits together | Layer | What it is | Where it lives | Who owns it | |---|---|---|---| | **Events** | Facts like "wish created" or "status changed", already flowing through Kafka | Kafka topic schemas, published in the API spec | Engineering | | **Commands** | What someone can do next ("complete", "reopen", "approve"), each with its input fields | The wish state machine, served by the API as `available_commands` | Engineering | | **Views** | How an event or entity looks: list row, card, detail, timeline entry, command form | `block_specs`, one per type and variant | **You** design the house style. Users can fork it into a lens. | | **Theme** | Colours, type, spacing | UDG tokens | You. Users can remap them within the contrast tests. | In practice this means: - **One look everywhere.** macOS, Flutter, the web client and the CLI all render the same view spec. Nobody hand-builds a wish screen again. - **You don't design status rules.** The API says which commands are available right now, so a view only decides how commands are *presented*. - **People can change a lot, but not everything.** A lens can rearrange, restyle or hide most of a view. Some blocks are **sealed** and can't be removed: consent gates, safety ceremonies, tier locks and the lineage proof line. You decide what's sealed (new issue below). - **Runs already stream as blocks.** The ratified `StreamEvent` contract (rituals-api-spec PR #6) sends `block_start`/`block_delta`/`block_end` plus status, tier, rubric-gate and error events. The run issue is about how those look, not a new contract. ## The work, in order Wishes are the pilot because they have the most event plumbing already. Parlays come next, then runs. **Views (per event/entity type)** - [ ] #180 Wish views: list row, card, detail, timeline - [ ] #181 Wish commands: how available commands and their forms are presented - [ ] #183 Parlay and approval views - [ ] #185 Run views: how each `StreamEvent` type looks - [ ] #188 Run result with lineage seal **Shared building blocks the views use** - [ ] #178 Slot form (now also how command inputs render) - [ ] #179 Slot-fill (ask only for what's missing) - [ ] #182 Confirm, four severity levels - [ ] #184 Disambiguation - [ ] #186 Code and file output - [ ] #187 Diff, then apply **Customisation** - [x] #189 Lens guardrails: what's sealed, and how far a lens can move from the house style ## Decided ([ville, 2026-10-05](https://git.toilville.dev/Toilville/toilville-design/issues/177#issuecomment-26060); closed [2026-10-13](https://git.toilville.dev/Toilville/toilville-design/issues/177#issuecomment-30144). Where this differs from #189, [#189's final decision](https://git.toilville.dev/Toilville/toilville-design/issues/189#issuecomment-30142) governs.) **Block types.** `code`, `diff` and `progress` are new block types. `confirm` is a composition of existing blocks, and it must keep CEREMONY intent and critical importance where they apply, so a renderer sees a confirmation and not just a section, a toggle and actions. **Framework: Grammar / Voice / Personality.** - **Grammar** is fixed: semantics, reading and focus order, accessibility floors, reduced motion, sealed requirements. - **Voice** is the house style: the default look of each intent and importance level. - **Personality** is the person's bounded visual preferences: Density, Corners, Motion and Atmosphere (lower only). It belongs to the person, stays the same across modes and views, and never breaks Grammar. The limits are in #189. - **Modes** are capability, access and trust states, not Personality presets. A mode owns the Accent and the Atmosphere baseline. A lens can't replace the Accent or raise Atmosphere above the baseline. Warning, error, consent, success and trust colours stay protected. - **View customisation** is block arrangement and visibility, per view type, within the sealed constraints. - **Resets:** Reset personality and Reset view (#189). There is no "Reset to mode defaults". - **Sealed baseline:** consent gates, safety ceremonies and overrides, tier locks, lineage proof, destructive-action confirmations. It is extensible. - **Hero** is an optional semantic slot. It is never the only place important information lives, and its decoration collapses in compact, high-contrast and reduced-motion renderings. Which views get one is decided in #180 and the other concrete view issues. - **Modalities** need semantic equivalence, not visual equivalence: every renderer keeps meaning, importance, action hierarchy and sealed requirements. ## What every view spec should include Block composition; the fields it binds to (from the event schema); empty, loading, error and locked states; a visible way out of every waiting state; a compact layout; the CLI rendering; and token names only, no raw values. ## Engineering track (not for you, just linked) Toilville/rituals-api-spec#15 · Toilville/ritual-engine#832 · Toilville/ritual-engine#834 · Toilville/ritual-engine#835 · Toilville/ritual-engine#836 · toilville/toilville_rituals#496 · Toilville/forge-api#8 Related: #93 (design canon scope). Audit page: https://claude.ai/artifact/C3ANoqoEbXSR1NaywjMfx9
peterswimm changed title from Rituals: design the interaction pattern library the Forge will serve as ForgeBlocks to Rituals: house-style views over ritual events, with user lenses 2026-10-04 20:34:13 +00:00
Author
Owner

Reframed today. Instead of one design per screen, you'll design the house-style view for each ritual event/entity type (wishes first, then parlays, then runs), which the API serves and users can fork into a lens. #180, #181, #183 and #185 have new titles and bodies; #189 (lens guardrails) is new. The other pattern issues (#178, #179, #182, #184, #186, #187, #188) are unchanged and now act as shared building blocks for the views.

Reframed today. Instead of one design per screen, you'll design the house-style **view** for each ritual event/entity type (wishes first, then parlays, then runs), which the API serves and users can fork into a **lens**. #180, #181, #183 and #185 have new titles and bodies; #189 (lens guardrails) is new. The other pattern issues (#178, #179, #182, #184, #186, #187, #188) are unchanged and now act as shared building blocks for the views.
Author
Owner

Hey @ville 👋 Following up on the reframe above. Before you get into the individual wish and parlay views, I'd love your thinking on the framework underneath them. Once views come from the API and people can fork them into lenses, the UDG stops being a set of tokens we apply by hand. It becomes the rules for what a view is allowed to do. I want those rules to leave room for personality, heroes and new modalities without giving up accessibility.

What we already have to build on

  • Tokens: 14 families, including duration and easing. Motion already drops to zero when the OS asks for reduced motion.
  • Semantics: blocks carry a semantic intent (MEDIA_HERO, CEREMONY, ACTION_PRIMARY, STATUS_INDICATOR…) and an importance level (critical, high, normal, low). Renderers barely use either today.
  • Layout and atmosphere: your 6 ratified shapes, the breakpoint bands and the compact density flag; per-mode accents (Observatory → Federation); a parameterised ambient shader layer in Flutter.
  • Accessibility tests: WCAG contrast tests in both themes for every token pair.

A starting idea to push back on: three layers of expression

  1. Grammar (fixed, nobody overrides it). Semantic intent, reading order, focus order, contrast floors, minimum text and target sizes, reduced-motion behaviour, and the sealed blocks: consent, safety, tier locks, lineage proof. This is the part that keeps every view accessible no matter who styled it.
  2. Voice (the house style, yours). How each intent and importance level looks by default: type pairing, colour roles, spacing rhythm, motion character, and how a CEREMONY feels compared with a STATUS_INDICATOR. This is what makes something read as Toilville on every surface.
  3. Personality (dials, where lenses live). A small, named set of controls a person or a mode can turn within limits you set. For example: accent hue, density, corner softness, motion energy (still → lively), atmosphere (plain → ambient shader), and hero treatment. Each dial is clamped so it can't break the grammar.

If the dials are named and bounded, we get "just enough personality". A lens can feel very different without anyone writing raw colours or hiding a consent gate.

Heroes
I'd like heroes to be a real slot in the shapes, not a one-off. MEDIA_HERO exists as an intent, but nothing defines what a hero is for. Some uses: a wish's "why", a ritual's identity at the top of a run, a parlay's decision at stake, a mode's atmosphere. Questions:

  • Which shapes get an optional hero slot, and how does it collapse at compact widths and in the CLI?
  • Is a hero image or shader, or can it be typographic or data-driven (the wish title plus its one key fact)?
  • How does a hero behave under reduced motion, high contrast and a screen reader? It should never be the only place information lives.

Modalities
Every view should degrade well across visual, compact, keyboard-only, screen reader, voice (the Swift side already has voice and spatial renderers registered but unused) and the plain-text CLI. Using semantic intent and importance as the contract, with visuals as one way to render it, seems like the lever. A CEREMONY should feel equally deliberate as a sheet, a spoken confirmation or a terminal prompt.

What I'm hoping you'll weigh in on

  1. Does grammar / voice / personality match how you think about the system, or is there a better split?
  2. Which personality dials would you allow, and where would you clamp each one?
  3. Should the mode accents become presets of those dials, so Workshop feels different from Sanctum by more than colour?
  4. Hero: slot rules, and the accessible fallback.
  5. Anything you'd add to the sealed list in #189.

None of this blocks the wish views. A rough sketch or a few notes here or on #189 would be plenty to steer the engineering.

Hey @ville 👋 Following up on the reframe above. Before you get into the individual wish and parlay views, I'd love your thinking on the **framework underneath them**. Once views come from the API and people can fork them into lenses, the UDG stops being a set of tokens we apply by hand. It becomes the rules for what a view is allowed to do. I want those rules to leave room for personality, heroes and new modalities without giving up accessibility. **What we already have to build on** - **Tokens**: 14 families, including duration and easing. Motion already drops to zero when the OS asks for reduced motion. - **Semantics**: blocks carry a *semantic intent* (`MEDIA_HERO`, `CEREMONY`, `ACTION_PRIMARY`, `STATUS_INDICATOR`…) and an *importance* level (critical, high, normal, low). Renderers barely use either today. - **Layout and atmosphere**: your 6 ratified shapes, the breakpoint bands and the `compact` density flag; per-mode accents (Observatory → Federation); a parameterised ambient shader layer in Flutter. - **Accessibility tests**: WCAG contrast tests in both themes for every token pair. **A starting idea to push back on: three layers of expression** 1. **Grammar (fixed, nobody overrides it).** Semantic intent, reading order, focus order, contrast floors, minimum text and target sizes, reduced-motion behaviour, and the sealed blocks: consent, safety, tier locks, lineage proof. This is the part that keeps every view accessible no matter who styled it. 2. **Voice (the house style, yours).** How each intent and importance level *looks* by default: type pairing, colour roles, spacing rhythm, motion character, and how a `CEREMONY` feels compared with a `STATUS_INDICATOR`. This is what makes something read as Toilville on every surface. 3. **Personality (dials, where lenses live).** A small, named set of controls a person or a mode can turn within limits you set. For example: accent hue, density, corner softness, motion energy (still → lively), atmosphere (plain → ambient shader), and hero treatment. Each dial is clamped so it can't break the grammar. If the dials are named and bounded, we get "just enough personality". A lens can feel very different without anyone writing raw colours or hiding a consent gate. **Heroes** I'd like heroes to be a real slot in the shapes, not a one-off. `MEDIA_HERO` exists as an intent, but nothing defines what a hero is *for*. Some uses: a wish's "why", a ritual's identity at the top of a run, a parlay's decision at stake, a mode's atmosphere. Questions: - Which shapes get an optional hero slot, and how does it collapse at compact widths and in the CLI? - Is a hero image or shader, or can it be typographic or data-driven (the wish title plus its one key fact)? - How does a hero behave under reduced motion, high contrast and a screen reader? It should never be the only place information lives. **Modalities** Every view should degrade well across visual, compact, keyboard-only, screen reader, voice (the Swift side already has voice and spatial renderers registered but unused) and the plain-text CLI. Using semantic intent and importance as the *contract*, with visuals as one way to render it, seems like the lever. A `CEREMONY` should feel equally deliberate as a sheet, a spoken confirmation or a terminal prompt. **What I'm hoping you'll weigh in on** 1. Does grammar / voice / personality match how you think about the system, or is there a better split? 2. Which personality dials would you allow, and where would you clamp each one? 3. Should the mode accents become *presets* of those dials, so Workshop feels different from Sanctum by more than colour? 4. Hero: slot rules, and the accessible fallback. 5. Anything you'd add to the sealed list in #189. None of this blocks the wish views. A rough sketch or a few notes here or on #189 would be plenty to steer the engineering.
Member

Framework: agreed on Grammar / Voice / Personality.

  • Grammar is fixed: semantics, reading and focus order, accessibility floors, reduced motion, sealed requirements.
  • Voice is the Toilville house style: the default look of each intent and importance level.
  • Personality is bounded variation for modes and lenses. It never breaks Grammar.

Personality controls (initial set):

  • Accent: validated palette only, no free hue. Warning, error and consent colours keep their meaning.
  • Density: bounded compact to spacious. Minimum text and target sizes still apply.
  • Corner softness: bounded sharp to soft.
  • Motion energy: bounded still to expressive. OS reduced motion always wins.
  • Atmosphere: bounded plain to ambient. Keep it limited at first. It must not harm readability.
  • Hero is not a control for now. It inherits accent, density, motion and atmosphere.

Modes: each mode is a designed Personality preset (accent, density, corners, motion, atmosphere), not an accent colour only. Do not infer a mode's personality from its current accent. A lens adjusts the preset within Grammar. Two resets: to the mode defaults, and to the house style.

Hero: an optional semantic slot, used only where a view has something that deserves primary emphasis. It can be typographic, visual, ambient or data-driven. It is never the only place for important information. Decoration collapses in compact, high-contrast and reduced-motion renderings. CLI, voice and screen reader keep the meaning. Which of the six shapes get a hero slot is open until I review the shapes.

Sealed (#189): the proposed baseline stands (consent gates, safety ceremonies and overrides, tier locks, lineage proof, destructive-action confirmations). It is extensible. If the Wish, Parlay or Run work shows another element a lens must not hide or weaken, add it.

Modalities: semantic equivalence, not visual equivalence. Every renderer keeps meaning, importance, action hierarchy and sealed requirements. A CEREMONY stays deliberate and consequential as a spoken prompt or a terminal prompt.

Block types: code, diff and progress are new block types. confirm is a composition of existing blocks. It must keep CEREMONY intent and critical importance where they apply, so a renderer sees a confirmation and not only a section, a toggle and actions.

Framework: agreed on Grammar / Voice / Personality. - Grammar is fixed: semantics, reading and focus order, accessibility floors, reduced motion, sealed requirements. - Voice is the Toilville house style: the default look of each intent and importance level. - Personality is bounded variation for modes and lenses. It never breaks Grammar. Personality controls (initial set): - Accent: validated palette only, no free hue. Warning, error and consent colours keep their meaning. - Density: bounded compact to spacious. Minimum text and target sizes still apply. - Corner softness: bounded sharp to soft. - Motion energy: bounded still to expressive. OS reduced motion always wins. - Atmosphere: bounded plain to ambient. Keep it limited at first. It must not harm readability. - Hero is not a control for now. It inherits accent, density, motion and atmosphere. Modes: each mode is a designed Personality preset (accent, density, corners, motion, atmosphere), not an accent colour only. Do not infer a mode's personality from its current accent. A lens adjusts the preset within Grammar. Two resets: to the mode defaults, and to the house style. Hero: an optional semantic slot, used only where a view has something that deserves primary emphasis. It can be typographic, visual, ambient or data-driven. It is never the only place for important information. Decoration collapses in compact, high-contrast and reduced-motion renderings. CLI, voice and screen reader keep the meaning. Which of the six shapes get a hero slot is open until I review the shapes. Sealed (#189): the proposed baseline stands (consent gates, safety ceremonies and overrides, tier locks, lineage proof, destructive-action confirmations). It is extensible. If the Wish, Parlay or Run work shows another element a lens must not hide or weaken, add it. Modalities: semantic equivalence, not visual equivalence. Every renderer keeps meaning, importance, action hierarchy and sealed requirements. A CEREMONY stays deliberate and consequential as a spoken prompt or a terminal prompt. Block types: `code`, `diff` and `progress` are new block types. `confirm` is a composition of existing blocks. It must keep CEREMONY intent and critical importance where they apply, so a renderer sees a confirmation and not only a section, a toggle and actions.
Member

The framework decisions are complete. Closing this umbrella.

  • Decided here: the Grammar / Voice / Personality framework, the sealed baseline, "semantic equivalence, not visual equivalence" for modalities, the block types (code, diff and progress are new; confirm is a composition), and the hero principle.
  • Correction: the "Decided" text and my earlier comment here say that modes are Personality presets, that accent and atmosphere are lens controls, and that the two resets are to the mode defaults and the house style. #189 replaces that. A mode is a capability and access state that owns Accent and the Atmosphere baseline. Lens Personality is Density, Corners, Motion and Atmosphere (lower only). The final limits, resets and editing flow are in #189. Where they differ, #189 governs.
  • Hero: the principle stands. It is an optional slot, never the only place for important information, and its decoration collapses in compact, high-contrast and reduced-motion renderings. Which views get a hero slot is decided in #180 and the other concrete view issues, not here.
  • The child issues #178 to #188 stay open. They are the view and pattern specs. They do not block this umbrella.

@peterswimm please update the "Decided" section to match.

The framework decisions are complete. Closing this umbrella. - Decided here: the Grammar / Voice / Personality framework, the sealed baseline, "semantic equivalence, not visual equivalence" for modalities, the block types (`code`, `diff` and `progress` are new; `confirm` is a composition), and the hero principle. - Correction: the "Decided" text and my earlier comment here say that modes are Personality presets, that accent and atmosphere are lens controls, and that the two resets are to the mode defaults and the house style. #189 replaces that. A mode is a capability and access state that owns Accent and the Atmosphere baseline. Lens Personality is Density, Corners, Motion and Atmosphere (lower only). The final limits, resets and editing flow are in #189. Where they differ, #189 governs. - Hero: the principle stands. It is an optional slot, never the only place for important information, and its decoration collapses in compact, high-contrast and reduced-motion renderings. Which views get a hero slot is decided in #180 and the other concrete view issues, not here. - The child issues #178 to #188 stay open. They are the view and pattern specs. They do not block this umbrella. @peterswimm please update the "Decided" section to match.
Author
Owner

Updated the "Decided" section to match your closing comment: modes are access states that own Accent and the Atmosphere baseline, the lens Personality is Density, Corners, Motion and Atmosphere (lower only), the two resets are Reset personality and Reset view, and #189 governs where the two differ. Closing as you said. The engineering follow-up is toilville/toilville_rituals#542.

Updated the "Decided" section to match your closing comment: modes are access states that own Accent and the Atmosphere baseline, the lens Personality is Density, Corners, Motion and Atmosphere (lower only), the two resets are Reset personality and Reset view, and #189 governs where the two differ. Closing as you said. The engineering follow-up is toilville/toilville_rituals#542.
Sign in to join this conversation.
No description provided.