@marver-design/marver 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -2
  2. package/dist/{build-D0GnIR4G.mjs → build-CNoXE13J.mjs} +3 -3
  3. package/dist/cli.mjs +23 -7
  4. package/dist/{dev-BK4x3PBr.mjs → dev-Blyy4jOL.mjs} +24 -5
  5. package/dist/init-3h9pXEzp.mjs +337 -0
  6. package/dist/manifest-CHmKAAtG.mjs +298 -0
  7. package/dist/{plugin-DB5t2WUl.mjs → plugin-DiDJA9n-.mjs} +157 -120
  8. package/dist/{serve-BPNmWeJx.mjs → serve-BvbAbWeK.mjs} +8 -1
  9. package/package.json +4 -3
  10. package/src/client/frame-host/bridge.js +8 -2
  11. package/src/client/frame-host/main.tsx +7 -1
  12. package/src/client/shell/App.tsx +69 -8
  13. package/src/client/shell/canvas/FrameNode.tsx +9 -0
  14. package/src/client/shell/store.ts +58 -8
  15. package/src/client/shell/styles.css +21 -2
  16. package/templates/AGENTS-embedded.md +38 -26
  17. package/templates/AGENTS-studio.md +38 -26
  18. package/templates/instructions/boards.md +38 -0
  19. package/templates/instructions/brand.md +60 -0
  20. package/templates/instructions/components.md +52 -0
  21. package/templates/instructions/configure.md +44 -0
  22. package/templates/instructions/craft.md +90 -0
  23. package/templates/instructions/discover.md +52 -0
  24. package/templates/instructions/reference/color.md +53 -0
  25. package/templates/instructions/reference/concepts.md +68 -0
  26. package/templates/instructions/reference/copy.md +57 -0
  27. package/templates/instructions/reference/critique.md +53 -0
  28. package/templates/instructions/reference/delight.md +35 -0
  29. package/templates/instructions/reference/layout.md +51 -0
  30. package/templates/instructions/reference/motion.md +66 -0
  31. package/templates/instructions/reference/operate.md +38 -0
  32. package/templates/instructions/reference/slop.md +76 -0
  33. package/templates/instructions/reference/states.md +48 -0
  34. package/templates/instructions/reference/tune.md +61 -0
  35. package/templates/instructions/reference/typography.md +45 -0
  36. package/templates/instructions/review.md +51 -0
  37. package/templates/instructions/wireframe.md +49 -0
  38. package/dist/config-DMBEpdEN.mjs +0 -132
  39. package/dist/init-DcOy1krf.mjs +0 -168
@@ -0,0 +1,66 @@
1
+ # Motion - state, relationship, one authored moment
2
+
3
+ Motion explains state, relationship, and hierarchy - or delivers ONE authored moment
4
+ the surface has earned. Decoration without purpose is animation debt.
5
+
6
+ ## Write the motion thesis first
7
+
8
+ - **Focal moment**: the one sequence that deserves authorship, if any. It must come
9
+ from THIS product; a generic fade-and-rise, hover-lift, parallax, or scroll-reveal
10
+ is not a thesis.
11
+ - **Continuity**: which state/layout/navigation changes need spatial explanation.
12
+ - **Feedback**: which controls need acknowledgment.
13
+ - **Budget**: which effects are expensive and how often they run.
14
+
15
+ ## Material by meaning
16
+
17
+ Transform and opacity are the foundation, not the whole palette:
18
+
19
+ - Continuity/relationship → shared-element motion, FLIP transforms, view transitions.
20
+ - Focus/depth → bounded blur, backdrop, shadow, or light changes.
21
+ - Reveal → masks, clip-paths, controlled occlusion.
22
+ - Feedback → the SMALLEST change that makes cause and result unmistakable.
23
+
24
+ One strong material idea carried through beats stacked techniques. Sibling stagger
25
+ only when a list appears AS a list - cap the total delay; never reinterpret every
26
+ scrolled section as a staggered list.
27
+
28
+ Refuse unprompted: pulsing dots on static status, fake blinking carets, auto-scrolling
29
+ marquees, and scaling/rotating images on hover (the image is not an action target -
30
+ give its container the feedback).
31
+
32
+ ## Timing
33
+
34
+ | Duration | Use |
35
+ |---|---|
36
+ | 100-150ms | immediate feedback |
37
+ | 150-300ms | routine state change |
38
+ | 300-500ms | layout, overlay, view transition |
39
+ | 500-800ms | one deliberately authored focal entrance |
40
+
41
+ Exits FASTER than entrances. Confident deceleration: `cubic-bezier(0.16, 1, 0.3, 1)`.
42
+ No bounce or elastic by reflex. Long feedback reads as latency.
43
+
44
+ ## Implementation law
45
+
46
+ - Content visible in the DEFAULT state - a failed script must never hide the page.
47
+ - Never casually animate layout-driving properties (width/height/top/left/margin);
48
+ use transforms or FLIP.
49
+ - Bound blur/filter/shadow work to isolated regions; `will-change` only during
50
+ known animation.
51
+ - Every animation gets a `prefers-reduced-motion` path: preserve the MEANING, not
52
+ necessarily the animation. Remove spatial movement; keep state changes legible via
53
+ opacity/color; fully suppressing non-essential motion is a valid and often correct
54
+ answer.
55
+ - No new dependency for an effect the stack already expresses.
56
+
57
+ ## Operate surfaces
58
+
59
+ 150-250ms for everything routine; motion conveys state, never decoration; NO
60
+ page-load choreography - users load into a task and don't want to watch it arrive.
61
+
62
+ ## Verify
63
+
64
+ The focal motion belongs to this product; every supporting animation explains
65
+ something; interruption behaves; the reduced-motion path keeps meaning; removing any
66
+ remaining animation would lose information, not just garnish.
@@ -0,0 +1,38 @@
1
+ # Operate - dense product UI depth
2
+
3
+ For app UIs, dashboards, settings, tables, tools - surfaces where the user is IN a
4
+ task. The bar is **earned familiarity**: a category-fluent user should trust the
5
+ interface immediately. Product UI's failure mode is not flatness - it is strangeness
6
+ without purpose: over-decorated buttons, invented affordances for standard tasks,
7
+ display fonts on labels. The tool should disappear into the task.
8
+
9
+ ## What Operate surfaces are ALLOWED that brand surfaces are not
10
+
11
+ - System fonts and familiar sans defaults.
12
+ - Standard navigation: top bar + side nav, breadcrumbs, tabs, command palettes.
13
+ - Density - tables with many rows, panels with many labels, when users need it.
14
+ - Consistency over surprise: the same vocabulary screen to screen is a virtue;
15
+ delight is saved for moments, not pages.
16
+
17
+ ## The rules
18
+
19
+ - **Typography**: one family; fixed rem scale by default (fluid sizing needs a
20
+ proven container reason); tighter ratio (1.125-1.2) - see reference/typography.md.
21
+ - **Color**: restrained is the floor. Accent spends only on primary actions, current
22
+ selection, and state. A second neutral layer separates chrome (sidebars, toolbars)
23
+ from content. Standardize the full state vocabulary: hover, focus, active,
24
+ disabled, selected, loading, error, warning, success, info.
25
+ - **Components**: every interactive component ships the states that apply to it
26
+ (see reference/states.md). Same button shape, same form-control vocabulary, same
27
+ icon stroke everywhere - if "save" looks different in two places, one is wrong.
28
+ - **Overlays escape their container**: an absolute dropdown inside overflow-hidden
29
+ gets clipped; reach for a portal, `position: fixed`, or the dialog/popover APIs.
30
+ - **Motion**: 150-250ms, state-conveying only, no page-load choreography.
31
+ - **Modals are usually laziness**: exhaust inline and progressive alternatives first.
32
+ A modal earns its interruption or does not exist.
33
+
34
+ ## Never
35
+
36
+ Decorative motion; display fonts in UI labels or data; reinvented standard
37
+ affordances (custom scrollbars, weird form controls, nonstandard modals) for flavor;
38
+ heavy saturation on inactive states; a different component vocabulary per screen.
@@ -0,0 +1,76 @@
1
+ # Slop - the full catalog of generated-UI tells
2
+
3
+ Every pattern here is a statistical default of AI-generated design. None is banned
4
+ by nature - a brief can earn any of them - but reaching for one UNPROMPTED means no
5
+ decision was made. Use this as a sweep list on review passes and whenever output
6
+ feels generic. craft.md carries the short list; this is the complete one.
7
+
8
+ ## Surfaces and decoration
9
+
10
+ - Thick colored side-stripe border on a card or alert (the single most recognizable tell).
11
+ - Thick accent border fighting rounded corners.
12
+ - Hairline border + wide diffuse shadow on the same card (pick one elevation system).
13
+ - Glassmorphism/blur/glow used as decoration on elements that overlay nothing.
14
+ - Decorative grid-line or blueprint background with no canvas, map, or measurement under it.
15
+ - Repeating-gradient stripes as surface texture.
16
+ - Saturated radial glow/halo behind a section as a fake spotlight.
17
+ - Dark mode built from colored box-shadow glows.
18
+ - Everything over-rounded into the same soft blob; pills on large containers.
19
+ - Hand-drawn-style SVG scenes and mascots (read as doodles); hero art assembled from generic vector shapes (reads as clip art). Crisp geometric/diagram SVG is fine - SVG imitating pictures is not.
20
+
21
+ ## Typography
22
+
23
+ - Tracked uppercase kicker/eyebrow above a heading; the tiny pill chip above an oversized hero headline.
24
+ - A full-sentence headline at display size dominating the viewport.
25
+ - Oversized italic serif as the hero voice (the universal AI-startup landing look).
26
+ - The icon-tile-above-heading feature-card template.
27
+ - Flat hierarchy: adjacent sizes too close to carry different jobs.
28
+ - Inter, Geist, Space Grotesk as the "safe" display pick - no longer distinctive.
29
+ - One family carrying an entire Persuade page (fine on Operate; a tell on marketing).
30
+ - Tracking crushed past character integrity (tighter than -0.04em), or body tracking wider than 0.05em.
31
+ - Functional text under 11-12px; line-height under 1.3 on multi-line text; long passages in all-caps; justified text without hyphenation.
32
+
33
+ ## Color
34
+
35
+ - Purple/violet gradients; cyan-on-dark; the neon-accent-on-near-black look.
36
+ - Warm cream/beige as the default "tasteful" ground.
37
+ - Gradient-filled text.
38
+ - Gray text on a colored surface (derive from the surface hue instead).
39
+
40
+ ## Layout
41
+
42
+ - Same-size icon+heading+text card grids as the page structure; nested cards.
43
+ - The hero-metric template (big number, small label, three supporting stats, accent).
44
+ - Tiny numbered labels (01/02/03) beside headings when order carries nothing.
45
+ - One spacing value everywhere - no rhythm.
46
+ - A heading sitting closer to the PREVIOUS block than to its own content.
47
+ - One column of the first viewport running far past its neighbor, leaving dead space.
48
+ - Scroller cards flush against the panel edge with no matching inset.
49
+ - Text occluded by an overlapping element; content overflowing its container.
50
+ - Absolutely-positioned children (tooltips, menus) clipped by an overflow container.
51
+ - Prose wider than ~80ch; body text flush against the viewport edge; cramped padding.
52
+
53
+ ## Motion
54
+
55
+ - Pulsing dot making a static status look live.
56
+ - Fake blinking terminal caret on non-editable copy.
57
+ - Auto-scrolling marquees.
58
+ - Bounce/elastic easing; animating width/height/padding/margin.
59
+ - Scaling or rotating images on hover (the image is not an action target - give the container the feedback).
60
+ - The identical fade-and-rise entrance stamped on every section.
61
+
62
+ ## Copy
63
+
64
+ - Em dashes sprinkled through body copy (an AI cadence tell - use plain sentences).
65
+ - Manufactured-contrast aphorisms closing every section ("It's not X. It's Y.").
66
+ - Dismissing things as "theater" (a generated-copy tic).
67
+ - Generic SaaS buzzwords ("supercharge", "seamless", "unlock", "effortless").
68
+ - The same label repeated in several slots of one card.
69
+
70
+ ## Mechanical (belongs in every review sweep)
71
+
72
+ - Broken or placeholder `<img>` (empty/missing src) shipped to the canvas.
73
+ - Uncaught script error on load; content invisible at rest because reveal code hid it.
74
+ - Skipped heading levels; missing accessible names.
75
+ - Any font, color, radius, or size that falls OUTSIDE the documented system in
76
+ design/DESIGN.md - the tell that the system was decoration, not law.
@@ -0,0 +1,48 @@
1
+ # States - production resilience for every surface
2
+
3
+ A screen is not designed until its whole state space is. This file covers the states
4
+ themselves and the stress inputs that break them.
5
+
6
+ ## The state inventory (per screen)
7
+
8
+ - **Loading**: skeletons in the content's own shape, not a spinner centered in a
9
+ void. Name the real operation when the wait is meaningful; never invent progress.
10
+ - **Empty** - five distinct states, each with its own copy and next action:
11
+ 1. first use (emphasize value, offer a template or starting action)
12
+ 2. user cleared it (light touch - they did this on purpose)
13
+ 3. no results (suggest a different query, offer to clear filters)
14
+ 4. no permission (explain why, and how to get access)
15
+ 5. failed to load (what happened + retry)
16
+ An empty state TEACHES the interface; "nothing here" teaches nothing.
17
+ - **Error**: field-level near the field, page-level with recovery. See
18
+ reference/copy.md for the anatomy.
19
+ - **Success**: proportional to consequence - routine saves feel certain, milestones
20
+ may celebrate.
21
+ - **Disabled**: visually distinct AND explains itself (tooltip or inline hint on
22
+ why, when discoverable).
23
+ - **Partial/degraded**: some data loaded, some failed - never all-or-nothing when
24
+ the content has independent parts.
25
+
26
+ ## Stress inputs (run these against wireframes AND hi-fi)
27
+
28
+ - A 120-character name, an email at max length, a title with no spaces.
29
+ - Emoji in every text field; RTL text; CJK text (no word breaks).
30
+ - 0 items, 1 item, 1000 items.
31
+ - Numbers at boundaries: 0, negative, 999999999, 0.001.
32
+ - Rapid double-submit; back-button mid-flow; refresh mid-form.
33
+ - Offline and slow-3G: what does the user see in second 1, 3, 10?
34
+
35
+ In frames, these are FIXTURES: add a `stress` export to `_fixtures.ts` alongside the
36
+ happy-path data, and a sibling frame that renders it. A design that only ever met
37
+ its demo data is undesigned.
38
+
39
+ ## First-run and onboarding moments
40
+
41
+ - Show, don't tell: the interface demonstrates itself through a guided first action,
42
+ not a tour of tooltips over an empty screen.
43
+ - Time-to-value is the metric: the shortest path from arrival to the product's core
44
+ worth, everything else deferred.
45
+ - Onboarding is optional when possible, skippable always, and never gates a
46
+ returning user.
47
+ - Context over ceremony: teach a feature at the moment it becomes relevant, not in
48
+ a welcome carousel.
@@ -0,0 +1,61 @@
1
+ # Tune - when the human says bland, loud, or busy
2
+
3
+ The three most common disappointment verdicts, each with a discipline. All three
4
+ share one law: SCOPE IS SOVEREIGN - touch only the named target, add no color, font,
5
+ radius, or primitive the surface does not already own; if the system truly cannot
6
+ express the direction, ask before expanding it.
7
+
8
+ ## "Too bland" → bolder
9
+
10
+ The reflex answer - more effects - is the opposite of bold. Reject it first.
11
+
12
+ - **Diagnose why it reads flat.** A flat section is usually one that quietly opted
13
+ out of the system's own strongest moves. Look at what the rest of the page does
14
+ that this section does not: the display type at full strength, the signature
15
+ motif, the density shifts.
16
+ - **Amplify what the system already owns.** Bolder should look MORE like the same
17
+ brand, not less.
18
+ - **Commit, then quiet.** Make ONE decisive move completely, then calm everything
19
+ around it so the move is legible. If every element got louder, the section got
20
+ flatter.
21
+ - **Give it its own rhythm** - a peak in the scroll, a shift in density or pace.
22
+ - **The skeleton test**: strip the copy out mentally. Does the bare structure still
23
+ say what this section is and why it matters? If it only works once the words
24
+ return, the boldness is font-size, not design.
25
+
26
+ ## "Too loud" → quieter
27
+
28
+ Quiet is harder than bold; subtlety needs precision. Think luxury, not laziness -
29
+ quiet without intent collapses to generic.
30
+
31
+ - Pull saturation DOWN a step from wherever it is (the check: colors read as chosen,
32
+ not loud); fewer colors used more deliberately; neutrals do more work; high
33
+ contrast reserved for what matters most.
34
+ - Reduce weights a step (900→600, 700→500); hierarchy moves to size, weight, and
35
+ SPACE instead of color and boldness.
36
+ - Tinted grays over pure gray; never gray text on a colored surface - use a darker
37
+ shade of that surface's hue.
38
+ - Shorter motion distances, gentler ease-out, no bounce; delete animations that
39
+ serve nothing.
40
+ - Never: flatten all hierarchy, strip all color, or erase the personality. The
41
+ point of view survives the cuts or the pass failed.
42
+
43
+ ## "Too busy" → distill
44
+
45
+ Simplicity removes obstacles, not features. Every element justifies its existence.
46
+
47
+ - Name the ONE primary goal of the surface; one obvious primary action, few
48
+ secondary, everything else tertiary or disclosed progressively.
49
+ - Remove redundancy: no heading restating the intro, no repeated explanations, no
50
+ decorative borders/shadows/containers that serve no hierarchy.
51
+ - Cards are not a layout primitive - spacing and alignment group things; never nest
52
+ cards.
53
+ - Cut copy until removing one more word would lose meaning or recovery. Active voice.
54
+ - Fewer choices beats organized choices: merge similar actions, apply smart
55
+ defaults, ask only when necessary.
56
+ - Never: hide information a decision needs, sacrifice a11y, or oversimplify a
57
+ genuinely complex domain - match complexity to the task's real complexity.
58
+
59
+ After any tune pass, run the review walk (instructions/review.md) before
60
+ re-presenting - a tuned surface that broke a state trades one disappointment for
61
+ another.
@@ -0,0 +1,45 @@
1
+ # Typography - roles, hierarchy, reading
2
+
3
+ Type carries information, hierarchy, and voice. Improve it inside the settled brand;
4
+ replacing the faces is a Brand decision, not a typesetting one.
5
+
6
+ ## Diagnose first
7
+
8
+ - **Roles.** Can heading, body, label, metadata, and data be told apart at a glance?
9
+ Adjacent sizes too close to carry different jobs is the classic failure.
10
+ - **Scale.** A deliberate role scale, or a collection of arbitrary values? Repeated
11
+ roles must be byte-identical across frames.
12
+ - **Reading.** Body in the 45-75ch measure; line-height tuned to the face and width,
13
+ not a universal ratio (wider measure needs more leading).
14
+ - **Stress.** Long headings, translation-length words, zoom, narrow containers, and
15
+ font-loading fallback - run them.
16
+
17
+ ## The system
18
+
19
+ - The fewest roles and families that make hierarchy unmistakable. Combine size,
20
+ weight, spacing, and tone deliberately - never ask size alone to do all the work.
21
+ - Body floor is 1rem/16px on ordinary web surfaces; denser roles must be a decision.
22
+ - Light text on dark surfaces compensates on three axes: slightly more line-height,
23
+ a touch more tracking, one step more weight if the face runs thin.
24
+ - Paragraph rhythm: spacing OR first-line indent, never both (double-marked
25
+ boundaries).
26
+ - Use numeric/tabular font features where the content is numbers in columns.
27
+ - Load only the weights you use; give webfonts metric-compatible fallbacks so
28
+ loading never reflows or blanks text.
29
+
30
+ ## Operate surfaces (dense product UI)
31
+
32
+ - One well-tuned family is usually right - no display/body pairing needed.
33
+ - Default to a fixed rem scale; reach for fluid clamp sizes only when a heading
34
+ genuinely must track its container (marketing display type) - a fluid heading that
35
+ shrinks inside a sidebar looks worse, not more responsive.
36
+ - Tighter scale ratio (1.125-1.2 between steps): more type elements live here, and
37
+ exaggerated contrast creates noise.
38
+ - Prose measure still applies to prose; tables and dense rows may legitimately run
39
+ wider and smaller.
40
+
41
+ ## Verify
42
+
43
+ Roles recognizable without reading the copy; long text comfortable at every relevant
44
+ width; repeated roles identical everywhere; zoom and user font settings respected;
45
+ no loading reflow.
@@ -0,0 +1,51 @@
1
+ # Review - the self-review pass before presenting anything
2
+
3
+ Run this before telling the human a design is ready. The budget is fixed: one full
4
+ inspection round, one batch of fixes, at most one confirmation round, then stop.
5
+ Endless self-polishing costs real money and converges slower than one round of human
6
+ feedback - present, don't perfect. The cap binds POLISH only: a functional defect or
7
+ accessibility blocker found in the confirmation round gets fixed before presenting,
8
+ however late it surfaced.
9
+
10
+ ## The walk
11
+
12
+ 1. **Play the flow** (press P / instruct the human once frames are wired): every
13
+ `data-goto` lands, no dead ends, every screen either links onward or is an honest
14
+ terminal state. Dead ends in play mode are flow bugs, not polish items.
15
+ 2. **Device sweep**: every viewport configured in design/config.ts (the Devices
16
+ menu). The design targets its `meta.viewport`, but it must not BREAK at the
17
+ others - overflow, clipped controls, and unreadable collapses are defects even
18
+ off-target.
19
+ 3. **Keyboard walk**: tab through each screen once - focus is visible and follows
20
+ reading order, every interactive element is reachable, Escape closes what Enter
21
+ opened, and nothing traps focus.
22
+ 4. **Both themes** (when the brand ships two): press d, look at every frame. A theme
23
+ where one element keeps its other-theme color fails the sweep.
24
+ 5. **Read every string aloud.** Labels name actions, errors name recoveries, no
25
+ placeholder text survives, no lorem, no "TODO" copy.
26
+ 6. **States exist**: for each screen with meaningful states, the empty / error /
27
+ loading siblings are present and reachable.
28
+ 7. **Craft floor**: one pass over craft.md's Verify list against the RENDERED frames.
29
+
30
+ ## Honesty rules
31
+
32
+ - Verify against the canvas, not the code. The code compiling is not the design
33
+ working.
34
+ - Report what you did NOT check as plainly as what you did.
35
+ - A defect you found and deferred is listed, never silently absorbed.
36
+ - If the concept itself is wrong, say so and recommend re-entering Wireframe -
37
+ polish never rescues a wrong concept, and hiding the diagnosis inside cosmetic
38
+ fixes wastes the round.
39
+
40
+ ## When the human asks for a REVIEW (not just before presenting)
41
+
42
+ The walk above is the self-check. When the human explicitly requests a review or
43
+ critique of designs, run the structured pass in instructions/reference/critique.md
44
+ instead - specificity verdict, ten scored heuristics, prioritized issues.
45
+
46
+ ## Presenting
47
+
48
+ Lead with what to look at: the board name, the frame to start on, the flow to walk,
49
+ and the one or two decisions you need from the human. Copy file paths for anything
50
+ you reference (select frames + press c). Never present work whose review you skipped;
51
+ say "unreviewed" if the human asked for speed.
@@ -0,0 +1,49 @@
1
+ # Wireframe - nail structure and words while changes are cheap
2
+
3
+ Lo-fi is for NEW work: a new site, feature, flow, or page where the question is
4
+ "what is on this screen and in what order", not "how does it look". Skipping it on
5
+ new work means debating typography over a structure nobody agreed to. Skip it only
6
+ when the structure is already settled (a refinement of an existing screen goes
7
+ straight to Build).
8
+
9
+ ## What lo-fi is deciding
10
+
11
+ Structure and copy. Nothing else. The flow's screens, each screen's content and
12
+ order, and the actual words. Everything visual is deliberately withheld so feedback
13
+ lands on what is actually being decided.
14
+
15
+ ## The rules (strict)
16
+
17
+ 1. **Throwaway code is correct here.** Plain divs, inline layout, one file per frame.
18
+ Do NOT build proper components for wireframes and do NOT touch the app's
19
+ `components/` directory - lo-fi structure hardening into real components is how
20
+ throwaway decisions become permanent. If the app already has branded components,
21
+ you MAY compose with them as-is (a real Button is a fine box) - never restyle
22
+ them for the wireframe.
23
+ 2. **No new visual decisions.** Grayscale, system font, sharp corners, 1px borders,
24
+ no shadows. Existing components keep their look; you just don't ADD any. The frame
25
+ should read as unfinished - polish invites feedback on the wrong layer.
26
+ 3. **Real copy, always.** Copy IS the design at this stage - headlines, button labels,
27
+ error messages. Lorem ipsum decides nothing; write words the shipped product could
28
+ use, and expect them to be edited.
29
+ 4. **Boxes for images.** A gray box with a one-word label ("hero photo", "avatar").
30
+ Never source or generate imagery in this phase.
31
+ 5. **Every screen reachable.** Wire the flow with `data-goto` as you go. A wireframe
32
+ that cannot be walked end-to-end in play mode (press P) is not done.
33
+ 6. **States are structure.** empty / error / loading as sibling frames for any screen
34
+ where they meaningfully differ - "what does empty look like" is a structural
35
+ decision, not polish.
36
+
37
+ ## Variants
38
+
39
+ Diverging on structure? Versions are sibling frames in one scene, ordered by prefix:
40
+ `landing/a-single-column.tsx`, `landing/b-split.tsx`. Name variants by their
41
+ structural idea. Two or three real alternatives beat five shades of one.
42
+
43
+ ## Exit criteria
44
+
45
+ Move on only when: the human has walked the flow in play mode, the copy has been
46
+ read and edited, and one structure per surface has won. Then Brand (if the world is
47
+ unsettled) or Build (if it is). The winning wireframe EVOLVES into the hi-fi frame -
48
+ same file, same id, rebuilt from real components - so links and boards survive. The
49
+ losing variants get deleted, not archived; the flow diagram stays as documentation.
@@ -1,132 +0,0 @@
1
- import { join } from "node:path";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { pathToFileURL } from "node:url";
4
- //#region src/server/detect.ts
5
- function readJson(file) {
6
- try {
7
- return JSON.parse(stripJsonComments(readFileSync(file, "utf8")));
8
- } catch {
9
- return null;
10
- }
11
- }
12
- function stripJsonComments(s) {
13
- return s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,\s*([}\]])/g, "$1");
14
- }
15
- function detectHost(root) {
16
- const pkg = readJson(join(root, "package.json")) ?? {};
17
- const deps = {
18
- ...pkg.dependencies,
19
- ...pkg.devDependencies
20
- };
21
- const twRange = deps["tailwindcss"];
22
- const tailwind = !twRange ? null : /(^|[^\d])4\./.test(twRange) || twRange.startsWith("^4") || twRange.startsWith("~4") ? 4 : 3;
23
- const router = deps["next"] ? "next" : deps["react-router"] || deps["react-router-dom"] ? "react-router" : null;
24
- const routerPkg = deps["react-router-dom"] ? "react-router-dom" : "react-router";
25
- const toaster = deps["sonner"] ? "sonner" : deps["react-hot-toast"] ? "react-hot-toast" : null;
26
- let shadcn = null;
27
- const comp = readJson(join(root, "components.json"));
28
- if (comp?.tailwind?.css) shadcn = {
29
- themeCss: comp.tailwind.css,
30
- uiAlias: comp.aliases?.ui ?? "@/components/ui"
31
- };
32
- const themeCss = shadcn?.themeCss && existsSync(join(root, shadcn.themeCss)) ? shadcn.themeCss : firstExisting(root, [
33
- "src/index.css",
34
- "src/styles/theme.css",
35
- "src/styles/globals.css",
36
- "src/app/globals.css",
37
- "app/globals.css",
38
- "src/globals.css",
39
- "src/style.css",
40
- "styles/globals.css"
41
- ]);
42
- const ts = readJson(join(root, "tsconfig.json"));
43
- const include = ts?.include;
44
- const exclude = ts?.exclude ?? [];
45
- const sweeps = ts != null && !exclude.some((e) => e === "design" || e.startsWith("design/")) && (!include || include.some((i) => i === "." || i === "**/*" || i.startsWith("design")));
46
- return {
47
- tailwind,
48
- router,
49
- routerPkg,
50
- toaster,
51
- shadcn,
52
- themeCss,
53
- tsconfigSweepsDesign: !!sweeps
54
- };
55
- }
56
- function firstExisting(root, candidates) {
57
- for (const c of candidates) if (existsSync(join(root, c))) return c;
58
- return null;
59
- }
60
- //#endregion
61
- //#region src/server/config.ts
62
- const DEFAULTS = {
63
- mode: "studio",
64
- theme: null,
65
- viewports: {
66
- mobile: {
67
- width: 390,
68
- height: 844
69
- },
70
- tablet: {
71
- width: 768,
72
- height: 1024
73
- },
74
- laptop: {
75
- width: 1280,
76
- height: 800
77
- },
78
- monitor: {
79
- width: 1920,
80
- height: 1080
81
- }
82
- },
83
- themes: ["light", "dark"],
84
- port: 5199,
85
- zoomSpeed: 1,
86
- share: { branding: true }
87
- };
88
- /** Load design/config.ts via native TS import (Node >= 22.18). Missing or broken fields fall back to defaults. */
89
- async function loadConfig(root) {
90
- const file = join(root, "design", "config.ts");
91
- if (!existsSync(file)) return { ...DEFAULTS };
92
- try {
93
- const user = (await import(`${pathToFileURL(file).href}?t=${Date.now()}`)).default ?? {};
94
- return {
95
- ...DEFAULTS,
96
- ...user,
97
- viewports: validViewports(user.viewports) ?? DEFAULTS.viewports,
98
- themes: Array.isArray(user.themes) && user.themes.length ? user.themes.map(String) : DEFAULTS.themes,
99
- port: validPort(user.port) ?? DEFAULTS.port,
100
- zoomSpeed: validZoom(user.zoomSpeed) ?? DEFAULTS.zoomSpeed,
101
- share: {
102
- branding: user.share?.branding !== false,
103
- name: typeof user.share?.name === "string" ? user.share.name : void 0,
104
- logo: typeof user.share?.logo === "string" ? user.share.logo : void 0
105
- }
106
- };
107
- } catch (err) {
108
- console.error(`[marver] design/config.ts failed to load, using defaults:\n ${err.message}`);
109
- return { ...DEFAULTS };
110
- }
111
- }
112
- const validDim = (n) => typeof n === "number" && Number.isFinite(n) && n >= 1 && n <= 2e4;
113
- function validPort(n) {
114
- return typeof n === "number" && Number.isInteger(n) && n > 0 && n < 65536 ? n : null;
115
- }
116
- function validZoom(n) {
117
- return typeof n === "number" && Number.isFinite(n) && n >= .1 && n <= 10 ? n : null;
118
- }
119
- function validViewports(v) {
120
- if (!v || typeof v !== "object") return null;
121
- const out = {};
122
- for (const [k, val] of Object.entries(v)) {
123
- const vp = val;
124
- if (validDim(vp?.width) && validDim(vp?.height)) out[k] = {
125
- width: Math.round(vp.width),
126
- height: Math.round(vp.height)
127
- };
128
- }
129
- return Object.keys(out).length ? out : null;
130
- }
131
- //#endregion
132
- export { loadConfig as n, detectHost as r, DEFAULTS as t };