From 972ac6374fea72b45b5bfee6bd619302fb728401 Mon Sep 17 00:00:00 2001 From: testtest126 <44771568+testtest126@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:43:25 +0200 Subject: [PATCH 1/5] Add design moodboard reference (docs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-facing style reference for MateMate, mirroring the one in LULL. Palette is sampled from the actual code (AccentColor/WarmBackground colorsets, BoardTheme.swift, docs/index.html :root) rather than assumed — the app's gold/ochre accent and the public site's green accent are genuinely different tokens, not a copy error, and are called out explicitly so nobody merges them into one guess. Co-Authored-By: Claude Sonnet 5 --- docs/design/moodboard/MOODBOARD.md | 109 +++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 docs/design/moodboard/MOODBOARD.md diff --git a/docs/design/moodboard/MOODBOARD.md b/docs/design/moodboard/MOODBOARD.md new file mode 100644 index 0000000..4da8d09 --- /dev/null +++ b/docs/design/moodboard/MOODBOARD.md @@ -0,0 +1,109 @@ +# MateMate — Moodboard + +*Agent-facing style reference. Skim, don't read straight through. Code is the +source of truth — this doc points at it rather than restating it, so it can't +drift out of sync.* + +## Palette + +**Source of truth is code, not this doc — and the app and the public site +use two genuinely different accent hues. This is not a copy error; verify +here before assuming one.** + +| token | in-app (`Assets.xcassets`) | public site (`docs/index.html` `:root`) | +|---|---|---| +| background | `WarmBackground` → `#F6EFE2` light / `#171109` dark | `--bg` → `#F3F4EE` light / `#0F1512` dark | +| text / ink | *(none — system `.primary`/label color, not a custom token)* | `--ink` → `#1C231F` light / `#E8EBE3` dark | +| primary accent | `AccentColor` → `#8A6216` light / `#E7BA5C` dark (**gold/ochre**) | `--accent` → `#2C6E52` light / `#82CBA6` dark (**green**) | +| secondary/soft | — | `--buff` → `#E7D3A4` light / `#D9C186` dark (this is the site's gold) | + +**If you were handed "mustard/ochre-gold primary, ink-black wordmark" for +this project** — that's accurate for the **app**, confirmed against +`AccentColor.colorset` and `screenshot-home.png` (gold capsule buttons, true +near-black bold wordmark rendered via the default SwiftUI `.navigationTitle`, +no custom "ink" color asset exists). It is **not** accurate for the +**public docs site** — its primary accent is a deep green (`--accent: +#2C6E52`), with the gold/buff tone demoted to a secondary token. Flag this +distinction rather than picking one and assuming it covers both surfaces. + +### Board-theme swatches + +Four presets, `BoardTheme.swift`, `UserDefaults` key `board_theme`: + +| theme | light square | dark square | +|---|---|---| +| Classic | `#F0D9B5` | `#B58763` | +| Green | `#EDEDD1` | `#759657` | +| Blue | `#DEE6ED` | `#6B8CAD` | +| Gray | `#E0E0E0` | `#8C8C91` | + +(Coordinate-label colors are separately tuned per theme for WCAG AA 4.5:1 — +see `coordinateColor(onLight:)` in the same file; don't reuse the swatch +colors above for text.) + +## Typography & voice + +- **Wordmark** — "MateMate", bold sans, large — but it's the **native** + SwiftUI `.navigationTitle` (`HomeView.swift`, `GameView.swift`), not a + custom logotype or graphic. Don't design a bespoke wordmark treatment; + the system font *is* the brand here. +- **Controls** — native iOS SF-style throughout: system `Picker`, + `SegmentedPickerStyle`-driven segmented controls, native + `SignInWithAppleButton` (renders its own black pill — don't restyle it). +- **Microcopy** — short, plain, confident: "Play Online", "Start Game", + "Recovers your account if you've played before." No exclamation points, + no cuteness, no jargon. + +## UI fragments + +Grounded in `docs/screenshots/screenshot-home.png` and `HomeView.swift`: + +- **Segmented pickers** — "Time control" (Bullet / Blitz / Rapid) and + "Play as" (White / Black / Random), via a shared `AdaptiveSegmentedPicker`. +- **Gold pill primary buttons** — "Play Online", "Start Game": full-capsule, + filled with `AccentColor` (the gold/ochre token above), white label. +- **Black Sign-in-with-Apple pill** — the stock Apple component, unmodified. +- **Board-theme swatches** — four small rounded squares (Classic/Green/ + Blue/Gray) in the Appearance section, selected value shown in gold. +- **Trophy icon** — SF Symbol `"trophy"` (`LeaderboardView.swift`), shown top + trailing in a circular cream badge on Home. + +## Tone words + +classical · warm · clean · native · approachable · tournament-serious-but-friendly + +## Do / Don't + +| DO | DON'T | +|---|---| +| Warm neutrals (cream/parchment) as the base | Dark-mode-first design | +| Exactly one gold/ochre accent, in-app | Neon or saturated color outside the board themes | +| Native iOS patterns (`Picker`, system buttons, `SignInWithAppleButton`) | Heavy custom chrome that fights the system look | +| Multi-theme boards as the one place color plays | A second competing accent hue | + +## Reference screenshots + +Referenced (not duplicated) from `docs/screenshots/` and `docs/`: + +- [`screenshot-home.png`](../../screenshots/screenshot-home.png) — Home: + wordmark, both picker groups, gold pills, Sign in with Apple, board-theme + swatches. The single best reference for this whole doc. +- [`screenshot-game.png`](../../screenshots/screenshot-game.png) — an + in-progress board. +- [`screenshot-review.png`](../../screenshots/screenshot-review.png) — + post-game review. +- [`app-icon.png`](../../app-icon.png) — the app icon. + +## A note on "themes," two unrelated meanings + +Don't conflate these — same word, two different systems: + +- **In-app board themes** (what this doc covers): Classic / Green / Blue / + Gray, `BoardTheme.swift`, applies to the chessboard only. +- **The-fleet page skins** (`docs/the-fleet/`, a documentation-site feature, + unrelated to the app's design system): **six** named cultural themes — + `arabic`, `japanese`, `indian`, `codex`, `andalus`, `terminal` — set via + `data-theme` on the page root. If you were told only four (arabic/indian/ + andalus/terminal), that's incomplete; `japanese` and `codex` also exist. + These style the making-of documentation pages, not MateMate itself, and + have their own independent palettes per theme — not covered here. From c54d88b6eb771985241c0d6124324ec40b26bf0c Mon Sep 17 00:00:00 2001 From: testtest126 <44771568+testtest126@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:02:53 +0200 Subject: [PATCH 2/5] Replace with canonical moodboard content (chess + LULL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes the from-descriptions draft with the design tool's authoritative, code-grounded version — sampled directly from AccentColor.colorset, BoardTheme.swift, Styling.swift, BoardView.swift, and MoveAnnouncer.swift — and extends the doc to cover LULL in the same file, per the canonical source shared for both repos. Co-Authored-By: Claude Sonnet 5 --- docs/design/moodboard/MOODBOARD.md | 201 +++++++++++++---------------- 1 file changed, 92 insertions(+), 109 deletions(-) diff --git a/docs/design/moodboard/MOODBOARD.md b/docs/design/moodboard/MOODBOARD.md index 4da8d09..ffaf792 100644 --- a/docs/design/moodboard/MOODBOARD.md +++ b/docs/design/moodboard/MOODBOARD.md @@ -1,109 +1,92 @@ -# MateMate — Moodboard - -*Agent-facing style reference. Skim, don't read straight through. Code is the -source of truth — this doc points at it rather than restating it, so it can't -drift out of sync.* - -## Palette - -**Source of truth is code, not this doc — and the app and the public site -use two genuinely different accent hues. This is not a copy error; verify -here before assuming one.** - -| token | in-app (`Assets.xcassets`) | public site (`docs/index.html` `:root`) | -|---|---|---| -| background | `WarmBackground` → `#F6EFE2` light / `#171109` dark | `--bg` → `#F3F4EE` light / `#0F1512` dark | -| text / ink | *(none — system `.primary`/label color, not a custom token)* | `--ink` → `#1C231F` light / `#E8EBE3` dark | -| primary accent | `AccentColor` → `#8A6216` light / `#E7BA5C` dark (**gold/ochre**) | `--accent` → `#2C6E52` light / `#82CBA6` dark (**green**) | -| secondary/soft | — | `--buff` → `#E7D3A4` light / `#D9C186` dark (this is the site's gold) | - -**If you were handed "mustard/ochre-gold primary, ink-black wordmark" for -this project** — that's accurate for the **app**, confirmed against -`AccentColor.colorset` and `screenshot-home.png` (gold capsule buttons, true -near-black bold wordmark rendered via the default SwiftUI `.navigationTitle`, -no custom "ink" color asset exists). It is **not** accurate for the -**public docs site** — its primary accent is a deep green (`--accent: -#2C6E52`), with the gold/buff tone demoted to a secondary token. Flag this -distinction rather than picking one and assuming it covers both surfaces. - -### Board-theme swatches - -Four presets, `BoardTheme.swift`, `UserDefaults` key `board_theme`: - -| theme | light square | dark square | -|---|---|---| -| Classic | `#F0D9B5` | `#B58763` | -| Green | `#EDEDD1` | `#759657` | -| Blue | `#DEE6ED` | `#6B8CAD` | -| Gray | `#E0E0E0` | `#8C8C91` | - -(Coordinate-label colors are separately tuned per theme for WCAG AA 4.5:1 — -see `coordinateColor(onLight:)` in the same file; don't reuse the swatch -colors above for text.) - -## Typography & voice - -- **Wordmark** — "MateMate", bold sans, large — but it's the **native** - SwiftUI `.navigationTitle` (`HomeView.swift`, `GameView.swift`), not a - custom logotype or graphic. Don't design a bespoke wordmark treatment; - the system font *is* the brand here. -- **Controls** — native iOS SF-style throughout: system `Picker`, - `SegmentedPickerStyle`-driven segmented controls, native - `SignInWithAppleButton` (renders its own black pill — don't restyle it). -- **Microcopy** — short, plain, confident: "Play Online", "Start Game", - "Recovers your account if you've played before." No exclamation points, - no cuteness, no jargon. - -## UI fragments - -Grounded in `docs/screenshots/screenshot-home.png` and `HomeView.swift`: - -- **Segmented pickers** — "Time control" (Bullet / Blitz / Rapid) and - "Play as" (White / Black / Random), via a shared `AdaptiveSegmentedPicker`. -- **Gold pill primary buttons** — "Play Online", "Start Game": full-capsule, - filled with `AccentColor` (the gold/ochre token above), white label. -- **Black Sign-in-with-Apple pill** — the stock Apple component, unmodified. -- **Board-theme swatches** — four small rounded squares (Classic/Green/ - Blue/Gray) in the Appearance section, selected value shown in gold. -- **Trophy icon** — SF Symbol `"trophy"` (`LeaderboardView.swift`), shown top - trailing in a circular cream badge on Home. - -## Tone words - -classical · warm · clean · native · approachable · tournament-serious-but-friendly - -## Do / Don't - -| DO | DON'T | -|---|---| -| Warm neutrals (cream/parchment) as the base | Dark-mode-first design | -| Exactly one gold/ochre accent, in-app | Neon or saturated color outside the board themes | -| Native iOS patterns (`Picker`, system buttons, `SignInWithAppleButton`) | Heavy custom chrome that fights the system look | -| Multi-theme boards as the one place color plays | A second competing accent hue | - -## Reference screenshots - -Referenced (not duplicated) from `docs/screenshots/` and `docs/`: - -- [`screenshot-home.png`](../../screenshots/screenshot-home.png) — Home: - wordmark, both picker groups, gold pills, Sign in with Apple, board-theme - swatches. The single best reference for this whole doc. -- [`screenshot-game.png`](../../screenshots/screenshot-game.png) — an - in-progress board. -- [`screenshot-review.png`](../../screenshots/screenshot-review.png) — - post-game review. -- [`app-icon.png`](../../app-icon.png) — the app icon. - -## A note on "themes," two unrelated meanings - -Don't conflate these — same word, two different systems: - -- **In-app board themes** (what this doc covers): Classic / Green / Blue / - Gray, `BoardTheme.swift`, applies to the chessboard only. -- **The-fleet page skins** (`docs/the-fleet/`, a documentation-site feature, - unrelated to the app's design system): **six** named cultural themes — - `arabic`, `japanese`, `indian`, `codex`, `andalus`, `terminal` — set via - `data-theme` on the page root. If you were told only four (arabic/indian/ - andalus/terminal), that's incomplete; `japanese` and `codex` also exist. - These style the making-of documentation pages, not MateMate itself, and - have their own independent palettes per theme — not covered here. +# Moodboards — chess (MateMate) & LULL + +Style reference for agents working in these repos. Two games, one maker, opposite moods — never blend them. +Visual boards: `chess-moodboard.html` / `lull-moodboard.html` (self-contained, open in any browser). + +--- + +## 01 · MateMate (github.com/testtest126/chess) + +**Mood:** warm · classical · native-first iOS · quiet craft · one real board, always. +Feels like it shipped with iOS, warmed by the walnut of the classic board. + +### Color +- Accent: brass `#8A6216` (light) / gold `#E7BA5C` (dark). Never default iOS blue. (`AccentColor.colorset`) +- Contrast rule (`Styling.swift · BrandCTALabelColor`): labels on gold fill — white in light mode, `#1F1F1F` in dark. White on `#E7BA5C` fails WCAG (<2:1). +- Surfaces: cream `#F6EFE2` / card `#FFFDF8` (light); walnut `#171109` / card `#251C11` (dark). (`WarmBackground.colorset`) +- Outcomes: won `#34C759` · lost `#FF3B30` · draw/ongoing `#8E8E93`. +- Board themes (`BoardTheme.swift`, light/dark squares): Classic `#F0D9B5/#B58763` · Green `#EDEDD1/#759657` · Blue `#DEE5EE/#6B8CAD` · Gray `#E0E0E0/#8C8C91`. + +### Type & voice +SF / system only. Large Title 34 heavy · body 17 · row headline 15 semibold + outcome dot · detail 12 `#8E8E93`. +Copy: plain, warm, unhurried. No exclamation marks. + +### Rules +- Restyle *within* system idioms: real segmented controls, grouped cards, SF type. No web-look, no fantasy chrome in the app. +- One real board wherever the brand appears (mini boards, position thumbnails, theme tiles). +- Selection = 2px accent ring, offset −1. +- Sign in with Apple: exactly stock, always. +- Motion: default SwiftUI springs only; pieces slide, never bounce. If Settings.app wouldn't animate it, MateMate doesn't. + +### Piece design & notation (BoardView.swift · MoveAnnouncer.swift) +- Pieces: Unicode figurines, **filled glyph for both colors**, tinted white(.99) / white(.13) — outline glyphs render inconsistently. Every glyph carries U+FE0E (else the pawn turns emoji and ignores tint). Glyph 0.78× square; dragged piece lifts to 1.4×; white pieces get the stronger shadow (.5 vs .25). +- Board chrome: 14pt continuous corners, soft drop shadow. Coordinates 0.22× semibold, contrast-validated per theme, black halo on dark squares. +- Square states: selected yellow .45 · last move yellow .30 · hint blue .35 · legal target = black .22 dot (ring on captures) · check = red radial glow. +- Notation: SAN from ChessKit (`Board.san`) — `e4 Nf3 exd5 O-O a8=Q Nge2 R1a4 Qxe5+` — always mono on screen. Spoken = built from the move, never raw SAN: "White: Knight to f3, check" / "Black: pawn takes on d5" / "castles kingside" / "pawn promotes to Queen on e1". Every part localized in the app layer. + +### Web skins (docs pages only — the iOS app never wears a costume) +Same roles everywhere: ground / bone / gold / jade / flare. +- `arabic` — kufic geometry, indigo + gold. ground `#0d1233`, bone `#ece7d6`, gold `#d4af37`, jade `#4fb0c4`, flare `#c1523f`. Display: Futura. +- `indian` — lac red + marigold, didone. ground `#2a0f14`, bone `#f7ead0`, gold `#e8a020`, jade `#2bb3ad`, flare `#c81d3a`. Display: Didot. +- `andalus` — azulejo + horseshoe geometry. ground `#062a28`, bone `#f0e6d2`, gold `#c9963c`, jade `#2fb3a6`, flare `#c1633f`. Display: Avenir Next. +- `terminal` — CRT phosphor. ground `#080b0a`, bone `#c9d6c9`, gold/merged `#48d06a`, jade `#59d0c0`, flare `#e0574a`. Display: mono. + +--- + +## 02 · LULL (github.com/testtest126/LULL) + +**Mood:** cold · minimal · quiet dread · restraint over spectacle · consent, always. +A sleep aid that stops behaving like software. Not a scary game on a phone — the scary thing is the phone. "The unease is in the restraint, not the palette." (`Theme.swift`) + +### Color +- App (`Theme.swift`): ink `#07080a` · bone `#d7d5d0` · dim `#82858c` · faint `#494c53` · red `#bb3b3b`. +- Landing (`docs/index.html`): ink `#090c12` · bone `#d9d2c4` · sepia `#b9a179` · cyan `#7f9aa2` · red `#a8433f`. +- Icon ember: `#c0322c`. +- Red appears in exactly one place at a time (REC dot, ember ring, a verdict). Two reds on screen is a bug. + +### Type +- LABEL: caption2 mono, uppercase, tracking .1–.32em (e.g. `● WATCHING`). +- TITLE: system 44 heavy, lowercase ("it is awake."). +- BODY: system 17 — honest consent copy, plain, never altered for atmosphere. +- NARRATION: serif, lowercase, two-breath lines, never a shout. + +### Voice (Atmosphere.swift — original prose in each register, never a quotation; no author's name on screen) +- Kafka — the threshold (seekingConsent, denied): "a file is opening in your name." +- Beckett — the lull (watching, released): "nothing yet. / that is the idea." +- Poe — the watch (noticing → awake): "the eye has found you / and will not blink." +- Bulgakov — the guest (throughline, curdles): "manuscripts, they say, don't burn. / neither, it turns out, do i." + +### Structure & motion +- Phases (`EyeSession.Phase`): dormant → seekingConsent → watching (40s) → noticing (30s) → awake; endings: denied / released (panic switch, honored from any phase). +- One narration line per 9s beat (`Atmosphere.beatSeconds`). Slow crossfades only, never cuts. Escalation = more stillness, not more motion (2+ beats at awake → paralysis pairing). +- Status bar on every screen: phase left, `CLOSE THE EYE` right. +- Consent UI: hairline strokes, no fills; default is deny; declining is always safe and says so. + +### Named mechanics — not yet built (docs/concept.md; same pattern: gate → phase machine → voice) +- **THE ROOM** (`Sensor.microphone`) — "the microphone hears the silence, and what breaks it." Nothing recorded, nothing leaves the device. +- **THE REACH** (`Sensor.notifications`) — a notification at 3am, while the app is closed; the one mechanic that reaches past the session. Opt-in. +- **THE PULSE** (`Sensor.haptics`) — a heartbeat in your palm that is not quite yours; dread state drives one shared haptic curve. +- **THE HOUR** (ambient: time + `Sensor.motion` stillness) — "it plays differently when it is late and the room has gone still." No new permission; 03:33 is a different game than 21:00. +- **BEHIND YOU** (spatial audio) — "something placed just over your shoulder, in sound alone." A position, not a creature — never shown, never confirmed. +- New mechanics are new readings of already-granted sensors — never a reason to ask for a new one. + +### Ideation art (docs/ideation/ — design notes, not commitments) +Mood-anchor images are tonal references — the ceiling, not the target. Never reproduced literally. No new sensors; same consent gate and panic switch as THE EYE. +- **THE MIRROR** (`mirror-and-still-here.md`) — a surface that should show you yourself, lying. Ladder: clear → lag → drift → independence → contact (ceiling). Reflection = player's own live feed, desaturated + contrast-crushed, behind a growing frame-delay buffer; anything past drift is a canned authored asset caught on look-back, never live generation. Motif: "I AM STILL HERE" — persistent utterance that infects existing Poe copy; fogged, half-wiped, under-shown; full scrawl once at the ceiling, if at all. One true silence before the ceiling. +- **THE IDOL** (`the-idol-and-kintsugi.md`) — beauty quietly breaking, not gore; she is never made whole, she is made *more finished*. Ladder (on EyeSession.Phase): clear → hairline → spreading → gold-bleed → eyes open (ceiling). Cracks = hand-authored vector masks revealed in layers (no fracture sim); gold renders additive — light escaping, not paint. Each *return* of attention advances a crack. The orb = a gilded, distorted read of the player's own camera feed — she is holding you. The gold never resets: the repair IS the haunting. A porcelain tick per crack; silence before the eyes open. Cracks stay material — glass, ceramic, stone — never flesh. + +### The one rule — horror by permission (PILLARS.md) +✓ consent explicit, explained, revocable per sensor · ✓ panic switch instant from any phase · ✓ dread over gore · ✓ the game may lie to its fiction, never to the player about what the app does. +✕ photos/contacts/location/health — forbidden forever (no `Sensor` case exists) · ✕ fake "data leaked" · ✕ PII anywhere · ✕ jump-scare cadence, blood, a raised voice. + +If a scare only works by breaking this, the scare is wrong — not the rule. From c5f5bef3194563a56787580680fa018f2c7dd8a6 Mon Sep 17 00:00:00 2001 From: testtest126 <44771568+testtest126@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:11:47 +0200 Subject: [PATCH 3/5] Final moodboard content: app icon/brand, engine, online play, LULL cloud MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the chess "App icon & brand mark", "Engine strengths & review", and "Online play & clocks" sections, plus LULL's "The haunt — the cloud" section, per the owner's final sign-off on the design tool's content. Co-Authored-By: Claude Sonnet 5 --- docs/design/moodboard/MOODBOARD.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/design/moodboard/MOODBOARD.md b/docs/design/moodboard/MOODBOARD.md index ffaf792..895000c 100644 --- a/docs/design/moodboard/MOODBOARD.md +++ b/docs/design/moodboard/MOODBOARD.md @@ -28,12 +28,28 @@ Copy: plain, warm, unhurried. No exclamation marks. - Sign in with Apple: exactly stock, always. - Motion: default SwiftUI springs only; pieces slide, never bounce. If Settings.app wouldn't animate it, MateMate doesn't. +### App icon & brand mark (AppIcon.appiconset; repo issue #89) +- The mark: a chess king crowned with a gold checkmark — "check · mate," read twice. Light + dark + tinted 1024 masters ship in the asset catalog; the checkmark's gold = the brass/gold accent. +- Wordmark: plain SF, heavy — never a custom logotype. The ✓ takes the current mode's accent (brass light / gold dark) and never appears without the name. +- Wherever the brand appears, a real board appears with it. + ### Piece design & notation (BoardView.swift · MoveAnnouncer.swift) - Pieces: Unicode figurines, **filled glyph for both colors**, tinted white(.99) / white(.13) — outline glyphs render inconsistently. Every glyph carries U+FE0E (else the pawn turns emoji and ignores tint). Glyph 0.78× square; dragged piece lifts to 1.4×; white pieces get the stronger shadow (.5 vs .25). - Board chrome: 14pt continuous corners, soft drop shadow. Coordinates 0.22× semibold, contrast-validated per theme, black halo on dark squares. - Square states: selected yellow .45 · last move yellow .30 · hint blue .35 · legal target = black .22 dot (ring on captures) · check = red radial glow. - Notation: SAN from ChessKit (`Board.san`) — `e4 Nf3 exd5 O-O a8=Q Nge2 R1a4 Qxe5+` — always mono on screen. Spoken = built from the move, never raw SAN: "White: Knight to f3, check" / "Black: pawn takes on d5" / "castles kingside" / "pawn promotes to Queen on e1". Every part localized in the app layer. +### Engine strengths & review (GameSession.swift · GameReview) +- Difficulty presets: Beginner d1/1k nodes · Casual d2/0.5s · Club d4/1.0s · Expert d6/2.5s. Opening book: all but Beginner. Ponders on the player's time: Club + Expert. Random lapse: 30% / 10% / 0 / 0 — erratic like the humans they imitate. +- The engine never answers instantly: every reply takes ≥400ms, because instant feels broken. +- Review judgments by centipawn loss: Best ♛ `#1E7A46` <25 · Good ♝ `#71992F` <60 · Inaccuracy ♘ `#C2951C` <120 · Mistake ♞ `#CF7118` <250 · Blunder ♟︎ `#BB3A2C` ≥250. Shows the evaluator's preferred SAN when it differs. Judgment colors are their own scale — never the outcome green/red. + +### Online play & clocks (ChessOnline · chess-server) +- Time controls: Bullet 1+0 (60s) · Blitz 5+3 (default — peers that predate time controls always played 5+3) · Rapid 10+5. Notation always minutes+increment. +- "The mirror renders the game; the server *is* the game." Local ChessKit mirror for SAN/highlights/instant feel; every online move legality-checked server-side. Vapor owns auth, matchmaking, clocks, ratings. +- Guests play as `Guest-NNNN`; Sign in with Apple recovers an account, never gates play. +- Clocks server-authoritative: every `movePlayed` carries ClockState with both remaining times — the phone displays, never decides. Increment flashes green after a side's move; active side wears the quiet accent ring; tenths only under a minute. + ### Web skins (docs pages only — the iOS app never wears a costume) Same roles everywhere: ground / bone / gold / jade / flare. - `arabic` — kufic geometry, indigo + gold. ground `#0d1233`, bone `#ece7d6`, gold `#d4af37`, jade `#4fb0c4`, flare `#c1523f`. Display: Futura. @@ -85,6 +101,12 @@ Mood-anchor images are tonal references — the ceiling, not the target. Never r - **THE MIRROR** (`mirror-and-still-here.md`) — a surface that should show you yourself, lying. Ladder: clear → lag → drift → independence → contact (ceiling). Reflection = player's own live feed, desaturated + contrast-crushed, behind a growing frame-delay buffer; anything past drift is a canned authored asset caught on look-back, never live generation. Motif: "I AM STILL HERE" — persistent utterance that infects existing Poe copy; fogged, half-wiped, under-shown; full scrawl once at the ceiling, if at all. One true silence before the ceiling. - **THE IDOL** (`the-idol-and-kintsugi.md`) — beauty quietly breaking, not gore; she is never made whole, she is made *more finished*. Ladder (on EyeSession.Phase): clear → hairline → spreading → gold-bleed → eyes open (ceiling). Cracks = hand-authored vector masks revealed in layers (no fracture sim); gold renders additive — light escaping, not paint. Each *return* of attention advances a crack. The orb = a gilded, distorted read of the player's own camera feed — she is holding you. The gold never resets: the repair IS the haunting. A porcelain tick per crack; silence before the eyes open. Cracks stay material — glass, ceramic, stone — never flesh. +### The haunt — the "cloud" (docs/concept.md §04; later, and gated) +- "What happened to you happened to someone else, tonight, on their own phone." Story shifts between sessions, responds, is subtly shared. Its on-screen voice: `1 OTHER IS ALSO AWAKE`. +- Maps onto MateMate's Vapor server/sessions/realtime — already solved. LULL's first network touch, and exactly where chess's security rigor returns: a server handling player data earns real gating. +- Persistence candidates: a shared "I AM STILL HERE"; gilding a previous player left on the idol. Neither depends on it — local one-sitting versions ship first. +- No PII in repo, logs, or telemetry — ever. The fear stays legibly fiction, even over the wire. + ### The one rule — horror by permission (PILLARS.md) ✓ consent explicit, explained, revocable per sensor · ✓ panic switch instant from any phase · ✓ dread over gore · ✓ the game may lie to its fiction, never to the player about what the app does. ✕ photos/contacts/location/health — forbidden forever (no `Sensor` case exists) · ✕ fake "data leaked" · ✕ PII anywhere · ✕ jump-scare cadence, blood, a raised voice. From 53f531c4e33dc2987b5b1c6836fd565c7f8a122a Mon Sep 17 00:00:00 2001 From: testtest126 <44771568+testtest126@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:33:57 +0200 Subject: [PATCH 4/5] Sync moodboard doc to canonical version from LULL Pulled verbatim from LULL's docs/design/moodboard/MOODBOARD.md (source of truth for this shared doc), adding the "Leaderboard & ratings" and "Accessibility & VoiceOver" sections. Co-Authored-By: Claude Sonnet 5 --- docs/design/moodboard/MOODBOARD.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/design/moodboard/MOODBOARD.md b/docs/design/moodboard/MOODBOARD.md index 895000c..ea91a4d 100644 --- a/docs/design/moodboard/MOODBOARD.md +++ b/docs/design/moodboard/MOODBOARD.md @@ -3,6 +3,10 @@ Style reference for agents working in these repos. Two games, one maker, opposite moods — never blend them. Visual boards: `chess-moodboard.html` / `lull-moodboard.html` (self-contained, open in any browser). +**Contents** +- 01 · MateMate — Color · Type & voice · Rules · App icon & brand mark · Piece design & notation · Engine strengths & review · Online play & clocks · Accessibility & VoiceOver · Web skins +- 02 · LULL — Color · Type · Voice · Structure & motion · Named mechanics · Ideation art (Mirror, Idol) · The haunt · The one rule + --- ## 01 · MateMate (github.com/testtest126/chess) @@ -17,6 +21,8 @@ Feels like it shipped with iOS, warmed by the walnut of the classic board. - Outcomes: won `#34C759` · lost `#FF3B30` · draw/ongoing `#8E8E93`. - Board themes (`BoardTheme.swift`, light/dark squares): Classic `#F0D9B5/#B58763` · Green `#EDEDD1/#759657` · Blue `#DEE5EE/#6B8CAD` · Gray `#E0E0E0/#8C8C91`. +- Dark mode: accent brass → gold, cream → walnut `#171109`, cards near-black `#251C11`, CTA labels white → `#1F1F1F`, SIWA inverts to stock white. Never flips: board square colors (player's theme choice) and outcome green/red/gray. The ✓ always wears the current mode's accent. + ### Type & voice SF / system only. Large Title 34 heavy · body 17 · row headline 15 semibold + outcome dot · detail 12 `#8E8E93`. Copy: plain, warm, unhurried. No exclamation marks. @@ -50,6 +56,21 @@ Copy: plain, warm, unhurried. No exclamation marks. - Guests play as `Guest-NNNN`; Sign in with Apple recovers an account, never gates play. - Clocks server-authoritative: every `movePlayed` carries ClockState with both remaining times — the phone displays, never decides. Increment flashes green after a side's move; active side wears the quiet accent ring; tenths only under a minute. +### Leaderboard & ratings (User.swift · GameCoordinator.swift) +- Standard Elo, server-owned: everyone starts at 1200, K=32, expected = 1/(1+10^(Δ/400)). Deltas ride the `gameOver` message (`ratingDeltaWhite/Black`) — never computed client-side; shown as green +N / red −N. +- Leaderboard (`GET /leaderboard`): top 50 by Elo, players with ≥1 finished game; reached from the trophy button on Home. Rank gold only for #1. +- Matchmaking: mutual window — fresh entrant accepts ±100 Elo, widens per second waited, uncapped; a pair forms only when each window covers the gap. +- Rematch offer window 60s; colors swap; new game uses post-Elo ratings. Profiles (rating + record) visible to signed-in players; game contents are not. + +### Accessibility & VoiceOver (audit #83; tested, not aspirational) +- Every square is a VoiceOver button: label = "e4, White Knight"; identifier `square_e4`; value mirrors every visual highlight — selected · possible move · last move · hint · in check — and states compose ("possible move, last move"). Whole matrix unit-tested. +- Takebacks announce "Move taken back"; moves speak plain English, never raw SAN. +- Coordinate contrast unit-tested per theme: light squares ≥4.5:1 (AA small text); mid-tone dark squares can't reach 4.5:1 with any color → white ≥3.0:1 + halo shadow; new scheme must strictly beat the old opposite-square-color labels everywhere. +- Xcode accessibility audit runs on demand across home/game/review — evidence attachments, not a CI gate. +- Constraints live in code and tests (`BoardTheme.coordinateColor`, `BrandCTALabelColor`), never as guidance. + +- Sounds (`SoundPlayer.swift`): exactly three — `move.wav` · `capture.wav` · `game_end.wav`, fixed 0.6 volume. Session is `.ambient + .mixWithOthers`: the silent switch always wins; other apps' audio keeps playing. Capture vs move decided from the board (en passant included); same sounds vs engine and online. + ### Web skins (docs pages only — the iOS app never wears a costume) Same roles everywhere: ground / bone / gold / jade / flare. - `arabic` — kufic geometry, indigo + gold. ground `#0d1233`, bone `#ece7d6`, gold `#d4af37`, jade `#4fb0c4`, flare `#c1523f`. Display: Futura. @@ -107,6 +128,10 @@ Mood-anchor images are tonal references — the ceiling, not the target. Never r - Persistence candidates: a shared "I AM STILL HERE"; gilding a previous player left on the idol. Neither depends on it — local one-sitting versions ship first. - No PII in repo, logs, or telemetry — ever. The fear stays legibly fiction, even over the wire. +### App icon & wordmark (design/app-icon.svg · AppIcon-1024) +- The mark is a lens, not a cartoon eye — the device's own front camera looking back. Near-black radial ground, catchlight upper-left, one red: an ember ring at the rim `#c0322c` with a faint echo around the pupil. Never blinks, never animates. +- Wordmark: LULL in mono, tracking .32em, usually beside the ● REC line. No logotype. Working-title alts on record: HUSH / VIGIL / SOMNUS — whatever the name, the lens stays. + ### The one rule — horror by permission (PILLARS.md) ✓ consent explicit, explained, revocable per sensor · ✓ panic switch instant from any phase · ✓ dread over gore · ✓ the game may lie to its fiction, never to the player about what the app does. ✕ photos/contacts/location/health — forbidden forever (no `Sensor` case exists) · ✕ fake "data leaked" · ✕ PII anywhere · ✕ jump-scare cadence, blood, a raised voice. From 3c0145b9b9e7111238a5e64d331fe5dd0d0a6861 Mon Sep 17 00:00:00 2001 From: testtest126 <44771568+testtest126@users.noreply.github.com> Date: Tue, 21 Jul 2026 21:12:15 +0200 Subject: [PATCH 5/5] Sync moodboard doc to canonical version from LULL The branch's copy had drifted from the LULL source of truth (139 lines, missing Promotion picker, Hints & takebacks, Opening book, Draw offers & resign, the Ornaments line, and The dev loop sections). Re-synced verbatim from testtest126/LULL main. Co-Authored-By: Claude Sonnet 5 --- docs/design/moodboard/MOODBOARD.md | 36 +++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/design/moodboard/MOODBOARD.md b/docs/design/moodboard/MOODBOARD.md index ea91a4d..5c7b18e 100644 --- a/docs/design/moodboard/MOODBOARD.md +++ b/docs/design/moodboard/MOODBOARD.md @@ -45,6 +45,19 @@ Copy: plain, warm, unhurried. No exclamation marks. - Square states: selected yellow .45 · last move yellow .30 · hint blue .35 · legal target = black .22 dot (ring on captures) · check = red radial glow. - Notation: SAN from ChessKit (`Board.san`) — `e4 Nf3 exd5 O-O a8=Q Nge2 R1a4 Qxe5+` — always mono on screen. Spoken = built from the move, never raw SAN: "White: Knight to f3, check" / "Black: pawn takes on d5" / "castles kingside" / "pawn promotes to Queen on e1". Every part localized in the app layer. +### Promotion picker (BoardView.swift) +- Stock `confirmationDialog` titled "Promote to", tinted brass — never a custom picker. Triggered by legality: one from→to matching several legal moves means promotion, on tap and drag alike. +- Options sorted queen → rook → bishop → knight (`promotionOrder`); names localized via `PieceKind.localizedName`. +- Spoken: "Black: pawn promotes to Queen on e1" ("pawn takes and promotes to …" on captures). Written: SAN `a8=Q`. + +### Hints & takebacks (GameSession.swift) +- Hint = "what would you play for me?" — fixed depth-4/1.0s search regardless of opponent strength; pondering stops first (hint rides the warm table); shown only if the position is unchanged; both squares tint blue and read "hint"; clears on the next move. +- Take Back rewinds 2 plies (your move + engine's reply). Gated: game not over, engine idle, ≥2 moves, you to move. VoiceOver: "Move taken back." Engine games only — the server doesn't rewind. + +### Opening book (OpeningBook.standard) +- 14 mainlines, first 4–6 moves each: 1.e4 — Ruy Lopez, Italian, Sicilian Open, Sveshnikov-ish, French Classical, Caro-Kann Classical, Scandinavian · 1.d4 — QGD, Slav, KID, Nimzo-Indian, London · 1.c4 — English Reversed Sicilian, English Symmetric. +- Keyed by position (`repetitionKey`) — transpositions still hit the book. In book, the engine plays a uniformly random book move (variety). Illegal moves end their line at build time. Used by every strength except Beginner; EngineLab benches leave it off for determinism. + ### Engine strengths & review (GameSession.swift · GameReview) - Difficulty presets: Beginner d1/1k nodes · Casual d2/0.5s · Club d4/1.0s · Expert d6/2.5s. Opening book: all but Beginner. Ponders on the player's time: Club + Expert. Random lapse: 30% / 10% / 0 / 0 — erratic like the humans they imitate. - The engine never answers instantly: every reply takes ≥400ms, because instant feels broken. @@ -56,12 +69,6 @@ Copy: plain, warm, unhurried. No exclamation marks. - Guests play as `Guest-NNNN`; Sign in with Apple recovers an account, never gates play. - Clocks server-authoritative: every `movePlayed` carries ClockState with both remaining times — the phone displays, never decides. Increment flashes green after a side's move; active side wears the quiet accent ring; tenths only under a minute. -### Leaderboard & ratings (User.swift · GameCoordinator.swift) -- Standard Elo, server-owned: everyone starts at 1200, K=32, expected = 1/(1+10^(Δ/400)). Deltas ride the `gameOver` message (`ratingDeltaWhite/Black`) — never computed client-side; shown as green +N / red −N. -- Leaderboard (`GET /leaderboard`): top 50 by Elo, players with ≥1 finished game; reached from the trophy button on Home. Rank gold only for #1. -- Matchmaking: mutual window — fresh entrant accepts ±100 Elo, widens per second waited, uncapped; a pair forms only when each window covers the gap. -- Rematch offer window 60s; colors swap; new game uses post-Elo ratings. Profiles (rating + record) visible to signed-in players; game contents are not. - ### Accessibility & VoiceOver (audit #83; tested, not aspirational) - Every square is a VoiceOver button: label = "e4, White Knight"; identifier `square_e4`; value mirrors every visual highlight — selected · possible move · last move · hint · in check — and states compose ("possible move, last move"). Whole matrix unit-tested. - Takebacks announce "Move taken back"; moves speak plain English, never raw SAN. @@ -71,12 +78,24 @@ Copy: plain, warm, unhurried. No exclamation marks. - Sounds (`SoundPlayer.swift`): exactly three — `move.wav` · `capture.wav` · `game_end.wav`, fixed 0.6 volume. Session is `.ambient + .mixWithOthers`: the silent switch always wins; other apps' audio keeps playing. Capture vs move decided from the board (en passant included); same sounds vs engine and online. +### Draw offers & resign (GameCoordinator.swift · Messages.swift) +- Draw lifecycle is server-owned: `offer_draw` → `draw_offered` relayed to the opponent → `accept_draw` ⇒ ½–½ (drawAgreement, gray) / `decline_draw` ⇒ cleared; a played move clears the offer. One pending offer at a time; accepting only works against the opponent's pending offer. +- Resign: always confirmed, never one tap — the only red action in the app. Engine games settle locally; online it's one `resign` message and the server declares result + Elo. Mid-search resign is safe (engine answer discarded). +- `Game.EndReason` names every ending: checkmate · stalemate · resignation · timeout · drawAgreement · abandoned. + +### Leaderboard & ratings (User.swift · GameCoordinator.swift) +- Standard Elo, server-owned: everyone starts at 1200, K=32, expected = 1/(1+10^(Δ/400)). Deltas ride the `gameOver` message (`ratingDeltaWhite/Black`) — never computed client-side; shown as green +N / red −N. +- Leaderboard (`GET /leaderboard`): top 50 by Elo, players with ≥1 finished game; reached from the trophy button on Home. Rank gold only for #1. +- Matchmaking: mutual window — fresh entrant accepts ±100 Elo, widens per second waited, uncapped; a pair forms only when each window covers the gap. +- Rematch offer window 60s; colors swap; new game uses post-Elo ratings. Profiles (rating + record) visible to signed-in players; game contents are not. + ### Web skins (docs pages only — the iOS app never wears a costume) Same roles everywhere: ground / bone / gold / jade / flare. - `arabic` — kufic geometry, indigo + gold. ground `#0d1233`, bone `#ece7d6`, gold `#d4af37`, jade `#4fb0c4`, flare `#c1523f`. Display: Futura. - `indian` — lac red + marigold, didone. ground `#2a0f14`, bone `#f7ead0`, gold `#e8a020`, jade `#2bb3ad`, flare `#c81d3a`. Display: Didot. - `andalus` — azulejo + horseshoe geometry. ground `#062a28`, bone `#f0e6d2`, gold `#c9963c`, jade `#2fb3a6`, flare `#c1633f`. Display: Avenir Next. - `terminal` — CRT phosphor. ground `#080b0a`, bone `#c9d6c9`, gold/merged `#48d06a`, jade `#59d0c0`, flare `#e0574a`. Display: mono. +- Ornaments: one fixed SVG pattern layer at z-index −1; each theme swaps only the pattern and reads `--gold` stroke + `--orn-opacity`. arabic `hex6` six-fold rosette (.07) · japanese `ensoFaint` incomplete ensō (.05) · indian `jaali` lattice (.07) · codex `vine` marginalia (.12) · andalus `star8` Alhambra lattice (.07) · terminal `scan` 10px CRT lines (.05, widened from 5px to stop glyph aliasing). Headings over the layer get a bg-colored text-shadow halo. Default/light themes: no ornament. --- @@ -132,6 +151,11 @@ Mood-anchor images are tonal references — the ceiling, not the target. Never r - The mark is a lens, not a cartoon eye — the device's own front camera looking back. Near-black radial ground, catchlight upper-left, one red: an ember ring at the rim `#c0322c` with a faint echo around the pupil. Never blinks, never animates. - Wordmark: LULL in mono, tracking .32em, usually beside the ● REC line. No logotype. Working-title alts on record: HUSH / VIGIL / SOMNUS — whatever the name, the lens stays. +### The dev loop (run.sh) +- One command end to end: xcodegen generate → pick simulator (booted iPhone first, else newest runtime) → boot → build Debug → install → launch. Sign-off in register: "LULL is running on iPhone 16. Enjoy — alone, in the dark." +- The repo stays clean: never touches LULLKit or app/Sources; generates only the gitignored xcodeproj; temp derived-data outside the repo. Requires full Xcode (not CLT); errors die with the exact fix (`brew install xcodegen`, etc). Even tooling keeps the voice — cyan arrows, lowercase calm. +- The simulator can't see you: the front camera is a no-op there; build to a real device to see THE EYE actually watch. + ### The one rule — horror by permission (PILLARS.md) ✓ consent explicit, explained, revocable per sensor · ✓ panic switch instant from any phase · ✓ dread over gore · ✓ the game may lie to its fiction, never to the player about what the app does. ✕ photos/contacts/location/health — forbidden forever (no `Sensor` case exists) · ✕ fake "data leaked" · ✕ PII anywhere · ✕ jump-scare cadence, blood, a raised voice.