Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ Left to itself, an AI agent tends to produce UI that *looks* AI-generated — ge
| **Design systems** | `generate_design_system`: one seed + one personality (`technical` / `editorial` / `soft` / `data-dense`) → the complete design language — colors, curated font pairing, typography roles, radius/density stances, `$elevation` depth tokens (dark-aware), `$motion` defaults · layered `$token`s (workspace ▸ project ▸ canvas) · style presets · `DESIGN.md` import · `generate_scale` derives a modular type + spacing scale from a named ratio (optional fluid `clamp()` sizes) · `generate_color_system` turns one seed color into OKLCH ramps + AA-checked semantic tokens, a categorical chart palette, and a tint layer for chips/tiles/badges, dark theme included · dual-theme rendering + evaluation (`theme: "dark"` on screenshot/export, both-theme contrast in `canvas_evaluate` with APCA advisory) · token-detachment lint re-attaches literals that drift from a token |
| **Primitives** | Lucide + Material Symbols icons · Google Fonts by name · real form controls · components with instance overrides — `create_component` promotes existing work, `copy_nodes` carries subtrees (and their component defs) across canvases |
| **Import from code** | `canvas_import_html` / `canvas_import_url` — token-mapped, structure-reconstructed · `canvas_sync_from_url` pixel drift · `canvas_check_drift` structural drift · `framesmith verify` / `check-drift` CLI for CI/pre-commit gates, no MCP client needed |
| **Viewer** | Browser gallery + detail view · quality inspector (score, issues, click-to-highlight) · design-system token panel · point-and-tell feedback (Comment mode + Feedback tab) |
| **Viewer** | Browser gallery + detail view · phone canvases in a device frame with a safe-area overlay · quality inspector (score, issues, click-to-highlight) · design-system token panel · point-and-tell feedback (Comment mode + Feedback tab) |
| **Open by design** | MIT · plain HTML/CSS · open JSON you own in your repo · content-hash versioning (`canvas_version`) so approvals reference an exact design, not just a name · works with any MCP-compatible client |

## Viewer

Run `npx -p framesmith framesmith-viewer` to start the standalone browser viewer (it takes the first free port from 3001 up; pass a port to pin one). Open any canvas to review it at multiple breakpoints, compare them side-by-side, inspect the underlying JSON, or archive / delete.
Run `npx -p framesmith framesmith-viewer` to start the standalone browser viewer (it takes the first free port from 3001 up; pass a port to pin one). Open a web canvas to review it at multiple breakpoints and compare them side-by-side; open any canvas to inspect its JSON, leave comments, or archive / delete it. Cards keep each artboard's proportions (between a phone held upright and 2:1; a longer page shows its top), so phone screens are portrait cards. A canvas declared `mobile` opens at 1:1 in a device frame instead of the breakpoint buttons, with a **Safe area** toggle that shades the status-bar and home-indicator insets (47 and 34 on the default `iphone-390`). The overlay is viewer-only: it never changes a screenshot.

![framesmith canvas detail view — the dashboard pattern rendered (grouped sidebar navigation with an account row, KPI cards with sparklines and delta pills, a real multi-series line chart with an area fill and a dashed reference line beside a recent-activity feed) with the Quality inspector open on the right: a 99/100 "Excellent" score, per-category bars (spacing, color, typography, structure, consistency, usability, coverage, cliche), and honest APCA advisories in the issue list. The toolbar shows the canvas's designed states (default / loading / empty), theme and viewport toggles, and a Comment toggle.](https://raw.githubusercontent.com/vicmaster/framesmith/master/docs/framesmith-canvas.png?v=2.0)

Expand Down Expand Up @@ -1301,7 +1301,7 @@ The standalone viewer:
- **Gallery** (`/`) — browse all canvases as clickable cards with live thumbnails
- **Project** (`/project/:id`) — same gallery but scoped to one project
- **Archive** (`/archive`) — soft-deleted canvases with restore / permadelete actions
- **Canvas detail** (`/canvas/:id`) — full rendered design with responsive viewport buttons (Mobile / Tablet / Desktop), Compare mode, Fit toggle, and JSON inspector
- **Canvas detail** (`/canvas/:id`) — full rendered design with responsive viewport buttons (Mobile / Tablet / Desktop), Compare mode, Fit toggle, and JSON inspector; a canvas declared `mobile` opens 1:1 in a device frame with a Safe area toggle instead of the viewport, Compare and Fit buttons
- **Raw HTML** (`/canvas/:id/html`) — the rendered HTML for embedding or inspection
- **JSON API** (`/api/canvases`, `/api/canvas/:id/meta`) — programmatic access
- **Live auto-refresh** — the viewer polls for changes every 2 seconds, so the browser updates automatically as your agent runs `batch_design`
Expand Down
2 changes: 1 addition & 1 deletion VISION.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ The mobile attempt (2026-09-07) built one iOS screen end to end on v2.2.0 and go
- [x] Slice C — the mobile ruleset: 44px targets as an error on every control (the slice D primitives joined it), safe areas, a type floor, undeclared phone-width canvases told to declare, hand-built tap targets and multi-column prose named as advisories, and stress that knows the type
- [x] Slice D — vocabulary: `fixed` / `sticky` positioning with the renderer reserving room for pinned chrome, a root that grows with long content (closing slice C's long-screen gap), the `status-bar`, `home-indicator`, `nav-bar`, `tab-bar`, `button`, `list-row` and `sheet` primitives, the primitives joining the 44px target rule, `mobile-tab-bar`, and pinned bars in the safe-area rule (`safeArea` on the root landed in slice B)
- [x] Slice E — starting points: anatomy and realisation on structures, resolution by canvas type, six mobile realisations, and the pattern gate extended to them
- [ ] Slice F — the viewer: thumbnails at the artboard's real proportions and a device frame with a safe-area overlay
- [x] Slice F — the viewer: thumbnails at the artboard's real proportions and a device frame with a safe-area overlay
- [ ] Slice G — the acceptance re-run

_Full spec-driven breakdown in [`docs/specs/PHASE-30-SPEC.md`](docs/specs/PHASE-30-SPEC.md). Deliberately out of scope: an Android profile, tablet and other types, a tappable flag on frames, a thumb-reach rule, interaction and flows, mobile import, and mobile commerce archetypes (those come next, on the anatomy/realisation split this phase creates)._
Expand Down
1 change: 1 addition & 0 deletions docs/GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ A canvas declares what medium it is on, separately from its genre (what it is fo
- **`canvas_set_type` re-declares an existing canvas** (`"web"`, `"mobile"`, or `null` to clear). It writes the declaration only, so it never moves the `versionHash`. It never resizes the artboard and never writes or removes `safeArea`, because either would reflow what you placed; clearing the type leaves the root as it is. When a mobile result has a `hint`, follow it: it names `U("document", { safeArea: { top: 47, bottom: 34 } })` when the root doesn't reserve both insets, and `U("document", { width: 390, height: 844 })` when the root is another size. Both ops change the render, so re-check the layout after them. State variants keep the type they were created with, so re-declaring a base does not reach them: the result's `variantsOutOfSync` lists each variant whose type now differs (`{ state, canvasId, type }`); declare those too.
- **`generate_design_system` on a mobile canvas** pivots the type scale on the device body size: 17px for every personality except `data-dense`, which uses 16px. An explicit `baseSize` wins. The result reports the generated pivot as `baseSize` and `baseSizeSource` (`"mobile"` for both mobile pivots, `"explicit"`, or `"personality"` on web). A `$body` inherited from a workspace or project design system is preserved by default and listed in `designSystemConflicts`; pass `preserveInherited: false` to take the mobile body.
- **Every evaluate result carries a `surface` report**: `{ type, device, source, rulesOn, rulesOff, conflicts }`. Each axis value (type, genre, preset) contributes a ruleset, and the active rules are their union. `rulesOn` and `rulesOff` name the rule ids the rulesets turned on and off. A rule both enabled and disabled stays on: it is listed in `rulesOn` and in `conflicts`, so composing declarations can never switch a guardrail off. On a web canvas `rulesOn` is `["mobile-artboard"]`; on a mobile canvas it lists every rule in [the mobile ruleset](#the-mobile-ruleset). No ruleset turns a rule off today.
- **The viewer shows the declaration to the human.** Gallery cards take the artboard's proportions, between a phone held upright (390:844) and 2:1 (a longer page shows its top), so a phone screen is a portrait card. A canvas declared `mobile` opens at 1:1 in a device frame, without the breakpoint, Compare and Fit buttons, and with a **Safe area** toggle that shades the top and bottom insets: each side is the root's `safeArea` when it sets one, else the device's (47 and 34 on `iphone-390`), so a canvas made mobile with `canvas_set_type` shows the bands its content must clear. The overlay is presentation only and never reaches a screenshot or the `versionHash`. An undeclared 390px canvas opens as a web page with breakpoint buttons, so a phone screen that was never declared looks wrong to the reviewer as well as to `mobile-artboard`; `canvas_set_type({ canvasId, type: "mobile" })` fixes both, and the open page switches to the device frame on its own.

## The mobile ruleset

Expand Down
Loading
Loading