Household portrait — design spec
The founder's words (verbatim, iMessage 09:15): "a scribble drawing of a stick figure home. The home has the household name across the top, like 'the Wilson's' and then you have a stick figure family each with a name over them 'Ben', 'mimonga' etc. You can pick between different stick figure drawings for adult man, adult female, grandparent, child male, child female (maybe small medium large size for the kids) and then each one could have their choice of color."
![[2026-09-05-household-portrait-founder-sketch.jpg]]
The sketch sets the register: one marker-weight line, a house with roof, window and door, stick figures. Product-facing additions are marked Ray proposal; render defaults are the design lane's.
1. Figure set
- Founder's five kinds: adult man, adult woman, grandparent, boy, girl (six if decision 5 is kept) →
figure_kind(§3). - Kid sizes S/M/L are the founder's "maybe": optional. Ray proposal: if kept, size derives from the birth date:
bandForChild(birth_date, today)(curate.js L113-119) → 3_4 = S, 5_6 = M, 7_8 and 9_10 = L. Ray proposal for a null band (under 30 months perMIN_MONTHSL24, or over 10): under 30 months draws S and over 10 draws L, so a figure never vanishes for lack of a band. - Ray proposal: a second grandparent presentation (grandmother beside grandfather).
- Hand: [[DESIGN-scribble-works]] §Wordmark's "crayon-imperfect look" (a type rule) extended to illustration under §Ray's print constraint ("line-art, ink-light"): the Wordmark.astro L4 SVG feTurbulence alpha-erosion, one filter shared by house and figures. One stroke weight, no shading, no fill but the color patch (§2).
- Rule for THIS dispatch only (the contract does not require it): code-drawn inline SVG; no raster, no generated art. Photos are already out ([[2026-09-02-members-area-spec]] L55); DESIGN checklist #7 and §Photography ban photorealistic AI children and allow illustrated ones.
- Names over heads:
children.display_name(0005 L119) in--font-scribble(Base.astro L90). Adults: §3.
2. Color
- Rule satisfied: DESIGN §Color (sampled from the Ray mascot, warm paper ground) and checklist #5. The contract names no tokens; these are the site's existing sampled set (Base.astro
:rootL58-97), so a figure can never introduce a color. - A figure may use the five sampled swatches:
--ray-yellow,--ray-red,--ray-pink,--ray-sky,--ray-navy(L64-71). Line is always--ray-ink(L63). Ground:--sheetinside the house on--paper(L73-76). Not offered: the derived text and call-to-action (CTA) tokens (--ray-red-deep,--ray-blue,--ray-maroon) and the--wash-*tints. - What color paints: one patch per figure, the torso, so five colors read as five people.
- Default: by join order, cycling yellow → sky → pink → red → navy.
- Picking: a five-dot swatch row (§5). Stored as the token name, so a palette retune in Base.astro retunes every portrait.
3. Data
- No ALTER TABLE in this repo (0005 L16-19: forward-only, CREATE IF NOT EXISTS only), so nothing is added to
adultsorchildren. This spec OWNS three side tables in a new numbered migration, all CREATE IF NOT EXISTS:member_portraits(member_table CHECK IN ('adults','children'), member_id, figure_kind, color), composite primary key;adult_profiles(adult_id PRIMARY KEY, display_name);household_profiles(household_id PRIMARY KEY, display_name). CHECKs: the five kinds (six if decision 5 is kept), the five token names. No row = defaults: the §2 color cycle and a neutral ungendered figure until the member picks. - Schema facts:
adultshas no name column (0005 L47-59; the Adults row shows a masked email, account.astro L221).householdshas no display_name (0003 L33-40) and r5 adds none; household-name storage lives here. - Ray proposal, name source: "The Wilsons" cannot be derived, since no lead name is stored anywhere. Propose an entered household name (
household_profiles.display_name, default "Our house") and an entered adult first name (adult_profiles.display_name, 1-40 like children's, default the role word "Lead" / "Adult"). The email's local part is never used; it leaks the address. No last name is ever asked for; a child never has one (0005 L106, account.astro L134). - Kid size is not stored: derived from
children.birth_date(0005 L120).
4. Layout
390w (one column) 1280w (portrait spans the cards)
┌────────────────────────────┐ ┌──────────────────────────────────────────────┐
│ the Wilsons │ roof │ the Wilsons │
│ /‾‾‾‾‾‾‾‾‾‾‾‾\ │ │ /‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\ │
│ / [ ] \ │ │ / [ ] \ │
│ | Ben mimonga | │ adults │ | Ben mimonga Nana Mae Leo Io | │
│ | o o | │ │ | o o o o o o | │
│ | /|\ /|\ | │ │ | /|\ /|\ /|\ /|\ /|\ /|\ | │
│ | / \ / \ Mae| │ kids │ | / \ / \ / \ / \ / \ / \ | │
│ | o | │ by size │ |________________________________| │
│ | /|\ | │ │ [ pick figure · color ] │
│ |__[door]_____/ \_| │ └──────────────────────────────────────────────┘
└────────────────────────────┘
- House frame: the sketch's house (roof, window, door) as one crayon-filtered SVG path on a
frame-papercard like the Kids and Adults cards (account.astro L119, L199): DESIGN §The frame motif. - Name lettering: across the roof line, centered,
--font-scribble, one line, ellipsis past 24 characters. - Arrangement: adults first by join order, then kids L → M → S, then null-band kids by age, all on the floor line. Each figure owns a fixed slot (adult 64px, L 56, M 48, S 40 at 390w; 1.5× at 1280w) so names never overlap; slots wrap to a second row inside the house and the roof does not grow.
- 390w: house fills the card, at most two rows. 1280w: one row holds 3 adults + 8 kids, picker under the house.
- One-person household: the signed-in adult, centered, roof "Our house", Ray's bubble (checklist #4, guide not hero): "Add the people I'm making these for."
- Eight kids (cap, 0005 L113 D8): 11 slots, two rows at 390w, one at 1280w; a tested state.
5. Interactions
- Pick figure + color, inline on the member's row: the Kids and Adults rows (account.astro L136-159, L218-247) gain a figure thumbnail; tapping opens the picker under that row (the
data-kid-editorpattern): figure tiles, the five-dot swatch row, Done. The portrait redraws live. No modal. - Who may edit: an adult edits only their own figure and color; any active adult edits any kid's (household-owned, 0005 L103). Ray proposal: only a lead renames the household. Enforced on the PATCH as well as in the UI.
- Switcher, founder-confirmed 09:31 (the house IS the switcher, the NAME is the dropdown): when r5's
GET /api/account/householdsreturns more than one membership, the roof name becomes a dropdown of household names with role badges; picking one callsPOST /api/account/households/[id]/switchand the portrait redraws with that household's people. Rows readhousehold_profiles.display_name; an unnamed one reads "Our house ·" (masked as account.astro L221 does), so unnamed households stay distinguishable. - Ray proposal, a row of houses: with more than one membership, small houses stand above the portrait, current one highlighted (
--wash-goldground, others--kraft); tapping a house switches too. This REPLACES r5's "Your households" card; r5's endpoints stay the data source. If declined, the dropdown alone satisfies 09:31.
6. Playset tie-in
- Ray proposal: the kid's figure, in their color, top-right of the title page's parent strip (page 1 of the packaged PDF, r1 daily-playset-v2), 0.9in tall, name beneath in the bundled scribble font, inside the existing margin. Ink-light by construction (checklist #8, §Ray's print constraint); not a Ray mark (2026-09-02 amendment: the B2 wordmark stays in the footer).
- Print gate unchanged (one page, Letter, bundled fonts; checklist #6).
Mockups (rough, code-drawn SVG, not pixel-final)
Rendered from the §1-§5 rules (real palette tokens, real crayon-erosion filter technique) as a standalone HTML mockup, screenshotted at the two target widths. Evidence: ~/.claude/state/studio/round-2026-09-06-evidence/household-portrait/ (mockup.html + three PNGs).
- A — 390w, populated (6 members, 2-row wrap):
mockup-A-390-populated.png. Shows adults-then-kids-by-size ordering, fixed-size slots, names above heads, one color patch per torso, roof does not grow when the floor wraps. - B — 1280w, same household, one row:
mockup-B-1280-desktop.png. Same data, single row per §4's "1280w: one row holds 3 adults + 8 kids." - C — 390w, empty state + switcher:
mockup-C-390-empty-switcher.png. One-adult household ("Our house," dropdown chevron on the name per founder 09:31), Ray's bubble, and the row-of-houses switcher (§5 Ray proposal) with the active house highlighted in--wash-gold.
Known rough edges (not fixed for a spec-stage mockup): grandparent's cane and one figure's arm crowd the door in the A/B crowded rows — a real build tunes per-slot X offsets project-side; this mockup is for register/token/layout-shape review, not final spacing.
Design-critic gate (charter §2 QA gate map, site-page row): PASS, 2nd pass, 2026-09-06. 1st pass returned ITERATE on one blocking-ish finding (mockup B: member names overlapped the roofline window, hurting the "Osmo-adjacent product clarity" register) plus a minor ask to confirm names render in --font-scribble not a fallback. Fixed by moving the window higher on the roofline in the mockup markup; re-check confirmed the overlap is gone at both 390w and 1280w, nothing else regressed, and the scribble/handwritten lettering reads as distinct from body type at both breakpoints. All other checklist items (register, palette-token traceability, ink-light line weight, no-photorealism, bubble copy, roof-doesn't-grow-on-wrap) passed on the 1st look and were not re-litigated. 2 of 3 max critic iterations used.
7. Dependencies + gates
- Needs r5: only the two endpoints (
GET /api/account/households,POST /api/account/households/[id]/switch) for §5; without them, one house and no dropdown. - Needs r1 merged before §6, and the §3 tables in the next numbered migration, applied to no remote DB by the builder.
- Gates (charter §2 quality-assurance (QA) gate map): rendered portrait on /account →
design-critic(site-page row, build-landing-page four-layer); picker and switch →behavior-critic, source-blind, pre-written contract, on a preview; title-page figure →verify-pdf-output; this note →verify-vault-write. - Returning-visitor clause (charter §2 design row): satisfied by founder origin, 09:15. Extra (a) is founder-confirmed 09:31; extra (b) is not. No PR sequencing here; product dequeues.
Open decisions
- Name source: enter a household name (
household_profiles.display_name, default "Our house") rather than derive "The Wilsons" from a last name nobody stores. Ray proposal. - Adult name field:
adult_profiles.display_name(first name, 1-40, nullable, default role word). Ray proposal. - Null-band size rule: under 30 months draws S, over 10 draws L. Ray proposal. Alternative: one kid size until S/M/L is decided.
- S/M/L at all, and derived rather than picked: the founder's "maybe"; derivation from the birth date is a Ray proposal. Keep, or one size?
- Second grandparent presentation. Ray proposal.
- Ray extra (a), portrait as switcher: founder-confirmed 09:31 (house = switcher, name = dropdown). Still open: the row of small houses replacing r5's "Your households" card. Ray proposal.
- Ray extra (b), kid figure on the playset title page: unobjected, not approved; changes the returning visitor's printed page. Ray proposal.
- Household kinds: the founder mentioned "schoolhouses once we get there" (09:31 iMessage); Ray's reading: classrooms as a possible future household kind. Noted only.