diff --git a/.planning/intel/assets-spec.md b/.planning/intel/assets-spec.md index 9b4ba9f..1fa478e 100644 --- a/.planning/intel/assets-spec.md +++ b/.planning/intel/assets-spec.md @@ -1,12 +1,33 @@ # Mokosh Asset Specification Concrete deliverables list derived from `design-system.md`. Each entry tells a -contributor (you, an agent, a hired designer) exactly what file to produce, -what dimensions/format, what to draw, and where to commit it. Authored -2026-05-17 to unblock Plan 01-09's notification-icon failure + Plan 01-10's -welcome page. +contributor (you, an agent, a hired designer) exactly what file to produce +and where to commit it. **Path / dimensions / format / file-size floors / validation +are technical constraints from Chrome and MV3 — those are floors.** Subject, +colors, illustration choices, and aesthetic intent are open and owned by the +design team. -Status: `draft` — first iteration; revise as actual designs surface. +Authored 2026-05-17 to unblock Plan 01-09's notification-icon failure + +Plan 01-10's welcome page. Status: `draft` — every aesthetic description below +is a starting suggestion; the design team picks the actual direction per +`brand-identity.md` + `design-system.md`. + +--- + +## What's locked vs what's open in this file + +| Cell | Status | +|---|---| +| **Path** | **FLOOR** — Chrome/manifest look at exact paths | +| **Dimensions** | **FLOOR** — Chrome notification + extension APIs enforce | +| **Format** (PNG/SVG) | **FLOOR** — Chrome API requirements per surface | +| **Min file size** | **FLOOR** — Chrome `imageUtil` silent-rejection floors | +| **Validation command** | **FLOOR** — these are the checks Chrome runs | +| **Subject** | **OPEN** — design team picks the mark, motif, illustration | +| **Color** | **OPEN** — per `design-system.md` palette direction | +| **Style notes** | OPEN — engineering's sketch only | + +Floors are non-negotiable. Everything else is direction the design team owns. --- @@ -19,40 +40,40 @@ land its operator-empirical UAT until valid versions exist. | | | |---|---| -| **Path** | `icons/icon16.png` (commit to source tree; vite copies to `dist/icons/` on build) | -| **Dimensions** | 16 × 16 px | -| **Format** | PNG, RGBA (transparent background), 8-bit | -| **Min file size** | ≥ 200 bytes (current placeholder is 79 B — Chrome rejects it) | -| **Subject** | The Mokosh mark per `design-system.md` §5.2. At 16px most detail is lost; produce as a single recognizable silhouette. | -| **Color** | Single accent color OR transparent + accent. Recommended: a filled circle in `#212121` (near-black, neutral) for visibility on both light and dark Chrome themes. Adding the recording dot in `--mks-rec` makes this state-coloured, which conflicts with the "neutral mark + state via badge" decision (design-system §5.2). **Pick neutral.** | +| **Path** **(FLOOR)** | `icons/icon16.png` (commit to source tree; vite copies to `dist/icons/` on build) | +| **Dimensions** **(FLOOR)** | 16 × 16 px | +| **Format** **(FLOOR)** | PNG, RGBA (transparent background), 8-bit | +| **Min file size** **(FLOOR)** | ≥ 200 bytes (Chrome rejects below this) | +| **Subject** *(OPEN — design team)* | Engineering currently ships a dark-square + green-dot placeholder. Design team picks the actual mark per `design-system.md` §5.3 — could be a recording-dot in a frame, a thread/spool motif, a wordmark fragment, an abstract glyph, or anything else. At 16 px most detail is lost; aim for a single recognizable silhouette. | +| **Color** *(OPEN — design team)* | Engineering's placeholder uses neutral dark + accent green. Design team picks per palette direction. Note: if the team lands on "neutral mark + state via badge" (one of several options in `design-system.md` §5.2), the icon stays neutral across all states; if the team picks "per-state icon swaps", separate variants per state are needed (see Priority 2 A-06). | | **Where used** | Chrome menu bars, Extensions page list, autocomplete popup | -| **Validation** | After committing: `npm run build && grep -q '"16"' dist/manifest.json && [ -s dist/icons/icon16.png ]` | +| **Validation** **(FLOOR)** | `npm run build && grep -q '"16"' dist/manifest.json && [ -s dist/icons/icon16.png ]` | ### A-02 — `icons/icon48.png` | | | |---|---| -| **Path** | `icons/icon48.png` | -| **Dimensions** | 48 × 48 px | -| **Format** | PNG, RGBA, 8-bit | -| **Min file size** | ≥ 500 bytes (current placeholder is 123 B) | -| **Subject** | Same mark as A-01, more visible internal detail. The frame/ring around the dot can resolve at this size. | -| **Color** | Same constraint: neutral. | -| **Where used** | Chrome Extensions page (chrome://extensions card icon), some context menus | -| **Validation** | `grep -q '"48"' dist/manifest.json && [ -s dist/icons/icon48.png ]` | +| **Path** **(FLOOR)** | `icons/icon48.png` | +| **Dimensions** **(FLOOR)** | 48 × 48 px | +| **Format** **(FLOOR)** | PNG, RGBA, 8-bit | +| **Min file size** **(FLOOR)** | ≥ 500 bytes | +| **Subject** *(OPEN — design team)* | Same concept as A-01; this size carries more internal detail, so glyph elements that don't resolve at 16 px (frame, ring, secondary shape) can appear here. | +| **Color** *(OPEN — design team)* | Same direction as A-01. | +| **Where used** | Chrome Extensions page card icon, some context menus | +| **Validation** **(FLOOR)** | `grep -q '"48"' dist/manifest.json && [ -s dist/icons/icon48.png ]` | ### A-03 — `icons/icon128.png` | | | |---|---| -| **Path** | `icons/icon128.png` | -| **Dimensions** | 128 × 128 px (REQUIRED minimum for `chrome.notifications.create({type:'basic'})`) | -| **Format** | PNG, RGBA, 8-bit | -| **Min file size** | ≥ 1 KB (current placeholder is 306 B — silently rejected by `chrome.imageUtil` per the empirical finding) | -| **Subject** | Full Mokosh mark, all detail visible. This is the primary brand asset. | -| **Color** | Neutral mark; the badge layer adds state colour. | -| **Where used** | Chrome Web Store thumbnail (someday), notification iconUrl (per `design-system.md` §8.2), about-extension dialogs | -| **Validation** | `[ $(stat -c%s dist/icons/icon128.png) -gt 1024 ]` AND `chrome.notifications.create` succeeds in smoke without `imageUtil` error | +| **Path** **(FLOOR)** | `icons/icon128.png` | +| **Dimensions** **(FLOOR)** | 128 × 128 px (REQUIRED minimum for `chrome.notifications.create({type:'basic'})`) | +| **Format** **(FLOOR)** | PNG, RGBA, 8-bit | +| **Min file size** **(FLOOR)** | ≥ 1 KB (Chrome's `imageUtil` silently rejects smaller files per the Plan 01-09 empirical finding) | +| **Subject** *(OPEN — design team)* | Primary brand asset — full mark, every detail visible. Design team has full latitude. | +| **Color** *(OPEN — design team)* | Same direction as A-01/A-02. | +| **Where used** | Chrome Web Store thumbnail (someday), notification `iconUrl`, about-extension dialogs | +| **Validation** **(FLOOR)** | `[ $(stat -c%s dist/icons/icon128.png) -gt 1024 ]` AND `chrome.notifications.create` succeeds in smoke without `imageUtil` error | --- @@ -62,86 +83,98 @@ land its operator-empirical UAT until valid versions exist. | | | |---|---| -| **Path** | `icons/icon192.png` | -| **Dimensions** | 192 × 192 px | -| **Format** | PNG, RGBA, 8-bit | -| **Min file size** | ≥ 2 KB | -| **Subject** | Identical to A-03 at higher resolution; for hi-DPI displays in notification rendering | -| **Status** | Optional but recommended. If skipped, A-03 (128px) is the fallback. | +| **Path** **(FLOOR if shipped)** | `icons/icon192.png` | +| **Dimensions** **(FLOOR if shipped)** | 192 × 192 px | +| **Format** **(FLOOR if shipped)** | PNG, RGBA, 8-bit | +| **Min file size** | ≥ 2 KB (suggested) | +| **Subject** *(OPEN)* | Identical concept to A-03 at higher resolution for hi-DPI notification rendering | +| **Status** | Optional. Skip if not producing hi-DPI variants; A-03 is the fallback. | -### A-05 — Welcome page hero mark (Plan 01-10) +### A-05 — Welcome page hero (Plan 01-10) | | | |---|---| -| **Path** | `src/welcome/hero.svg` (preferred — vector) OR `src/welcome/hero.png` (1024×512 fallback) | -| **Format** | SVG (inline-safe, no external refs) OR PNG | -| **Subject** | Lockup of the Mark + the wordmark "Mokosh" OR "AI Call Recorder". Type lockup at large scale. Per `design-system.md` §10 ODD-4, default is "type-only hero" if no illustration exists — in that case the SVG can be a stylized rendering of the wordmark alone. | +| **Path** *(suggested)* | `src/welcome/hero.svg` (vector preferred) OR `src/welcome/hero.png` (≥ 1024 × 512 fallback) | +| **Format** **(FLOOR)** | SVG (inline, no external refs **(FLOOR for CSP)**) OR PNG | +| **Subject** *(OPEN — design team owns entirely)* | Could be wordmark-only lockup, mark + wordmark, illustrated scene, photographic backdrop, type-only treatment, video, or no hero at all (some welcome pages start with copy). Design team picks. | | **Used by** | `src/welcome/welcome.html` (Plan 01-10) | -| **Status** | Required for Plan 01-10 closure. Acceptable interim: type-only HTML/CSS lockup (no asset file needed) | +| **Status** | Required for Plan 01-10 closure IF the design team's welcome layout uses a hero. Acceptable interim: type-only HTML/CSS lockup (no asset file needed). | --- ## Priority 2 — refinement passes (future phases) -### A-06 — Status-glyph variants for badge composition +### A-06 — Per-state icon variants (only if "per-state icon swaps" direction is picked) -The current architecture uses Chrome's badge API (text + background color) for -state communication. If a future phase wants richer state indication (e.g. a -recording-dot embedded in the toolbar icon itself, swapped via -`chrome.action.setIcon`), we'd need per-state icon variants: +`design-system.md` §5.2 lists two iconography directions: -| Variant | Dimensions | When used | +- **Neutral mark + state via badge** (Chrome's `chrome.action.setBadgeBackgroundColor` does the state work) — only A-01/A-02/A-03 needed +- **Per-state icon swaps via `chrome.action.setIcon`** — needs full sets per state + +If the design team picks per-state swaps, the deliverables expand: + +| Variant set | Dimensions | When used | |---|---|---| -| `icons/icon-rec-16.png` etc. | 16/48/128 | When recording active (red dot overlay) | -| `icons/icon-err-16.png` etc. | 16/48/128 | When in error state | -| `icons/icon-off-16.png` etc. | 16/48/128 | When idle | +| `icons/icon-rec-{16,48,128}.png` | 16/48/128 | When recording active | +| `icons/icon-err-{16,48,128}.png` | 16/48/128 | When in error state | +| `icons/icon-off-{16,48,128}.png` | 16/48/128 | When idle | -Recommendation: defer to Phase 5 hardening unless badge text proves insufficient. -The performance cost of setIcon swaps every state change is non-trivial. +Trade-off: visual richness vs. perf cost of `setIcon` swaps every state change. +Design team weighs. -### A-07 — Popup polish +### A-07 — Popup polish *(OPEN — defer)* | | | |---|---| -| **Path** | `src/popup/popup-bg.svg` | -| **Subject** | Optional subtle background pattern OR colour for popup container; currently popup uses solid `--mks-popup-bg-dark/light` | -| **Status** | Skip; current solid background is fine | +| **Path** *(suggested)* | `src/popup/popup-bg.svg` or similar | +| **Subject** *(OPEN)* | Background pattern, gradient, illustration, or nothing (current placeholder is a solid color). | +| **Status** | Defer until the design team picks popup direction. Solid background is the working placeholder. | -### A-08 — Operator runbook visuals (smoke.sh page enhancements) +### A-08 — Operator runbook visuals (smoke-test page) -The smoke test page (in `smoke.sh`'s SMOKE_HTML) currently uses emoji and -inline CSS. Could be replaced with a properly-designed instructional page if +The dev smoke page (`smoke.sh`'s SMOKE_HTML) currently uses Unicode emoji and +inline CSS. Could be replaced with properly-designed instructional visuals if operators actually use it for onboarding. Currently dev-only; defer. --- -## Implementation pathways for the contributor +## Implementation pathways -Pick ONE based on availability: +Pick ONE per asset: -### Path A — auto-generated solid-color placeholder set +### Path A — auto-generated placeholders (engineering's current default) -**Use case:** quickly unblock Plan 01-09 closeout. Replace placeholders with -real designed assets later. +**Use case:** unblock Plan 01-09 closeout immediately. Designer-team assets +swap in cleanly later. The currently committed placeholders in working tree +were produced this way. ```bash -# Quick generator using ImageMagick (one-liner per size) -convert -size 16x16 xc:'#212121' -draw "fill #00C853 circle 8,8 8,4" icons/icon16.png -convert -size 48x48 xc:'#212121' -draw "fill #00C853 circle 24,24 24,12" icons/icon48.png -convert -size 128x128 xc:'#212121' -draw "fill #00C853 circle 64,64 64,32" icons/icon128.png +# Example placeholder generator using ImageMagick (one-liner per size) +convert -size 16x16 xc:'' -draw "fill circle 8,8 8,4" icons/icon16.png +convert -size 48x48 xc:'' -draw "fill circle 24,24 24,12" icons/icon48.png +convert -size 128x128 xc:'' -draw "fill circle 64,64 64,32" icons/icon128.png ``` -Produces dark-square + green-dot icons (~1 KB each). Functional, not branded. +Engineering's current run used `'#212121'` background + `'#00C853'` accent +(neither is direction — both are placeholder picks). Design team can either +swap in branded assets per Path B/C, or rerun this command with different +colors as a stepping-stone placeholder. + +Produces dark-square + accent-dot icons (~1 KB each at 128 px). Functional, +not branded. ### Path B — design-first -You produce the assets per the `design-system.md` constraints. Drop them at the -spec'd paths. Run `npm run build`, smoke.sh, confirm notification fires. +The design team produces the assets per `brand-identity.md` + `design-system.md` +direction. Drop them at the spec'd paths. Run `npm run build`, smoke.sh, +confirm notification fires. ### Path C — hire / commission -Send `design-system.md` + this file to a designer. Acceptance: deliverables at -the listed paths, dimensions, formats, with file sizes above the floors. +Send `brand-identity.md` + `design-system.md` + this file to an external +designer. Acceptance: deliverables at the listed paths, dimensions, formats, +with file sizes above the floors. The design team or product owner approves +brand fit independently of engineering. --- @@ -149,25 +182,23 @@ the listed paths, dimensions, formats, with file sizes above the floors. Plan 01-09's operator UAT can resume when ALL of these are true: -- [ ] `icons/icon16.png` exists, ≥ 200 bytes, is 16×16 PNG -- [ ] `icons/icon48.png` exists, ≥ 500 bytes, is 48×48 PNG -- [ ] `icons/icon128.png` exists, ≥ 1024 bytes, is 128×128 PNG -- [ ] `npm run build` mirrors them to `dist/icons/` -- [ ] Smoke run: `chrome.notifications.create` does NOT throw `imageUtil` error -- [ ] Recovery notification visibly appears after click "Stop sharing" in Chrome +- [ ] `icons/icon16.png` exists, ≥ 200 bytes, is 16 × 16 PNG **(FLOOR)** +- [ ] `icons/icon48.png` exists, ≥ 500 bytes, is 48 × 48 PNG **(FLOOR)** +- [ ] `icons/icon128.png` exists, ≥ 1024 bytes, is 128 × 128 PNG **(FLOOR)** +- [ ] `npm run build` mirrors them to `dist/icons/` **(FLOOR)** +- [ ] Smoke run: `chrome.notifications.create` does NOT throw `imageUtil` error **(FLOOR)** +- [ ] Recovery notification visibly appears after clicking "Stop sharing" in Chrome -Once those pass + Plan 01-09 Bug B fix (state routing for `user-stopped-sharing` -→ `setIdleMode`) lands, the wave closes. +Brand fit / design approval is a separate gate — owned by the design team and +product, not blocking the functional Plan 01-09 closure. --- ## Related -- `design-system.md` — visual + interaction language this spec realises -- `.planning/phases/01-stabilize-video-pipeline/01-09-PLAN.md` — the plan that - surfaced the icon need -- `.planning/debug/01-09-recovery-flow.md` — the debug session that confirmed - the icon files are the blocker -- `src/background/index.ts` lines 54, 833-840 — NOTIFICATION_ICON_PATH constant - + the chrome.notifications.create call site that needs valid icons -- `manifest.json` `icons` and `action.default_icon` — declare which sizes exist +- `brand-identity.md` — naming + blurb + creative slate (Brief #1) +- `design-system.md` — visual + interaction language this spec realises (engineering sketch + technical floors) +- `.planning/phases/01-stabilize-video-pipeline/01-09-PLAN.md` — the plan that surfaced the icon need +- `.planning/debug/resolved/01-09-recovery-flow.md` *(when written)* — the debug session that confirmed the icon files are the blocker +- `src/background/index.ts` lines 54, 833-840 — `NOTIFICATION_ICON_PATH` constant + the `chrome.notifications.create` call site that needs valid icons +- `manifest.json` `icons` and `action.default_icon` — declare which sizes ship diff --git a/.planning/intel/brand-identity.md b/.planning/intel/brand-identity.md new file mode 100644 index 0000000..f99b9fb --- /dev/null +++ b/.planning/intel/brand-identity.md @@ -0,0 +1,283 @@ +# Mokosh — Brand Identity (Brief #1: Name + Blurb + Open Creative Slate) + +First in a series of brand-foundation artifacts for the **design team** and +the **brand team**. Engineering's role here is to enumerate what's mechanically +locked (one item only) and inventory the options for everything else. **Every +creative decision below is open.** Pick, override, or replace from a blank page. + +Sibling docs already shipped: + +- `design-system.md` — engineering's starting visual sketch (treat as draft, not contract) +- `assets-spec.md` — concrete file deliverables (Chrome API technical floors are binding; aesthetic descriptions are open) + +Status: `draft` — authored 2026-05-17. Replace, rewrite, or scrap whole sections. + +--- + +## What's locked vs what's open + +| Decision | Status | Owner | +|---|---|---| +| Internal codename **"Mokosh"** | **LOCKED** | Engineering (already wired through code, docs, commits, planning) | +| Public display name (`manifest.json:name`) | OPEN | Brand team | +| Design system name | OPEN | Both teams | +| One-liner / blurb / long description | OPEN | Brand team | +| Voice + tone + register | OPEN | Brand team | +| Color palette (every hex) | OPEN | Design team | +| Typography (face, scale, fallbacks) | OPEN | Design team — technical floor: Cyrillic must render | +| Iconography style (solid/line/mixed, mark concept) | OPEN | Design team — technical floor: 16/48/128 px PNG, file-size floors per `assets-spec.md` | +| Corner radii | OPEN | Design team | +| Motion vocabulary | OPEN | Design team | +| Welcome-tab layout + hero treatment | OPEN | Design team | +| Localization defaults (RU-first or EN-first) | OPEN | Brand team + product | + +Anywhere this brief (or the sibling specs) cites a specific hex, font, or +treatment, read it as **"what engineering currently ships in placeholder +builds"** — not as direction. Engineering will rewire to whatever the teams +decide. + +--- + +## 1. The name — `Mokosh` *(LOCKED)* + +Only locked decision in this brief. The codename is already woven through the +codebase (`src/`, `manifest.json`, planning docs, debug sessions, commit +history), so changing it is a refactor, not a brand choice. Engineering owns +the lock; the teams own everything downstream. + +| | | +|---|---| +| **Origin** | Мокошь — East-Slavic goddess of weaving, fate, and women's work; one of the few female deities in the pre-Christian Slavic pantheon. | +| **Pronunciation** | English: **MOH-kosh** (first syllable stressed). Russian: МО́кошь, /ˈmokəʂ/. | +| **Resonance (suggested, not prescriptive)** | The tool weaves session threads (video, DOM, events) into one artifact. Brand team is free to lean into or away from the etymology — it's a vessel, not a constraint. | + +--- + +## 2. The public display name *(OPEN — brand team)* + +`manifest.json:name` is whatever the brand team writes. The placeholder +shipping today is `"AI Call Recorder"` (a literal description from the +original Russian SPEC). Candidate directions, all equally on the table: + +- **Just `Mokosh`.** Most minimal; codename surfaces externally. +- **`Mokosh` + tagline lockup.** E.g. `Mokosh — Session Capture` or whatever the brand team writes. +- **Keep `"AI Call Recorder"` or similar literal descriptor.** Most discoverable in a Chrome extension list for non-internal viewers. +- **Bilingual lockup.** E.g. `"Mokosh / АИ Регистратор"` — addresses Russian-first audience explicitly. +- **Something entirely different the brand team coins.** + +Open question: does the display name need to make sense to a Russian-speaking +operator on first glance, or do operators get onboarded with the welcome tab +before they ever read the toolbar tooltip? + +--- + +## 3. The design system name *(OPEN — both teams)* + +Engineering needs *something* to call the visual language in design reviews +and docs. Options without ranking: + +| Option | Name | Tradeoffs | +|---|---|---| +| A | **Mokosh** (extends the product codename) | One brand to remember. Mirrors Stripe→"Stripe Design" pattern. Ties the visual language tightly to this one product. | +| B | A separate name coined by the design team (e.g. *Thread*, *Tracelight*, *anything*) | Lets the visual language travel beyond Mokosh if the org builds related operator tools. More naming overhead. | +| C | Generic descriptor (e.g. *Operator Design Language*, *Support Tooling DS*) | Functional. Forgettable. | +| D | No formal name at all — just "the Mokosh styles" | Pragmatic for a small system; defer naming until the system warrants it. | + +--- + +## 4. The blurb *(OPEN — brand team)* + +Sketches below are conversation starters, not recommendations. Write fresh +if none of these land. Brand team owns the final word. + +### One-liner — ≤ 12 words + +Used in `manifest.json:description`, Chrome Web Store thumbnail (if ever +published), welcome-tab subtitle. + +- *"One click. The last 30 seconds, packaged."* +- *"Self-contained bug reports for operator workflows."* +- *"Capture what happened. Send it. Move on."* +- *"Quietly recording so you don't have to."* +- *(or anything else)* + +### Short blurb — 2–3 sentences + +Used on the welcome tab hero, internal one-pagers, README top. + +**Sketch A (operator-first framing):** +> Mokosh sits quietly in your Chrome toolbar and remembers the last 30 seconds +> of video, the last 10 minutes of page state, and the last 10 minutes of user +> input — at all times. When something breaks, one click packs it all into a +> single archive that support can open immediately. No server. No waiting. + +**Sketch B (support-first framing):** +> Mokosh turns operator bug reports into something support engineers can +> actually reproduce. A continuous in-browser ring buffer captures video, DOM +> state, and user input; one click bundles it into a self-contained ZIP that +> opens locally with no infrastructure required. + +**Sketch C (write your own).** + +### Long blurb — one paragraph + +Sketch for the welcome tab and one-pagers. Treat as a strawman. + +> The hardest part of fixing an operator's bug is not the fix — it's +> reconstructing what they were looking at when it happened. Mokosh closes +> that gap. It runs as a background recorder that the operator never has to +> think about: thirty seconds of screen video, ten minutes of page state, and +> ten minutes of mouse-and-keyboard activity are always in memory, ready to +> ship. When a bug strikes, the operator clicks once and walks away. Support +> opens the resulting archive locally — no upload, no server, no third party, +> no password leakage — and replays exactly what the operator saw, in their +> own browser, frame for frame. + +--- + +## 5. Voice / tone / register *(OPEN — brand team)* + +Engineering has no opinion. A few axis questions to help frame the decision: + +- **Warmth** — clinical / neutral / warm / friendly +- **Formality** — system-message terse / professional / conversational / casual +- **Humour** — none / dry / occasional / playful +- **Emoji policy** — never / functional only (✓ × ⚠) / freely +- **Punctuation** — sentence case + periods, all lowercase no punctuation, headline case, or other +- **Two-register or single-register?** — does toolbar/notification copy share voice with welcome-tab copy, or do they diverge (system-message-ish for chrome surfaces, full-prose for onboarding)? + +Optional inspiration anchors — pick any, none, or replace: + +- **Linear, Loom, Notion AI, Duolingo, Salesforce, Stripe, Intercom, your-own-reference-here.** + +--- + +## 6. Visual language *(OPEN — design team)* + +Engineering currently ships placeholders. Every choice below is open. + +### Palette + +Current placeholder direction: dark-mode-native, monochrome with a single +saturated accent for "recording" state. **This is one of many possible +directions** — alternatives include: + +- Light-mode primary with dark-mode variant +- Multi-accent (separate colors for record / save / error states beyond just green/yellow/red) +- Warm/earthy (browns, ochres, off-whites) +- Cool/clinical (blues, grays, white) +- High-contrast monochrome (pure black/white + one accent) +- Whatever the design team coins + +Technical floor (not creative): the toolbar badge supports text + a background +color via `chrome.action.setBadgeBackgroundColor` — color encodes state there. +That's a mechanism, not a palette constraint. + +### Corner radii + +Current placeholder direction: sharp (2–4 px). Equally valid: pillow-rounded +(8–16 px), mixed (sharp containers + rounded controls), fully circular for +chips and badges, or any combination. Design team owns. + +### Typography + +Current placeholder direction: system stack (`-apple-system, "Segoe UI", +Roboto, "Noto Sans", sans-serif`) — chosen for zero-load and Cyrillic +coverage. Equally valid: custom face (Inter, IBM Plex Sans, JetBrains Mono, +or anything the design team licenses), variable font, type pairs. + +**Technical floor:** the chosen face(s) must render Cyrillic correctly +(Russian operators are primary) and must not block the MV3 service worker +(no remote `@font-face` from external CDNs — bundle locally if non-system). + +### Iconography + +Current placeholder direction: solid-filled, 24 px grid, neutral mark + state +via badge (the toolbar icon itself doesn't change between idle/recording — +the badge does). Equally valid: line-only, mixed (solid for primary + +line for secondary), per-state icon swaps via `chrome.action.setIcon`, +animated icons, illustrated mark. + +**Technical floor:** sized PNGs at 16, 48, 128 px (the 128 px is required for +`chrome.notifications.create`); minimum file size floors per +`assets-spec.md` so Chrome doesn't silently reject. + +### Motion + +Current placeholder direction: minimal — 200–300 ms opacity/transform fades, +no bounce, no entrance animations on notifications. Equally valid: more +expressive (spring-based), or completely static (no transitions at all). + +### Welcome-tab layout + +Open. Could be hero + 3-step explainer, a single-column scrolling story, a +modal dialog, a video walkthrough, anything. No engineering preference. + +--- + +## 7. Hard technical constraints (these are not creative) + +These are floors imposed by Chrome MV3 and the deployment surface. Not +brand decisions: + +- Manifest V3 CSP forbids `unsafe-eval` and remote scripts (no CDN web fonts that hot-load at runtime) +- Notification icons must be ≥ 128 px PNG, with file sizes above silent-rejection floors (see `assets-spec.md`) +- Toolbar icons required at 16 / 48 / 128 px +- Cyrillic glyph coverage required for the chosen typeface(s) +- Service worker has no DOM — any visual surface lives in popup, offscreen doc, or content-script-injected DOM +- Welcome tab opens via `chrome.tabs.create` on install — must be a static HTML/CSS/JS page in `dist/` + +--- + +## Any other notes? + +Engineering's working sketch is intentionally restrained — dark backgrounds, +sharp corners, system fonts, one accent color, near-zero motion — because the +product promise is *unobtrusiveness for operators under stress*. **That said, +none of this is brand direction; it's just what engineering picked when no +designer was in the room.** If the design and brand teams land on something +warmer, more playful, more illustrative, or stylistically different in any +direction, engineering will rewire to it. The placeholder palette and +mechanics in `design-system.md` exist so the extension *runs*, not because +they're right. + +**Before producing anything, please read these two specs in the same folder — +they're the inventory of what currently ships and the technical floors you +have to work within:** + +1. **`design-system.md`** — engineering's current visual sketch (color tokens, type stack, components, motion). Treat the *aesthetic content* as draft you can override; treat the *technical content* (Chrome API mechanics, MV3 CSP, badge mechanics) as floor. +2. **`assets-spec.md`** — concrete file deliverables: paths, dimensions, file-size floors, formats, three pathway options (auto-placeholder / design-first / commission) per asset. + +If anything in this brief or those specs conflicts with the direction the +teams land on, **the teams win** for creative decisions and the **specs win +for technical floors** (file sizes, Chrome API minimums, MV3 limits). Flag +any conflict and we'll resolve it together. + +--- + +## Open creative questions (non-exhaustive) + +For both teams to work through in whichever order makes sense. None are +blocking engineering today (placeholders ship), but each unlocks a polish +pass when answered. + +1. Display name policy — keep `"AI Call Recorder"`, switch to `"Mokosh"`, coin something new, or run a bilingual lockup? +2. Design system name — option A/B/C/D from §3, or other? +3. Localization defaults — Russian-first `manifest.json` with English override, or English-first with Russian override? +4. Voice register — one tone across all surfaces, or two (system-terse vs welcome-prose)? +5. Palette — keep monochrome-with-accent direction, or shift to multi-accent / warm / clinical / other? +6. Corner radii — sharp / soft / mixed? +7. Typography — system stack or custom face? If custom, what? +8. Iconography style — solid / line / mixed? Per-state icon swaps or fixed mark + dynamic badge? +9. Motion vocabulary — minimal, expressive, or none? +10. Welcome-tab layout — hero+steps, scrolling story, modal, video walkthrough, or other? +11. Hero treatment for the welcome tab — wordmark-only, mark+wordmark, or illustrative scene? + +--- + +## Related + +- `design-system.md` — engineering's current visual sketch (override at will) +- `assets-spec.md` — file deliverables + technical floors +- `manifest.json` — where the display-name decision lands +- `.planning/PROJECT.md` — engineering-level product framing (audience, technical constraints) diff --git a/.planning/intel/design-system.md b/.planning/intel/design-system.md index 9addcf3..1b83318 100644 --- a/.planning/intel/design-system.md +++ b/.planning/intel/design-system.md @@ -1,173 +1,229 @@ # Mokosh Design System -Cross-phase visual + interaction language for the Mokosh extension (user-facing -name "AI Call Recorder", internal codename "Mokosh"). Authored 2026-05-17 in -response to Plan 01-09's notification-icon discovery that the original -placeholder PNGs (`icons/icon{16,48,128}.png` at 79/123/306 bytes) fail Chrome's -notification API. Surfaces the visual decisions so any contributor (you, an -agent, a future designer) can produce assets that fit the same language. +Cross-phase visual + interaction reference for the Mokosh extension (internal +codename "Mokosh"; public display name currently `"AI Call Recorder"` — +open per `brand-identity.md`). Authored 2026-05-17 in response to Plan 01-09's +notification-icon discovery that the original placeholder PNGs failed Chrome's +notification API. -Status: `draft` — first iteration; expect amendments as actual designs surface. +**This file mixes two kinds of content** and the design team should treat them +differently: + +1. **Engineering sketches** — what the extension currently ships in placeholder + builds (colors, fonts, sizes, voice). These exist so the extension *runs*; + they are not direction. Override anything aesthetic. +2. **Technical floors** — what Chrome MV3, the notification API, MV3 CSP, or + WCAG accessibility require. These are binding regardless of creative + direction. Marked explicitly with **(FLOOR)** wherever they appear. + +Status: `draft` — engineering sketch + binding floors. Both design and brand +teams have full authority over everything not marked **(FLOOR)**. --- -## 1. Brand voice +## What's locked vs what's open -**Mokosh is an operator's silent helper.** It records continuously, surfaces -itself only when needed, and stays out of the operator's way the rest of the -time. The visual identity should reflect that: +| Decision | Status | +|---|---| +| Codename **"Mokosh"** | **LOCKED** (engineering — wired through code) | +| Public display name | OPEN (brand team) | +| All color hexes + token names | OPEN (design team) | +| Typography face(s) and scale | OPEN (design team) — must cover Cyrillic, must bundle locally **(FLOOR)** | +| Iconography style + mark concept | OPEN (design team) — must ship at 16/48/128 px PNG with file-size floors **(FLOOR)** | +| Spacing scale, corner radii, motion | OPEN (design team) | +| Brand voice, tagline, copy | OPEN (brand team) | +| Welcome-tab layout + treatment | OPEN (design team) | +| WCAG AA contrast | **FLOOR** (legal/accessibility — not creative) | +| Chrome notification API icon ≥ 128 px | **FLOOR** | +| MV3 CSP (no remote fonts/scripts, no `unsafe-eval`) | **FLOOR** | +| Toolbar badge text max 4 chars | **FLOOR** (Chrome truncates) | +| Russian-first audience | **FLOOR** (product, not visual) — visuals must work without depending on language for legibility | -- **Quietly competent.** Not playful, not flashy. Dependable industrial. -- **Diagnostic, not decorative.** Every visual choice serves an operator goal: - is recording active? did the bug get captured? where do I click to save? -- **Low chrome, high clarity.** When the extension is invisible (recording - silently), it should genuinely be invisible. When it shows itself (badge, - notification, popup), it should be unambiguous about state. -- **Russian-first wording, internationally legible visuals.** Operators read - Russian (per SPEC). Visuals must not depend on any language for legibility — - symbols + color + position carry meaning. - -Anti-patterns to avoid: -- Animated icons that draw attention during normal operation -- Decorative imagery in a tool that should fade into background -- Brand-marketing tone in operator-facing copy ("Hi there!", emojis) -- Color-only state indication (must pair color with text/shape) +Everything below is engineering's current sketch, framed as starting options, +unless explicitly tagged **(FLOOR)**. --- -## 2. Identity +## 1. Brand voice *(OPEN — brand team)* + +Engineering has no opinion. Axes to decide: + +- **Warmth** — clinical / neutral / warm / friendly +- **Formality** — system-terse / professional / conversational / casual +- **Humour** — none / dry / occasional / playful +- **Emoji policy** — never / functional only (✓ × ⚠) / freely +- **Two-register vs single-register** — toolbar/notification copy can match welcome-tab copy, or diverge (e.g. terse system messages vs full-prose onboarding) + +Engineering's current placeholder voice in shipped strings is *calm, brief, +operationally serious* — chosen because the product runs for operators under +stress. This is a defensible starting point and equally defensible to replace +entirely. + +--- + +## 2. Identity *(OPEN except codename)* | | | |---|---| -| Codename | Mokosh — Slavic goddess of fate, weaving, and the earth | -| User-facing display name | "AI Call Recorder" (Russian-speaking operator-tool name) | -| Tagline candidates (TBD) | "Записывает, чтобы вы могли воспроизвести." ("Records so you can reproduce.") | -| Mark concept | A thread/spool/weave motif evokes the codename without overpowering. Alternative: a simple recording dot inside a frame, more conventional. **Decision deferred** — see Section 10. | +| Codename **(LOCKED)** | Mokosh — Slavic goddess of weaving and fate | +| Public display name *(OPEN — brand)* | Currently placeholder `"AI Call Recorder"`. See `brand-identity.md` §2 for options. | +| Tagline *(OPEN — brand)* | Currently placeholder `"Записывает, чтобы вы могли воспроизвести."` ("Records so you can reproduce.") Replace, translate, or drop. | +| Mark concept *(OPEN — design)* | See §5 below — engineering sketches one possible direction; design team picks from anything. | --- -## 3. Color tokens +## 3. Color *(OPEN — design team)* -All extension surfaces draw from this palette. Color values are RGB; CSS -variable names are how implementation references them. +Engineering currently ships the placeholder palette below so the extension +runs. **Every hex is open. Every token name is open. The whole palette +strategy is open.** -### 3.1 Semantic state (operator-visible) +### 3.1 Engineering's current placeholder palette -| Token | Hex | Use | +| Token | Hex | Currently used for | |---|---|---| -| `--mks-rec` | `#00C853` | Recording active. Match `BADGE_REC_COLOR` in src/background/index.ts. Material Green A700; widely recognised "go/record" affordance. | -| `--mks-off` | `#9E9E9E` | Idle / not recording. Neutral gray, not red (red implies error). Material Gray 500. | -| `--mks-error` | `#FFB300` | Recoverable error (codec failure, buffer empty, etc.). Match `BADGE_ERROR_COLOR`. Material Amber 600 — caution not catastrophe. | -| `--mks-fatal` | `#D32F2F` | Unrecoverable state (rare). Material Red 700. | - -**Accessibility constraint:** All four colors must meet WCAG AA 4.5:1 contrast -when paired with their badge text color. White text on `--mks-rec` and -`--mks-fatal`; black text on `--mks-off` and `--mks-error`. - -### 3.2 UI surfaces - -| Token | Hex | Use | -|---|---|---| -| `--mks-surface-bg` | `#222222` | Smoke-test page background (current); also acceptable for popup dark mode | +| `--mks-rec` | `#00C853` | Toolbar badge background when recording (Material Green A700) | +| `--mks-off` | `#9E9E9E` | Toolbar badge background when idle | +| `--mks-error` | `#FFB300` | Toolbar badge background on recoverable error (Material Amber 600) | +| `--mks-fatal` | `#D32F2F` | Toolbar badge background on unrecoverable state (Material Red 700) | +| `--mks-surface-bg` | `#222222` | Smoke-test page / dark popup surfaces | | `--mks-surface-text` | `#EEEEEE` | Text on dark surfaces | -| `--mks-surface-code` | `#444444` | Inline code background (dark theme) | | `--mks-popup-bg-light` | `#FFFFFF` | Popup background, light Chrome theme | | `--mks-popup-bg-dark` | `#1F1F1F` | Popup background, dark Chrome theme | -| `--mks-popup-fg-light` | `#202124` | Popup text, light theme (matches Chrome's Material 3) | -| `--mks-popup-fg-dark` | `#E8EAED` | Popup text, dark theme | +| `--mks-diag-bg` / `--mks-diag-fg` | `#000000` / `#00FF00` | Smoke-test timer overlay (dev-only — keep monospace + high-contrast for legibility, but recolor freely) | -### 3.3 Diagnostic / dev-only +### 3.2 Palette directions for the design team to choose from -| Token | Hex | Use | -|---|---|---| -| `--mks-diag-bg` | `#000000` | Smoke-test timer overlay background | -| `--mks-diag-fg` | `#00FF00` | Smoke-test timer overlay text (high-contrast monospace) | +Direction matters more than specific hexes. Options without ranking: + +- **Dark-mode-native, monochrome + single accent for "recording"** (current placeholder) +- **Light-mode primary with dark-mode variant** +- **Multi-accent** — separate distinguishing color per state beyond just green/yellow/red +- **Warm / earthy** — browns, ochres, off-whites +- **Cool / clinical** — blues, grays, white +- **High-contrast monochrome** — pure black/white + one accent +- **Whatever the design team coins** + +### 3.3 Mechanical hooks the palette has to fill + +(Not creative — these are surfaces engineering wires colors into.) + +- `chrome.action.setBadgeBackgroundColor(...)` — one color per toolbar badge state +- Popup background + text (two themes if supporting both Chrome light/dark) +- Welcome-tab background + text +- Smoke-test diagnostic overlay (dev-only — design team can ignore) + +If the design team lands on N states beyond recording/idle/error, engineering +adapts the badge wiring. --- -## 4. Typography +## 4. Typography *(OPEN — design team, with one floor)* -**System fonts only.** No web-font loads — keeps the extension CSP simple and -load-time near-zero. Falls back gracefully on every OS. +Engineering ships system stack as a placeholder. Open to replacement. -| Family token | Stack | Use | +### 4.1 Technical floor **(FLOOR — KEEP)** + +- **Must cover Cyrillic glyphs.** Russian operators are primary. Latin-only faces are non-starters. +- **Must bundle locally.** MV3 CSP forbids remote `@font-face` from external CDNs. Any custom face ships as a static asset in `dist/`. +- **Should not block the service worker.** The SW has no DOM and renders no text; this only matters for popup + welcome. + +### 4.2 Engineering's current placeholder stack + +| Family token | Stack | Currently used for | |---|---|---| -| `--mks-font-ui` | `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif` | All UI text (popup, welcome page, notifications-rendered-as-pages) | +| `--mks-font-ui` | `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif` | All UI text | | `--mks-font-mono` | `"SF Mono", Menlo, Consolas, "Courier New", monospace` | Diagnostic overlays, code, timer | -### 4.1 Type scale +Chosen for zero-load, no FOUT, automatic Cyrillic coverage on every OS. +**Equally valid:** a licensed custom face (Inter, IBM Plex Sans, JetBrains +Mono, or anything), variable fonts, a type pair, a different system fallback +chain. -| Token | Size | Line-height | Use | +### 4.3 Engineering's current type scale (placeholder) + +| Token | Size | Line-height | Currently used for | |---|---|---|---| -| `--mks-text-xs` | 11px | 1.3 | Badge labels, status pills, footnotes | -| `--mks-text-sm` | 13px | 1.4 | Secondary UI text, captions | -| `--mks-text-base` | 15px | 1.5 | Body text, popup messages, notification body | +| `--mks-text-xs` | 11px | 1.3 | Badge labels, footnotes | +| `--mks-text-sm` | 13px | 1.4 | Secondary UI text | +| `--mks-text-base` | 15px | 1.5 | Body text | | `--mks-text-lg` | 18px | 1.4 | Section headings within popup | -| `--mks-text-xl` | 24px | 1.3 | Welcome page H1, primary call-to-action | -| `--mks-text-xxl` | 32px | 1.2 | Diagnostic timer (smoke), large status | +| `--mks-text-xl` | 24px | 1.3 | Welcome page H1 | +| `--mks-text-xxl` | 32px | 1.2 | Diagnostic timer, large status | -### 4.2 Weights +Replace freely. Modular scale, fluid type, t-shirt sizes — design team picks. -- 400 (regular): all body text -- 500 (medium): UI labels, badge text -- 700 (bold): primary CTAs, status indicators (REC/OFF/ERROR) +### 4.4 Engineering's current weight ladder (placeholder) -Avoid 600 / italic — keep the weight ladder tight. +- 400 (regular), 500 (medium), 700 (bold) + +Replace freely. --- -## 5. Iconography +## 5. Iconography *(OPEN — design team, with floors)* -### 5.1 Style +### 5.1 Technical floors **(FLOOR — KEEP)** -- **Solid filled** (not outline). Solid icons read better at 16px/48px sizes - where extension icons live; outline detail is lost at small sizes. -- **24×24 source grid** with 2px padding (effective icon area 20×20). Standard - Material/Apple icon-grid convention; ensures consistent visual weight. -- **Single accent color or two-tone max.** Reserve color complexity for badges - and notifications. +- Sized PNGs at **16, 48, 128 px** in `dist/icons/`, declared in `manifest.json:icons` and `manifest.json:action.default_icon` +- The **128 px is required** for `chrome.notifications.create({type:'basic'})` to render an iconUrl +- File-size minimums per `assets-spec.md` (Chrome silently rejects icons below ~200 B / 500 B / 1 KB at the three sizes) +- Optional 192 px variant for hi-DPI notification rendering +- Inline SVG preferred for popup/welcome surfaces where Chrome permits — sharper at all DPIs. Chrome's `notifications.create` REQUIRES PNG `iconUrl` though. -### 5.2 Mark concept (action.default_icon) +### 5.2 Engineering's current placeholder direction -The extension's primary mark serves 3 roles simultaneously: -- Browser toolbar icon (16/32 — tiny; needs immediately-readable silhouette) -- Extensions page icon (48 — moderate; can carry a bit more detail) -- Chrome Web Store + notification icon (128 — full detail) +Solid-filled, 24×24 source grid with 2 px padding, neutral mark + state via +badge (the toolbar icon itself doesn't change between idle/recording — the +`chrome.action.setBadgeBackgroundColor` does the state work). -**Recommended motif: a "recording dot inside a thread spool / frame".** A -red-or-green circle inside a hexagonal/circular frame. Reads as: "this thing -records." The frame nods at the Mokosh "weaving" theme without literally -showing thread (which would be unreadable at 16px). +**This is one of many possible directions.** Equally valid: -Alternative (cleaner, more conventional): just a filled red circle with a thin -white inner ring — looks like a record button, no thematic baggage. Slightly -less distinctive but immediately understood. +- Line-only icons +- Mixed (solid for primary, line for secondary) +- Per-state icon swaps via `chrome.action.setIcon` (adds perf cost — see §7) +- Animated SVG icons +- Illustrated mark (full scene rather than abstract glyph) -**Color in the mark:** the mark uses `--mks-rec` (green) when REC overlay would -be added by Chrome's badge anyway, OR a neutral mark with state communicated -purely via badge. Recommended: **neutral mark, state via badge.** Keeps the -icon recognizable across all states. +### 5.3 Mark concept *(OPEN — design team)* -### 5.3 Inline glyphs +Engineering's current placeholder is "dark square + green dot" via +ImageMagick. **No mark direction is implied.** Possible directions: -For popup and welcome page: +- Recording-dot inside a frame (conventional, immediately readable as "records") +- Thread/spool/weave motif (leans into the Mokosh etymology) +- Abstract geometric mark (no figurative reference) +- Wordmark only (the letterforms are the mark) +- Illustrated mascot +- Whatever the design team coins -| Concept | Glyph | Notes | +Constraints: must resolve at 16 px (a strong silhouette is hard at that size), +must work neutral OR colored (depending on the team's badge-vs-icon-state +decision). + +### 5.4 Inline glyphs *(OPEN — design team)* + +The popup and welcome surfaces need glyphs for actions and states. Concepts +engineering currently shows: + +| Concept | Currently shown as | Design-team-owned | |---|---|---| -| Save / download | ⬇ filled-arrow-into-tray | 20px in popup | -| Stop | ■ filled-square | Reserved for explicit stop control (see Section 10) | -| Recording active | ● solid-circle in `--mks-rec` | Pulsing optional (see Section 7) | -| Error | ▲ filled-triangle with `!` | `--mks-error` background | -| Settings | ⚙ filled-gear | Reserved; not currently surfaced | -| Welcome / intro | 🧵 thread/spool emoji is currently used in smoke; replace with custom glyph at design time | +| Save / download | ⬇ filled-arrow-into-tray (Unicode, placeholder) | Replace with custom glyph or icon font | +| Stop | ■ filled-square (placeholder) | — | +| Recording active | ● solid-circle (placeholder) | — | +| Error | ▲ filled-triangle with `!` (placeholder) | — | +| Settings | ⚙ filled-gear (placeholder; not currently surfaced) | — | +| Welcome / intro | 🧵 thread emoji (smoke-test placeholder only) | Replace at design time | --- -## 6. Spacing +## 6. Spacing *(OPEN — design team)* -Base unit: **4px.** All spacing values are multiples of this base. +Engineering currently uses a **4 px base** with the steps below as +placeholders. Replace with any base (8 px, variable, t-shirt sizes, +golden-ratio, etc.). -| Token | Value | Use | +| Token | Value | Currently used for | |---|---|---| | `--mks-space-1` | 4px | Tight padding within badges | | `--mks-space-2` | 8px | Default padding inside controls | @@ -176,143 +232,159 @@ Base unit: **4px.** All spacing values are multiples of this base. | `--mks-space-6` | 24px | Welcome page section gaps | | `--mks-space-8` | 32px | Welcome page hero spacing | -### 6.1 Surface sizing +### 6.1 Surface sizing — current placeholders + technical floors -| Surface | Size | Notes | +| Surface | Engineering's placeholder | Floor / mechanism | |---|---|---| -| Popup default | 320×200 | Chrome auto-sizes; this is the comfortable target | -| Welcome page | full viewport, max-width 720px content column | Plan 01-10 | -| Notification | Chrome-controlled (basic type, ~360px wide) | iconUrl + title + message | -| Toolbar badge text | max 4 chars | Chrome truncates beyond | +| Popup | 320 × 200 (comfortable; Chrome auto-sizes) | Chrome popups auto-size; no hard max | +| Welcome page | full viewport, content max-width 720 px | None — fully open | +| Notification | Chrome-controlled (~360 px wide) | **(FLOOR)** — not styleable | +| Toolbar badge text | max 4 chars | **(FLOOR)** — Chrome truncates beyond | --- -## 7. Motion +## 7. Motion *(OPEN — design team)* -Conservative. Motion draws attention; the extension should draw attention only -on state change. +Engineering currently ships near-zero motion (200–300 ms opacity fades, no +bounce) because the product promise is unobtrusiveness. **Equally valid:** -| Motion | Duration | Easing | Use | +- Lively spring physics +- Fully static (no transitions at all) +- Cinematic entrances on welcome +- Subtle micro-interactions on every state change + +Engineering's current placeholder durations: + +| Where | Duration | Easing | Notes | |---|---|---|---| | Hover transitions | 150ms | `ease-out` | Buttons, links | -| Badge state change | instant | — | REC/OFF/ERROR transitions; no animation | -| Recording pulse (optional) | 1000ms loop | `ease-in-out` | Subtle 0.85→1.0 opacity loop on REC badge if surface allows. Currently used in smoke `.flash` class — adopt for badge if Chrome's badge API allows (it doesn't natively; would need an action.setIcon swap on interval, which has perf cost — recommend OFF for now). | -| Notification slide | Chrome default | — | We don't control | -| Welcome page CTA hover | 200ms | `ease-out` | Background-color + scale 1.0→1.02 | +| Badge state change | instant | — | No animation (Chrome badge API doesn't support; setIcon swap interval would cost perf) | +| Welcome page CTA hover | 200ms | `ease-out` | Background-color + slight scale | +| Notification slide | Chrome default | — | **(FLOOR)** — not controllable | + +Per-state icon swap animation (e.g. recording-pulse) is possible but adds +`setIcon` interval cost; design team picks if worth it. --- ## 8. Component conventions -### 8.1 Toolbar action (chrome.action) +Two layers per component: **functional contract** (KEEP — comes from PLAN, +not creative direction) and **visual treatment** (OPEN — design team). -States: -- **Idle** — neutral mark, badge text empty (or `""`), background transparent -- **REC** — neutral mark + badge text `"REC"` + background `--mks-rec` -- **ERROR** — neutral mark + badge text `"ERR"` + background `--mks-error` -- **OFF** (post-stop, awaiting restart) — neutral mark + badge text `"OFF"` + background `--mks-off` +### 8.1 Toolbar action (`chrome.action`) -Tooltip (`chrome.action.setTitle`) communicates current state in Russian: -- Idle: "Mokosh — щёлкните, чтобы начать запись" -- REC: "Mokosh — идёт запись (00:42)" (with live duration) -- ERROR: "Mokosh — ошибка записи, щёлкните для восстановления" -- OFF: "Mokosh — запись остановлена, щёлкните, чтобы начать снова" +**Functional contract (KEEP):** +- Three states surface to operators: IDLE, REC, ERROR (some teams add OFF as a distinct post-stop state) +- Click behavior depends on state — IDLE click starts recording; REC click opens SAVE popup; ERROR click opens RESTART popup +- Tooltip text changes per state via `chrome.action.setTitle` + +**Visual treatment (OPEN):** +- Badge background color per state (currently mapped to `--mks-rec` / `--mks-off` / `--mks-error`) +- Badge text per state (currently `""` / `"REC"` / `"ERR"` / `"OFF"`) +- Tooltip wording (currently Russian, placeholder copy below — brand team rewrites) + - IDLE: `"Mokosh — щёлкните, чтобы начать запись"` + - REC: `"Mokosh — идёт запись (00:42)"` + - ERROR: `"Mokosh — ошибка записи, щёлкните для восстановления"` ### 8.2 Notification -Use `chrome.notifications.create` with `type: 'basic'`: +**Functional contract (KEEP):** +- Fired via `chrome.notifications.create({type:'basic', iconUrl, title, message, priority})` +- `iconUrl` must be a ≥128 px PNG via `chrome.runtime.getURL` **(FLOOR)** +- Fires on startup (until operator dismisses), on recovery (after user-stopped-sharing), optionally on save-complete (Phase 5 candidate) +- One notification per state transition (no spam) -```js -{ - type: 'basic', - iconUrl: chrome.runtime.getURL('icons/icon128.png'), // hi-res required - title: 'Mokosh', // short, branded - message: 'Recording started.' | 'Recording stopped.' | etc., // Russian - priority: 1, // default; 2 only for urgent -} -``` +**Visual treatment (OPEN):** +- Title text (currently `"Mokosh"`) +- Message text (brand team rewrites) +- `priority` (1 default, 2 for urgent — design team can pick when to escalate) -Notifications fire on: -- Startup prompt (every Chrome session) — until operator clicks once -- Recovery prompt (after user-stopped-sharing) — once -- Save complete (optional acknowledgement) — Phase 5 candidate +### 8.3 Popup (current scope: SAVE-only per Plan 01-09) -Avoid notification spam — at most one notification per state transition. +**Functional contract (KEEP):** +- Represents the current toolbar state (REC / ERROR; IDLE shouldn't normally surface here) +- REC state offers a single primary action: save the buffered archive +- ERROR state offers a single primary action: restart recording +- No secondary actions in either state (Plan 01-09 scope decision) -### 8.3 Popup (SAVE-only per Plan 01-09) - -- Compact: 320×200 max -- Single primary CTA: "Сохранить отчёт об ошибке" (full-width) -- Status line above CTA: "Запись активна, последние 30 сек захвачены" -- Footer: small text with recording duration ("XX:XX") for trust -- No secondary actions in REC mode -- ERROR mode: replace CTA with restart-recording action; status line shows - error reason +**Visual treatment (OPEN):** +- Sizing (current placeholder 320 × 200) +- CTA wording (current placeholder Russian; brand team rewrites) +- Layout (CTA position, status line, footer) +- Status messaging copy +- Dark/light theme handling (current placeholder: auto via `prefers-color-scheme`) ### 8.4 Welcome page (Plan 01-10) -- Full viewport, dark theme matching `--mks-popup-bg-dark` -- Hero: large mark + name + 1-line tagline -- Body: 2-3 short bullets explaining what Mokosh does (operator-readable Russian) -- Primary CTA: "Начать запись" button — large, `--mks-rec` background, white text -- Footer: privacy note ("Mokosh записывает только ваш экран; данные остаются у вас") +**Functional contract (KEEP):** +- Opens via `chrome.tabs.create` on first install +- Static HTML/CSS/JS in `dist/` (no remote loads **(FLOOR)**) +- Must communicate: what Mokosh does, how the operator triggers a save, privacy story + +**Visual treatment (OPEN — design team owns entirely):** +- Layout (hero + steps, scrolling story, modal, video walkthrough, anything) +- Tone (welcome cheer vs sober briefing — brand team) +- Hero treatment (wordmark-only, mark + wordmark, illustrated scene, video) +- Primary CTA wording + placement +- Whether there's a CTA at all (some onboarding flows just inform) --- -## 9. Accessibility & internationalization +## 9. Accessibility & internationalization *(FLOORS — KEEP)* -- **Contrast:** WCAG AA (4.5:1 normal, 3:1 large text). All semantic-state - pairings pre-validated above. -- **Focus:** visible focus rings on all interactive elements (popup buttons, - welcome page CTA). Use Chrome's default `outline: 2px solid auto`. -- **Color-independence:** every color-coded state pairs with text (REC/OFF/ERR - badge labels; never color alone). -- **Localization:** all user-facing strings are Russian per SPEC. UI scaffolding - must support future English/other-locale strings via standard Chrome - `_locales/` mechanism (deferred — no MVP requirement). -- **Reduced motion:** if recording-pulse animation is ever enabled (see §7), - honor `prefers-reduced-motion: reduce` by falling back to static. +These are functional/legal floors, not creative: + +- **Contrast: WCAG AA** (4.5:1 normal text, 3:1 large text). Any palette the design team lands on must validate against this for all state pairings. Engineering's current placeholder palette is pre-validated; new palettes need re-validation. +- **Focus indicators:** visible focus rings on all interactive elements (popup buttons, welcome CTA). Chrome's default `outline` works; custom focus styles welcome as long as they remain visible. +- **Color-independence:** every color-coded state must pair with text or shape. Color alone is not an accessible state indicator — pairs with badge labels, glyphs, or copy. +- **Russian-first localization:** all user-facing strings ship in Russian as the default locale. UI scaffolding must support future locales via Chrome's `_locales/` mechanism. +- **Reduced motion:** if any animation is enabled, honor `prefers-reduced-motion: reduce` by falling back to static. --- -## 10. Open design decisions +## 10. Open creative decisions -These are visual choices that need a human design pass before locking: +Non-exhaustive list for both teams. None block engineering today +(placeholders ship); each unlocks a polish pass when answered. -| # | Question | Default if undecided | -|---|---|---| -| ODD-1 | Mark concept: thread/spool motif OR clean record-button | Clean record-button (faster to produce; recognizable; no thematic risk) | -| ODD-2 | Pulsing REC badge animation | OFF (Chrome badge API doesn't support; would need setIcon interval; perf cost) | -| ODD-3 | Tagline final wording | "Записывает, чтобы вы могли воспроизвести." (above) | -| ODD-4 | Welcome page hero illustration | None — type-only hero | -| ODD-5 | Notification iconUrl: same as toolbar mark OR distinct? | Same — operator should recognise the source | -| ODD-6 | Dark/light theme detection in popup | Auto via `prefers-color-scheme` (uses Chrome theme by default) | +1. Public display name (`brand-identity.md` §2) +2. Design system name (`brand-identity.md` §3) +3. Voice register — one tone or two (system-terse vs welcome-prose) +4. Tagline final wording (currently `"Записывает, чтобы вы могли воспроизвести."`) +5. Palette direction (§3.2) + specific hexes +6. Token naming convention (`--mks-rec` placeholder pattern) +7. Typography face(s) — system stack vs custom +8. Type scale + weight ladder +9. Spacing base + steps +10. Corner radii — sharp / soft / mixed +11. Iconography style — solid / line / mixed +12. Mark concept (§5.3) +13. Per-state icon swaps vs fixed mark + dynamic badge +14. Motion vocabulary — minimal / lively / static +15. Welcome-tab layout + treatment (§8.4) +16. Popup layout treatment (§8.3 visual) +17. Notification copy + tone (§8.2) +18. Tooltip wording per state (§8.1) +19. Dark/light theme strategy — auto-detect, follow-Chrome, force one, user-toggle --- -## 11. Implementation notes +## 11. Implementation notes *(TECHNICAL — KEEP)* -- All extension contexts (SW, offscreen, popup, welcome page) share the same - CSP. No external font/asset loads. Everything bundled or `chrome.runtime.getURL`. -- Icons must be in `dist/icons/` and declared in both `manifest.json` `icons` - AND `action.default_icon`. -- Notification iconUrl uses `chrome.runtime.getURL('icons/icon128.png')` — at - least 128×128, ideally 192×192 for retina. Smaller icons silently fail - Chrome's `imageUtil` validation. -- All popup HTML/CSS lives in `src/popup/`. All welcome HTML/CSS lives in - `src/welcome/` (Plan 01-10). -- Inline SVG preferred over PNG where the surface permits — sharper at all - DPIs. Chrome's notification API REQUIRES PNG iconUrl though. +- All extension contexts (SW, offscreen, popup, welcome page) share the same CSP. No external font/asset loads. Everything bundled or `chrome.runtime.getURL`. **(FLOOR)** +- Icons must be in `dist/icons/` and declared in both `manifest.json:icons` AND `manifest.json:action.default_icon`. **(FLOOR)** +- Notification iconUrl uses `chrome.runtime.getURL('icons/icon128.png')` — at least 128 × 128, ideally 192 × 192 for retina. Smaller icons silently fail Chrome's `imageUtil` validation. **(FLOOR)** +- All popup HTML/CSS lives in `src/popup/`. All welcome HTML/CSS lives in `src/welcome/` (Plan 01-10). **(file convention — easy to change)** +- Inline SVG preferred over PNG where the surface permits — sharper at all DPIs. Notification API requires PNG. **(FLOOR for notification only)** --- ## 12. Related -- `assets-spec.md` — concrete deliverables list (specific files, sizes, formats) - derived from this design system +- `brand-identity.md` — naming + blurb + voice (Brief #1) +- `assets-spec.md` — concrete file deliverables + technical floors - `src/background/index.ts` — implements toolbar action + notification per §8 - `src/popup/index.html` — implements popup per §8.3 - `src/welcome/welcome.html` — implements welcome per §8.4 (Plan 01-10) -- `.planning/phases/01-stabilize-video-pipeline/01-CONTEXT.md` D-16-toolbar, - D-15-display-surface amendments — interaction model this design system - visually realises +- `.planning/phases/01-stabilize-video-pipeline/01-CONTEXT.md` D-15/D-16/D-17 amendments — interaction model this design language sits inside