Milestone v1.0: FamilySync MVP #1

Merged
luckberg merged 376 commits from gsd/v1.0-milestone into main 2026-06-10 17:39:19 -04:00
Showing only changes of commit 4b77ec0254 - Show all commits
+132
View File
@@ -317,6 +317,138 @@ All new surfaces must meet:
---
## Brand Assets & Iconography
Source: D-BRAND-01, D-BRAND-02 (locked user decisions, 2026-06-10).
In-app UI icons remain lucide-react — this section covers only the brand mark, app icons, and favicons.
### Mark: Glyph + Wordmark
**Concept (D-BRAND-01):** Two overlapping rounded shapes — circles or rounded rectangles — suggesting two members sharing a space (the family) or two overlapping calendar tiles. The overlap region is the accent color at full opacity; each outer shape is the accent color at reduced opacity (≈60%). The wordmark "FamilySync" sits to the right of the glyph in the lockup variant; the glyph alone is the source for all raster icons.
**Geometry / construction:**
- Two circles, each 40px diameter on a 64px × 64px artboard (SVG viewBox="0 0 64 64").
- Circle 1 center: (24, 32). Circle 2 center: (40, 32).
- Overlap: the intersection region formed by both paths.
- Rendering: use two `<circle>` elements with `fill-opacity="0.6"` for the individual shapes, then a `<clipPath>`-intersected shape (or a third overlapping path) at `fill-opacity="1"` for the overlap highlight.
- Wordmark: "FamilySync" set in the system-ui stack at 18px/600 in the lockup; the glyph and wordmark baseline-align.
**Color usage:**
| Surface | Glyph fill | Wordmark fill |
|---------|-----------|---------------|
| Light background (#FFFFFF) | #4A90D9 (accent) | #111318 (--color-text-primary) |
| Dark background (≥50% dark) | #FFFFFF | #FFFFFF |
| Monochrome (print / favicon .ico) | currentColor (#111318 on light, #FFFFFF on dark) — single flat shape, no opacity split |
**Clear space:** Minimum clear space = 1× the glyph diameter (64px on the 64px artboard, i.e. one full glyph-width on all four sides at actual render size).
**Minimum size:**
- Glyph-only: 24px × 24px rendered (below this, detail is lost; use the monochrome flat variant).
- Glyph + wordmark lockup: 120px wide minimum.
**Monochrome fallback:** A single filled shape representing both circles merged (union path), no opacity split. Used for favicon.ico and any single-color context.
### SVG Source-of-Truth Files
| File | Contents | Used as source for |
|------|----------|--------------------|
| `apps/pwa/src/assets/logo-glyph.svg` | Glyph only, viewBox="0 0 64 64", color-variable fills (`currentColor` + CSS custom property override) | All raster icon exports; in-app glyph-only placements |
| `apps/pwa/src/assets/logo-lockup.svg` | Glyph + "FamilySync" wordmark, viewBox="0 0 240 64" | Auth splash, header lockup (if present) |
| `apps/pwa/src/assets/logo-monochrome.svg` | Flat union-path glyph, single fill, viewBox="0 0 64 64" | favicon.ico source layer |
All SVG files: no embedded raster data, no `<image>` elements, path-only. Minified with no comments before commit.
### Raster Export Pipeline
Source: `apps/pwa/src/assets/logo-glyph.svg` (light-mode fill: #4A90D9 shapes on transparent background).
Export tool: any SVG-to-PNG renderer that preserves alpha (e.g. `sharp`, `Inkscape --export-png`, or `resvg`). A build-time script at `apps/pwa/scripts/export-icons.ts` (or equivalent Makefile target) must produce the full output list below from the SVG source — no manually-placed PNGs.
**Output list:**
| Output file | Size (px) | Format | Notes |
|-------------|-----------|--------|-------|
| `apps/pwa/public/icon-192.png` | 192×192 | PNG, RGBA | PWA manifest `any` icon |
| `apps/pwa/public/icon-512.png` | 512×512 | PNG, RGBA | PWA manifest `any` icon |
| `apps/pwa/public/icon-512-maskable.png` | 512×512 | PNG, RGBA | PWA manifest `maskable` icon — glyph centered in safe zone (see below) |
| `apps/pwa/public/apple-touch-icon.png` | 180×180 | PNG, RGB (no alpha), white background | iOS home screen; Apple ignores alpha |
| `apps/pwa/public/favicon-16.png` | 16×16 | PNG | favicon.ico source layer |
| `apps/pwa/public/favicon-32.png` | 32×32 | PNG | favicon.ico source layer |
| `apps/pwa/public/favicon-48.png` | 48×48 | PNG | favicon.ico source layer |
| `apps/pwa/public/favicon.svg` | — | SVG (copy of logo-glyph.svg) | Modern browsers; referenced as `<link rel="icon" type="image/svg+xml">` |
| `apps/pwa/public/favicon.ico` | 16+32+48 multi-res | ICO | Legacy browsers; bundle the three PNG layers into a single .ico using `png-to-ico` or equivalent |
Replace the three existing placeholder files (`icon-192.png`, `icon-512.png`, `apple-touch-icon.png`) with the real exports. The script must be idempotent (re-running overwrites all outputs).
### Maskable Safe Zone
The maskable icon specification requires the primary visual to fit within the center 80% of the canvas (the "safe zone"). For a 512×512 canvas, the safe zone is the inner 409×409 px centered region. The glyph export for `icon-512-maskable.png` must:
- Scale the glyph to fit within 409×409 (≈80% of 512).
- Center it on the 512×512 canvas.
- Fill the outer 10% bleed area with the PWA `background_color` (#FFFFFF) so masked shapes (squircle, circle) show a clean white surround rather than transparency artifacts.
Update `vite.config.ts` manifest `icons` array to reference `icon-512-maskable.png` for the `maskable` purpose entry (separate file from the `any` 512px icon):
```ts
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
{ src: '/icon-512-maskable.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
```
### Favicon Set — index.html Changes
Current state: `index.html` has only `<link rel="apple-touch-icon">` and no `<link rel="icon">`. This is a gap.
Add the following tags inside `<head>`, after the existing `apple-touch-icon` line:
```html
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
```
Keep the existing tags unchanged:
```html
<meta name="theme-color" content="#4A90D9" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="FamilySync" />
```
Browser resolution order: SVG favicon first (Chrome 80+, Firefox 41+, Safari 12+), ICO fallback for IE/legacy. No `favicon-32.png` link needed in HTML — the ICO multi-res bundle covers the same use case and reduces link clutter.
### In-App Logo Usage
| Surface | Variant | Size | Placement |
|---------|---------|------|-----------|
| Auth splash (Surface 1) | Glyph + wordmark lockup (`logo-lockup.svg`) | 120px wide (auto height ~32px) | Centered above the spinner stack; 24px gap below lockup, then spinner |
| Session-expired interstitial (Surface 2) | Glyph only (`logo-glyph.svg`) | 32×32px | Centered above spinner; same vertical stack as auth splash |
| App header / nav bar (if present) | Glyph only (`logo-glyph.svg`) | 24×24px | Leading slot of the top nav bar, 16px from left edge, vertically centered |
| PWA install prompt / about screen | Glyph + wordmark lockup | 160px wide | Centered |
Spacing tokens used: 24px gap (`--space-6`) between lockup and spinner on auth splash; 16px left inset (`--space-4`) for header placement. These are drawn from the established 8-point scale.
Color: render SVGs using CSS `color` inheritance where possible so light/dark mode automatically applies the correct fill. Set `fill="currentColor"` on all path elements in the SVG source; parent container sets `color: var(--color-text-primary)` (light) or `color: #FFFFFF` (dark overlay contexts such as auth splash over `--color-surface` — use `--color-text-primary` here since the background is white).
### Asset Manifest
| File path | Format | Size(s) | Purpose | Referenced in |
|-----------|--------|---------|---------|---------------|
| `apps/pwa/src/assets/logo-glyph.svg` | SVG | 64×64 viewBox | SVG source of truth — glyph only | Export script, in-app `<img>` or inline SVG |
| `apps/pwa/src/assets/logo-lockup.svg` | SVG | 240×64 viewBox | SVG source of truth — glyph + wordmark | Auth splash, install prompt |
| `apps/pwa/src/assets/logo-monochrome.svg` | SVG | 64×64 viewBox | Monochrome union-path variant | favicon.ico source |
| `apps/pwa/public/favicon.svg` | SVG | — | Modern browser favicon | `<link rel="icon" type="image/svg+xml">` in index.html |
| `apps/pwa/public/favicon.ico` | ICO | 16+32+48 multi-res | Legacy browser favicon | `<link rel="icon" type="image/x-icon">` in index.html |
| `apps/pwa/public/icon-192.png` | PNG (RGBA) | 192×192 | PWA manifest any icon | vite.config.ts manifest `icons` |
| `apps/pwa/public/icon-512.png` | PNG (RGBA) | 512×512 | PWA manifest any icon | vite.config.ts manifest `icons` |
| `apps/pwa/public/icon-512-maskable.png` | PNG (RGBA) | 512×512 | PWA manifest maskable icon | vite.config.ts manifest `icons` |
| `apps/pwa/public/apple-touch-icon.png` | PNG (RGB, white bg) | 180×180 | iOS home screen icon | `<link rel="apple-touch-icon">` in index.html |
| `apps/pwa/scripts/export-icons.ts` | TypeScript | — | Build-time raster export pipeline | `make icons` or equivalent |
---
## Registry Safety
| Registry | Blocks Used | Safety Gate |