@supportpages.io/wtfm 0.0.0-stage → 0.3.0
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.
- package/LICENSE +201 -0
- package/NOTICE +23 -0
- package/README.md +392 -2
- package/dist/actions.d.ts +98 -0
- package/dist/actions.js +86 -0
- package/dist/actions.js.map +1 -0
- package/dist/agent-settings.d.ts +22 -0
- package/dist/agent-settings.js +35 -0
- package/dist/agent-settings.js.map +1 -0
- package/dist/api.d.ts +14 -0
- package/dist/api.js +159 -0
- package/dist/api.js.map +1 -0
- package/dist/article-link.d.ts +16 -0
- package/dist/article-link.js +25 -0
- package/dist/article-link.js.map +1 -0
- package/dist/artifacts.d.ts +45 -0
- package/dist/artifacts.js +144 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/brand.d.ts +4 -0
- package/dist/brand.js +9 -0
- package/dist/brand.js.map +1 -0
- package/dist/bridge.d.ts +2964 -0
- package/dist/bridge.js +1036 -0
- package/dist/bridge.js.map +1 -0
- package/dist/capacity.d.ts +5 -0
- package/dist/capacity.js +11 -0
- package/dist/capacity.js.map +1 -0
- package/dist/credentials.d.ts +13 -0
- package/dist/credentials.js +88 -0
- package/dist/credentials.js.map +1 -0
- package/dist/development-tls.d.ts +8 -0
- package/dist/development-tls.js +38 -0
- package/dist/development-tls.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/export.d.ts +11 -0
- package/dist/export.js +91 -0
- package/dist/export.js.map +1 -0
- package/dist/hosted-operations.d.ts +108 -0
- package/dist/hosted-operations.js +120 -0
- package/dist/hosted-operations.js.map +1 -0
- package/dist/hosting-benefits.d.ts +66 -0
- package/dist/hosting-benefits.js +67 -0
- package/dist/hosting-benefits.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/local-inventory.d.ts +22 -0
- package/dist/local-inventory.js +59 -0
- package/dist/local-inventory.js.map +1 -0
- package/dist/local-setup.d.ts +208 -0
- package/dist/local-setup.js +140 -0
- package/dist/local-setup.js.map +1 -0
- package/dist/pairing.d.ts +71 -0
- package/dist/pairing.js +235 -0
- package/dist/pairing.js.map +1 -0
- package/dist/preferences.d.ts +18 -0
- package/dist/preferences.js +44 -0
- package/dist/preferences.js.map +1 -0
- package/dist/progress.d.ts +205 -0
- package/dist/progress.js +224 -0
- package/dist/progress.js.map +1 -0
- package/dist/reminders.d.ts +31 -0
- package/dist/reminders.js +73 -0
- package/dist/reminders.js.map +1 -0
- package/dist/replace-connection.d.ts +6 -0
- package/dist/replace-connection.js +77 -0
- package/dist/replace-connection.js.map +1 -0
- package/dist/repository-actions.d.ts +18 -0
- package/dist/repository-actions.js +9 -0
- package/dist/repository-actions.js.map +1 -0
- package/dist/repository-benefits.d.ts +96 -0
- package/dist/repository-benefits.js +64 -0
- package/dist/repository-benefits.js.map +1 -0
- package/dist/run-update.d.ts +17 -0
- package/dist/run-update.js +27 -0
- package/dist/run-update.js.map +1 -0
- package/dist/runs.d.ts +541 -0
- package/dist/runs.js +146 -0
- package/dist/runs.js.map +1 -0
- package/dist/runtime.d.ts +12 -0
- package/dist/runtime.js +58 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts +277 -0
- package/dist/schema.js +66 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +298 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +1714 -0
- package/dist/session.js +619 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +9 -0
- package/dist/settings.js +21 -0
- package/dist/settings.js.map +1 -0
- package/dist/sync.d.ts +495 -0
- package/dist/sync.js +191 -0
- package/dist/sync.js.map +1 -0
- package/dist/telemetry-scrub.d.ts +13 -0
- package/dist/telemetry-scrub.js +51 -0
- package/dist/telemetry-scrub.js.map +1 -0
- package/dist/telemetry.d.ts +73 -0
- package/dist/telemetry.js +173 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/walkthroughs.d.ts +224 -0
- package/dist/walkthroughs.js +109 -0
- package/dist/walkthroughs.js.map +1 -0
- package/dist/workspace.d.ts +14 -0
- package/dist/workspace.js +127 -0
- package/dist/workspace.js.map +1 -0
- package/dist/writer-agent.d.ts +21 -0
- package/dist/writer-agent.js +27 -0
- package/dist/writer-agent.js.map +1 -0
- package/dist/writer-entry.d.ts +171 -0
- package/dist/writer-entry.js +233 -0
- package/dist/writer-entry.js.map +1 -0
- package/dist/writing-style.d.ts +7 -0
- package/dist/writing-style.js +52 -0
- package/dist/writing-style.js.map +1 -0
- package/engine/SYNC.json +4 -0
- package/engine/VERSION +1 -0
- package/engine/detect-project/README.md +141 -0
- package/engine/detect-project/SKILL.md +1421 -0
- package/engine/detect-project/assets/desktop/desktop-frame.css +428 -0
- package/engine/detect-project/assets/game/game-frame.css +132 -0
- package/engine/detect-project/assets/macosui/LICENSE-puppertino.txt +21 -0
- package/engine/detect-project/assets/macosui/VERSIONS.txt +1 -0
- package/engine/detect-project/assets/macosui/fonts.css +15 -0
- package/engine/detect-project/assets/macosui/macos-frame.css +481 -0
- package/engine/detect-project/assets/macosui/puppertino.css +2153 -0
- package/engine/detect-project/assets/mobileui/LICENSE-fonts.txt +13 -0
- package/engine/detect-project/assets/mobileui/LICENSE-framework7.txt +52 -0
- package/engine/detect-project/assets/mobileui/VERSIONS.txt +6 -0
- package/engine/detect-project/assets/mobileui/device-frame.css +316 -0
- package/engine/detect-project/assets/mobileui/f7-color-theme.mjs +1345 -0
- package/engine/detect-project/assets/mobileui/f7-icons-names.json +1254 -0
- package/engine/detect-project/assets/mobileui/fonts.css +16 -0
- package/engine/detect-project/assets/mobileui/framework7-components.css +39 -0
- package/engine/detect-project/assets/mobileui/framework7-core.css +5245 -0
- package/engine/detect-project/assets/mobileui/icons.css +31 -0
- package/engine/detect-project/assets/mobileui/md3-defaults.css +89 -0
- package/engine/detect-project/assets/mobileui/platforms.json +46 -0
- package/engine/detect-project/assets/tailwind-fallback.css +1729 -0
- package/engine/detect-project/assets/webtui/LICENSE-webtui.txt +28 -0
- package/engine/detect-project/assets/webtui/VERSIONS.txt +7 -0
- package/engine/detect-project/assets/webtui/terminal-frame.css +195 -0
- package/engine/detect-project/assets/webtui/theme-catppuccin.css +1 -0
- package/engine/detect-project/assets/webtui/theme-everforest.css +1 -0
- package/engine/detect-project/assets/webtui/theme-gruvbox.css +1 -0
- package/engine/detect-project/assets/webtui/theme-nord.css +1 -0
- package/engine/detect-project/assets/webtui/theme-vitesse.css +1 -0
- package/engine/detect-project/assets/webtui/themes.json +37 -0
- package/engine/detect-project/assets/webtui/webtui-core.css +1 -0
- package/engine/detect-project/assets/win32ui/7css.css +2 -0
- package/engine/detect-project/assets/win32ui/LICENSE-7css.txt +21 -0
- package/engine/detect-project/assets/win32ui/VERSIONS.txt +1 -0
- package/engine/detect-project/assets/win32ui/win32-frame.css +278 -0
- package/engine/detect-project/package-lock.json +12 -0
- package/engine/detect-project/package.json +10 -0
- package/engine/detect-project/scripts/apply_runtime_profiles.js +313 -0
- package/engine/detect-project/scripts/check_css_health.js +412 -0
- package/engine/detect-project/scripts/check_project_map.js +150 -0
- package/engine/detect-project/scripts/check_runtime_coverage.js +311 -0
- package/engine/detect-project/scripts/check_runtime_recipe_quality.js +184 -0
- package/engine/detect-project/scripts/classify_app_type.sh +246 -0
- package/engine/detect-project/scripts/classify_surface.sh +95 -0
- package/engine/detect-project/scripts/classify_workspace.js +39 -0
- package/engine/detect-project/scripts/compile_css.sh +447 -0
- package/engine/detect-project/scripts/detect_static.js +645 -0
- package/engine/detect-project/scripts/detect_structure.js +187 -0
- package/engine/detect-project/scripts/include_census.js +451 -0
- package/engine/detect-project/scripts/json_get.js +142 -0
- package/engine/detect-project/scripts/merge_json.js +52 -0
- package/engine/detect-project/scripts/recommend_model_tier.js +252 -0
- package/engine/detect-project/scripts/resolve_route_chains.js +135 -0
- package/engine/detect-project/scripts/run_css_build.sh +40 -0
- package/engine/detect-project/scripts/sanitize_css.js +83 -0
- package/engine/detect-project/scripts/test_classify_surface.js +108 -0
- package/engine/detect-project/scripts/test_node_helpers.js +142 -0
- package/engine/detect-project/scripts/test_recommend_model_tier.js +119 -0
- package/engine/detect-project/scripts/test_resolve_route_chains.js +182 -0
- package/engine/detect-project/scripts/test_runtime_coverage.js +323 -0
- package/engine/detect-project/scripts/test_runtime_recipe_quality.js +187 -0
- package/engine/detect-project/scripts/theme_overrides.js +169 -0
- package/engine/detect-project/scripts/write_branding.js +129 -0
- package/engine/generate-illustrated-article/SKILL.md +461 -0
- package/engine/generate-illustrated-article/contracts/desktop.md +90 -0
- package/engine/generate-illustrated-article/contracts/game.md +38 -0
- package/engine/generate-illustrated-article/contracts/label-evidence.md +38 -0
- package/engine/generate-illustrated-article/contracts/macos.md +79 -0
- package/engine/generate-illustrated-article/contracts/mobile.md +40 -0
- package/engine/generate-illustrated-article/contracts/terminal.md +29 -0
- package/engine/generate-illustrated-article/contracts/win32.md +43 -0
- package/engine/generate-illustrated-article/package-lock.json +366 -0
- package/engine/generate-illustrated-article/package.json +15 -0
- package/engine/generate-illustrated-article/scripts/article_blocks.js +34 -0
- package/engine/generate-illustrated-article/scripts/check_article_json.js +105 -0
- package/engine/generate-illustrated-article/scripts/emit_walkthrough_signals.js +100 -0
- package/engine/generate-illustrated-article/scripts/extract_images.js +187 -0
- package/engine/generate-illustrated-article/scripts/generate_content_images.js +376 -0
- package/engine/generate-illustrated-article/scripts/include_census.js +451 -0
- package/engine/generate-illustrated-article/scripts/inject_assets.js +1691 -0
- package/engine/generate-illustrated-article/scripts/jit_mockup_css.js +191 -0
- package/engine/generate-illustrated-article/scripts/label_evidence.js +87 -0
- package/engine/generate-illustrated-article/scripts/lint_article_copy.js +252 -0
- package/engine/generate-illustrated-article/scripts/lint_mockup_fidelity.js +2403 -0
- package/engine/generate-illustrated-article/scripts/polish_tickets.js +1148 -0
- package/engine/generate-illustrated-article/scripts/related_repos.sh +52 -0
- package/engine/generate-illustrated-article/scripts/render_all.js +177 -0
- package/engine/generate-illustrated-article/scripts/render_mockup.js +665 -0
- package/engine/generate-illustrated-article/scripts/render_ready.js +164 -0
- package/engine/generate-illustrated-article/scripts/resolve_workspace.sh +86 -0
- package/engine/generate-illustrated-article/scripts/runtime_region_geometry.js +55 -0
- package/engine/generate-illustrated-article/scripts/source_paths.js +49 -0
- package/engine/generate-illustrated-article/scripts/test_control_visibility.js +30 -0
- package/engine/generate-illustrated-article/scripts/test_emit_walkthrough_signals.js +157 -0
- package/engine/generate-illustrated-article/scripts/test_generate_content_images.js +168 -0
- package/engine/generate-illustrated-article/scripts/test_include_census.js +126 -0
- package/engine/generate-illustrated-article/scripts/test_label_evidence.js +49 -0
- package/engine/generate-illustrated-article/scripts/test_lint_article_copy.js +138 -0
- package/engine/generate-illustrated-article/scripts/test_lint_mockup_fidelity.js +653 -0
- package/engine/generate-illustrated-article/scripts/test_node_ports.js +152 -0
- package/engine/generate-illustrated-article/scripts/test_polish_tickets.js +481 -0
- package/engine/generate-illustrated-article/scripts/test_related_repos.js +64 -0
- package/engine/generate-illustrated-article/scripts/test_render_ready.js +85 -0
- package/engine/generate-illustrated-article/scripts/test_source_paths.js +68 -0
- package/engine/generate-illustrated-article/scripts/trace_hook.js +79 -0
- package/engine/generate-illustrated-article/scripts/trace_hook.sh +4 -0
- package/engine/generate-illustrated-article/scripts/validate_html.js +114 -0
- package/engine/generate-illustrated-article/scripts/watermark.js +69 -0
- package/install.sh +14 -0
- package/package.json +57 -4
- package/scripts/auth.mjs +33 -0
- package/scripts/auto-update.mjs +7 -0
- package/scripts/build-plugin.mjs +58 -0
- package/scripts/build-release.mjs +94 -0
- package/scripts/check-release.mjs +40 -0
- package/scripts/check-runtime.mjs +10 -0
- package/scripts/cli.mjs +8 -0
- package/scripts/install.mjs +64 -0
- package/scripts/lib/agent-runner.mjs +181 -0
- package/scripts/lib/agent-settings.mjs +215 -0
- package/scripts/lib/article-skills.mjs +82 -0
- package/scripts/lib/auto-update.mjs +50 -0
- package/scripts/lib/brand.mjs +9 -0
- package/scripts/lib/browser.mjs +12 -0
- package/scripts/lib/claude-connection.mjs +33 -0
- package/scripts/lib/claude-permissions.mjs +47 -0
- package/scripts/lib/claude-plugin.mjs +15 -0
- package/scripts/lib/claude-writer.mjs +10 -0
- package/scripts/lib/cli-main.mjs +85 -0
- package/scripts/lib/cli.mjs +888 -0
- package/scripts/lib/codex-config.mjs +51 -0
- package/scripts/lib/codex-integration.mjs +61 -0
- package/scripts/lib/codex-skill.mjs +34 -0
- package/scripts/lib/harness-models.mjs +109 -0
- package/scripts/lib/install.mjs +269 -0
- package/scripts/lib/managed-writer.mjs +38 -0
- package/scripts/lib/planning.mjs +263 -0
- package/scripts/lib/prepare-update.mjs +85 -0
- package/scripts/lib/refresh-writers.mjs +12 -0
- package/scripts/lib/remove.mjs +167 -0
- package/scripts/lib/renderer.mjs +34 -0
- package/scripts/lib/terminal.mjs +252 -0
- package/scripts/lib/uninit.mjs +72 -0
- package/scripts/lib/update.mjs +55 -0
- package/scripts/lib/writer-recovery.mjs +35 -0
- package/scripts/lib/yolo.mjs +362 -0
- package/scripts/plugin-session.mjs +65 -0
- package/scripts/prepare-update.mjs +12 -0
- package/scripts/publish-release.mjs +92 -0
- package/scripts/skills/supportpages/SKILL.md +120 -0
- package/scripts/smoke-release.mjs +101 -0
- package/server.json +27 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
### Desktop mockup contract (desktop projects ONLY — supplements the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "desktop"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "desktop"` projects every screenshot is the app inside an OS window frame, authored with the `desktop-*` classes already shipped in `branding.css`. Unlike terminal and mobile this does NOT replace the web rules — the window content is real web UI styled by the app's own compiled CSS, so **everything above applies unchanged** (containing-chain from the renderer's components, chrome-once/clone-and-edit, populated data regions, overlay positioning, filled CTAs, inline-SVG icons, light mode, no invented classes/colours). The frame wraps it:
|
|
6
|
+
|
|
7
|
+
- **Skeleton** (chrome authored once, then cloned per step):
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<!doctype html>
|
|
11
|
+
<html>
|
|
12
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
13
|
+
<body class="desktop-stage theme-light" data-viewport="macos"> <!-- theme-light = the app's LIGHT theme class when its CSS is theme-class-scoped (use the app's real class name); only use a dark class if the app ships no light theme; omit entirely if the CSS isn't theme-scoped -->
|
|
14
|
+
<div class="desktop-window desktop-window--mac">
|
|
15
|
+
<!-- window_chrome fork — see below -->
|
|
16
|
+
<div class="desktop-window-content">
|
|
17
|
+
<!-- MACRO LAYOUT — exactly one of two variants; the choice is DATA-GATED, not stylistic
|
|
18
|
+
(see the "Macro layout is data-gated" rule below):
|
|
19
|
+
(A) DEFAULT — project_map.css_build records a working recipe (the render JIT compiles
|
|
20
|
+
every utility class you write): author the shell with the app's OWN layout classes,
|
|
21
|
+
copied from the real shell source. NO desktop-app-*/desktop-pane-* bones anywhere. -->
|
|
22
|
+
<div class="…real app root classes… (e.g. flex h-screen)">
|
|
23
|
+
…app titlebar/toolbar row(s) (hybrid: from chrome_component)…
|
|
24
|
+
<aside class="…real sidebar classes… (e.g. w-64 flex-shrink-0 flex flex-col)">
|
|
25
|
+
<!-- tree/list rows: ALWAYS .desktop-tree-row, one per item, populated -->
|
|
26
|
+
<div class="desktop-tree-row desktop-tree-row--active"><svg …>…</svg> <span>ItemName</span></div>
|
|
27
|
+
<div class="desktop-tree-row">…</div>
|
|
28
|
+
</aside>
|
|
29
|
+
<main class="…real main-pane classes… (e.g. flex-1 min-w-0 overflow-hidden)">
|
|
30
|
+
<!-- control strips (search/filter/actions): ALWAYS .desktop-toolbar -->
|
|
31
|
+
<div class="…real toolbar classes… desktop-toolbar">…controls…</div>
|
|
32
|
+
…page from real renderer templates…
|
|
33
|
+
<!-- tabular data: ALWAYS a semantic table, populated rows -->
|
|
34
|
+
<table class="desktop-table"><thead><tr><th>col</th>…</tr></thead><tbody><tr><td>…</td></tr>…</tbody></table>
|
|
35
|
+
<!-- code/query editors: gutter numbers + mono lines -->
|
|
36
|
+
<div class="desktop-code-editor"><div class="desktop-code-gutter">1<br>2</div><div class="desktop-code-lines">SELECT …</div></div>
|
|
37
|
+
</main>
|
|
38
|
+
<!-- when the real app has a bottom status bar, it's the app root's LAST child -->
|
|
39
|
+
<div class="…real statusbar classes… desktop-statusbar">…status fields…</div>
|
|
40
|
+
</div>
|
|
41
|
+
<!-- (B) DEGRADED PATH ONLY — no css_build recipe, or the shell's pane-sizing CSS genuinely
|
|
42
|
+
cannot work statically (unbuilt component package, JS-measured panel widths): layer the
|
|
43
|
+
bone ASSEMBLY onto the real classes, EXACTLY this nesting — the bones are one assembly,
|
|
44
|
+
never à la carte:
|
|
45
|
+
<div class="…real app root classes… desktop-app-rows">
|
|
46
|
+
…titlebar/toolbar row(s)…
|
|
47
|
+
<div class="desktop-app-columns">
|
|
48
|
+
<aside class="…real sidebar classes… desktop-pane-fixed" style="width: 320px">…</aside>
|
|
49
|
+
<main class="…real main-pane classes… desktop-pane-fill">…</main>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="…real statusbar classes… desktop-statusbar">…</div>
|
|
52
|
+
</div>
|
|
53
|
+
No toolbar rows and no status bar? Then the app root carries desktop-app-columns ITSELF
|
|
54
|
+
(no desktop-app-rows at all). desktop-pane-fixed / desktop-pane-fill are legal ONLY as
|
|
55
|
+
direct children of desktop-app-columns. A sidebar that sits BESIDE its main pane NEVER
|
|
56
|
+
goes directly inside desktop-app-rows — "rows" means stacked rows (a toolbar ABOVE the
|
|
57
|
+
content, flex-direction: column), and putting a sidebar+main pair in it renders the main
|
|
58
|
+
pane at ZERO HEIGHT: the screenshot shows chrome next to a blank pane. -->
|
|
59
|
+
<!-- modals/dialogs: .desktop-modal over .desktop-modal-backdrop, anchored to the window -->
|
|
60
|
+
<div class="desktop-modal-backdrop"></div>
|
|
61
|
+
<div class="desktop-modal" style="width: 560px">…dialog from real templates…</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
66
|
+
```
|
|
67
|
+
**Macro layout is data-gated — the app's own classes are the default; the bones are the degraded path.** Frame classes exist to REPLACE missing CSS, never to override working CSS: the bones' `!important` direction/sizing beats the app's real classes wherever the two disagree, so layering them where they aren't needed can only lose fidelity (a one-word mismatch — `desktop-app-rows` around a sidebar+main pair — collapses the main pane to zero height and blanks every screenshot). When `project_map.css_build` records a working recipe, the render JIT compiles every utility class the mockup uses, so the shell's real layout classes (`flex h-screen`, `w-64`, `flex-1`) are guaranteed to render — author variant (A) with NO `desktop-app-*`/`desktop-pane-*` bones. Author variant (B) ONLY when the shell's pane sizing genuinely cannot work statically: no `css_build` recipe, pane classes from an unbuilt component package, or runtime-dependent flex bases (the `flex-basis:100%` sidebar that swallows the window; the JS-measured panel) — then the bones pin the proportions deterministically while the app's own CSS paints everything inside each pane, layered onto the real classes (`class="sidebar connection-sidebar desktop-pane-fixed"`). Take the sidebar width from the source when it's stated; otherwise use a realistic desktop proportion (~260–360px).
|
|
68
|
+
`data-viewport` must be `macos` or `windows` matching `branding.json.platform` (with the matching `.desktop-window--mac`/`--win` variant) — **never `data-viewport="desktop"`** (a legacy 800×600 responsive-web preset that clips the frame). One platform, one window size, one theme per article.
|
|
69
|
+
- **The `window_chrome` fork** (from `project_map.desktop_metadata`; per-window values win over the top-level default). Exactly one of:
|
|
70
|
+
- `"native"` → `<div class="desktop-titlebar">` as the window's first child: `.desktop-traffic-lights` (three empty `<span>`s) + `.desktop-window-title` on mac; `.desktop-window-title` + `.desktop-caption-buttons` (`<span class="desktop-caption-min">`/`-max`/`-close`) on windows.
|
|
71
|
+
- `"hybrid"` → NO `.desktop-titlebar`. The app's own header bar, authored from `desktop_metadata.chrome_component` (list it in `partials_expanded`), plus `.desktop-traffic-lights desktop-traffic-lights--overlay` (mac) or `.desktop-caption-buttons desktop-caption-buttons--overlay` (windows) as a direct child of `.desktop-window`.
|
|
72
|
+
- `"custom"` → NO frame chrome at all — the app's chrome component draws everything, including its window controls, per the containing-chain rule.
|
|
73
|
+
Never render both a `.desktop-titlebar` and the app's own titlebar — the double-titlebar is this mode's signature failure. Likewise never mix platforms' controls: mac traffic lights and windows caption buttons are mutually exclusive (match `branding.json.platform`).
|
|
74
|
+
- **Frame classes are used, never defined.** Only `desktop-*` classes from `branding.css`; never redefine them in a `<style>` block; never stretch/shrink `.desktop-window` (its fixed 1480×900 is what the render presets and crop are built around).
|
|
75
|
+
- **Overlays position against the window, not the viewport.** Inside a framed mockup use `position: absolute` containers anchored to `.desktop-window-content` (it is `position: relative`) for modals/dropdowns/backdrops — `position: fixed` escapes the window and dims the whole stage canvas. Dialogs use the frame's `.desktop-modal` (opaque themed surface, centered, bordered) over `.desktop-modal-backdrop` — never a bare app modal class whose surface CSS may not exist, which renders transparent with the page bleeding through.
|
|
76
|
+
- **A step about choosing an option renders its dropdown OPEN.** A native `<select>` cannot render open — author the open state as an absolutely-positioned option list (high z-index, not inside an `overflow:hidden` ancestor) with the described option highlighted; same for menus a step tells the reader to open.
|
|
77
|
+
- **Pre-render self-check — verify EVERY mockup before the post-process block** (Phase 4 re-checks the same items on the rendered PNG; a self-check you skip here comes back as a polish ticket):
|
|
78
|
+
1. Every sidebar tree/list is `.desktop-tree-row` per item (bare app list classes render jammed inline), and **`project_map.app_shell` is the completeness checklist**: every shell region it records (icon rail, primary sidebar — including the controls its `content` names, e.g. a search field or connection/database picker — secondary panels, status bar, titlebar) appears in the mockup with the content the map describes, whenever that region is visible on the real screen. Author them as real widgets; never skip a region the map lists.
|
|
79
|
+
2. Tabular data is a `<table class="desktop-table">` with populated `<th>`/`<td>` rows; code/query editors are `.desktop-code-editor` with gutter numbers and **realistic syntax tinting from the app's real editor theme** — the entry stylesheet names it (a `codemirror`/`monaco`/`shiki` theme import: monokai ⇒ pink/magenta keywords, dracula ⇒ purple, etc.); use that palette via inline-styled spans, never a generic blue or a monochrome block.
|
|
80
|
+
3. Control strips use `.desktop-toolbar`; a real bottom status bar is present as `.desktop-statusbar` (last child of the app root).
|
|
81
|
+
4. Exactly one window-control set, matching `branding.json.platform` — never mac traffic lights AND windows caption squares.
|
|
82
|
+
5. Dialogs are `.desktop-modal` over `.desktop-modal-backdrop`, **with the app's real dialog/surface class (or an inline canvas colour) layered on** so the surface matches the app theme — the frame only guarantees a fallback; a white card in a dark app is a defect. Any dropdown/menu the step tells the reader to open is rendered OPEN with the target option visible.
|
|
83
|
+
6. The app root fills the window (no dead strip below), and the `<body>` theme class matches every other step's.
|
|
84
|
+
7. No two illustrated steps depict the **same action-ready state** when one screenshot can carry all of their `data-rtfm-action-target` markers. Keep the state that exposes the controls the reader must use; a result screen never replaces an uncovered start/type/submit target. The illustrated set is the minimum that covers every action, not the minimum PNG count at the expense of a control.
|
|
85
|
+
8. Macro layout matches its data gate: `css_build` recipe live ⇒ **zero** `desktop-app-*`/`desktop-pane-*` bones anywhere in the mockup (the app's own classes lay the shell out); degraded path ⇒ `desktop-pane-fixed`/`desktop-pane-fill` appear ONLY as direct children of a `desktop-app-columns`, and no sidebar sits directly inside a `desktop-app-rows` (that renders the main pane zero-height and invisible — the lint hard-fails it).
|
|
86
|
+
9. The step's subject is INSIDE the visible window: every control/section the step names — and the evidence strings that anchor it — sits above the window's bottom clip edge. If it would sit below the fold, depict the scrolled state (trim the content above it inside the scroll container). The renderer verifies evidence visibility after capture and a clipped subject fails the step.
|
|
87
|
+
- **Sizing.** The content area is ~1480×860 (mac) — a real desktop viewport, so render the desktop layout exactly as the web rules describe. Content realistically taller than the window shows a clipped viewport (`.desktop-window`'s `overflow: hidden` crops it) — let it clip; never grow the window. **But the step's SUBJECT must be inside the visible region:** anything below the window's bottom edge does not exist in the screenshot. When the control/section the step is about sits below the fold on a faithful top-of-page copy (a settings section far down a scrollable column), depict the **scrolled state** the real user would see — trim/condense the content ABOVE the target inside the scroll container (it scrolled out of view; that is the faithful state) so the target sits fully inside the window. A step whose own subject is clipped out of frame has failed regardless of how faithful the markup is.
|
|
88
|
+
- **The app root fills the window.** Author ONE root element inside `.desktop-window-content` and let it fill (`height: 100%` or flex) — **never hard-code a guessed pixel height on it**: a short root leaves a dead strip of frame background below the app. (The frame stretches a lone root automatically; don't fight it with fixed heights.)
|
|
89
|
+
- **Trees, data grids, and code editors use the `desktop-*` data widgets.** These components are usually JS widgets (grid libraries, editor components, design-system packages) whose CSS is runtime-generated or lives in an unbuilt package — it is NOT in `branding.css`, so their real DOM renders as stacked unstyled lines. Author self-contained stand-ins instead: sidebar tree/list rows as `.desktop-tree-row` (+ `--active`), tabular data as a semantic `<table class="desktop-table">` with real `<th>`/`<td>` rows (populated, per the data-region rule), and query/code editors as `.desktop-code-editor` > `.desktop-code-gutter` (line numbers) + `.desktop-code-lines`. Depict the state the step describes — a results step shows populated result rows, never an empty/"no data" placeholder.
|
|
90
|
+
- **Theme class on `<body>`.** If the app's compiled CSS scopes its rules under a theme class on body (selectors like `body.theme-… .component`), add exactly one such theme class to the mockup `<body>` alongside `desktop-stage`, and keep it identical across every step. **Prefer the light variant when the app ships one** (matching the light-mode rule in the web rules above); use a dark class only when the app has no light theme. Without a theme class the app's own component rules never match; with different ones across steps the article mixes themes.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
### Game mockup contract (game projects ONLY — wraps the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "game"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "game"` projects every screenshot is the game's playfield, wrapped in the `.game-*` frame classes already shipped in `branding.css`. The generic contract still holds — verbatim copy from source, realistic populated content, no invented colours, no annotations, chrome-once/clone-and-edit across steps — and the two screen kinds route differently: **`method: "UI"` screens** (DOM overlay menus) follow the web rules above — their markup is real HTML styled by the app's own compiled CSS — while **`method: "CANVAS"` states** have no DOM to copy and are authored as a self-contained SVG scene from the route's `scene_anatomy`. Both kinds live inside the same frame:
|
|
6
|
+
|
|
7
|
+
- **`view_sources.json` for game steps:** the real `framework` string from branding.json; per step, `url_or_route` = the state key, `primary_view` = the draw-code file (CANVAS) or the screen's markup file (UI) — a real path you opened with `Read` — **omit the `layout` key entirely**, `partials_expanded` always lists the draw-code file + the entry HTML + the stylesheet (**that listing is what whitelists the game's palette** — every colour you author must trace to a literal in a listed file or `branding.css`), `verbatim_evidence` = ≥3 real strings — HUD labels and `scene_anatomy.text_literals` fragments for CANVAS states, on-screen menu/button text for UI screens; never emoji-bearing strings — `default_user_assumptions` as usual. Persist resolved states back to `route_index` (including any `scene_anatomy` you had to derive at article time).
|
|
8
|
+
- **Document skeleton, CANVAS-state variant (mandatory):**
|
|
9
|
+
```
|
|
10
|
+
<!doctype html>
|
|
11
|
+
<html>
|
|
12
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
13
|
+
<body class="game-stage" data-viewport="game">
|
|
14
|
+
<div class="game-screen" style="width: <display_size.width>px; height: <display_size.height>px;">
|
|
15
|
+
<svg class="game-scene" viewBox="0 0 <logical_size.width> <logical_size.height>"
|
|
16
|
+
preserveAspectRatio="xMidYMid meet" shape-rendering="crispEdges">
|
|
17
|
+
<rect width="<logical_size.width>" height="<logical_size.height>" fill="<background.clear_color>"/>
|
|
18
|
+
<defs><linearGradient id="bg" x1="0" y1="0" x2="0" y2="1"><!-- background.gradient stops, verbatim --></linearGradient></defs>
|
|
19
|
+
<g data-layer="<layers[0].name>"><!-- entities --></g>
|
|
20
|
+
<g data-layer="<layers[1].name>"><!-- one <g> per scene_anatomy layer, IN ORDER --></g>
|
|
21
|
+
</svg>
|
|
22
|
+
<!-- hud_kind "dom": the app's REAL HUD markup (real ids/classes — its CSS is in branding.css) -->
|
|
23
|
+
<!-- hud_kind "canvas": <div class="game-hud" style="top: 16px; left: 16px;"><div class="game-hud-item">…</div></div> -->
|
|
24
|
+
</div>
|
|
25
|
+
</body>
|
|
26
|
+
```
|
|
27
|
+
`data-viewport="game"` always; `.game-screen` sized inline to `game_metadata.display_size`, verbatim, identical on every step. The SVG `viewBox` is `game_metadata.logical_size`, so **all scene coordinates stay in logical game units copied straight from the draw code** — the viewBox does the scaling; never a CSS `transform: scale`.
|
|
28
|
+
- **UI-screen variant:** same `<body class="game-stage">` + `.game-screen` shell; inside it the screen's real overlay markup from the entry HTML (real ids/classes — the compiled CSS paints it), positioned as the app's own CSS positions it. A menu the real game shows over the playfield uses `.game-overlay-menu` over a simplified scene (or the app's real backdrop element), with an inline neutral rgba dim if the real overlay has one.
|
|
29
|
+
- **Scene rules (CANVAS states).** `scene_anatomy` is the **completeness checklist, not the artifact** — author a living scene where every `layers[]` entry is present as a `<g data-layer>` in draw order (paint order is z-order) and every entity type is represented, at plausible **mid-game** counts per `count_hint`; never transcribe every instance, and never leave the scene in an empty attract-mode state (one lonely enemy and a zeroed score read as a broken screenshot — the article says "playing", so show play). Colours are **copied verbatim from the draw-code literals** (or `background.gradient` stops) — never approximated, never invented. An entity `catalog` names the source spec table — sample its variants. Text drawn on canvas uses the game's real font from branding.json.
|
|
30
|
+
- **HUD is mandatory** on every CANVAS step: every `app_shell.hud_fields` entry present, formats from `format`, **non-zero mid-game values**.
|
|
31
|
+
- **Glyphs:** geometric shapes (`◆ ● ▲ ►`), box/block elements, and `✓ ✗` are lint-safe; emoji and misc-symbol/dingbat characters (`★ ⚙ ⚡ ✨` and anything U+2600 and above) hard-fail **even when the real game draws them** — substitute a safe glyph or draw the shape in SVG.
|
|
32
|
+
- **Everything lives INSIDE `.game-screen`, anchored directly to it** — the screen IS the viewport; scene, HUD, and overlays all anchor within it (`position: relative`, and the frame contains fixed-position descendants, so copied markup using `position: fixed` cannot escape). **Skip the app's full-viewport wrapper containers** (a fixed-position container sized to the logical viewport): when `display_size` is smaller than the logical size, an oversized wrapper overhangs the screen and throws its edge-anchored children — a top-left HUD — outside the visible area. Parent each overlay/HUD element's own real markup straight to `.game-screen`. Never author new `position: fixed` elements yourself — use `absolute` against the screen. Frame classes are used, never defined; never resize `.game-screen` between steps.
|
|
33
|
+
- **Pre-render self-check, per step** (fix before writing the next file, not after the lint; Phase 4 re-checks the same items on the rendered PNG, and a self-check you skip here comes back as a polish ticket):
|
|
34
|
+
1. Exactly one `.game-screen`, inline-sized to `display_size`, with every element inside it — no `position: fixed`, nothing outside the screen?
|
|
35
|
+
2. CANVAS step: every `scene_anatomy` layer present as a `<g data-layer>` in draw order, background clear colour + gradient stops verbatim?
|
|
36
|
+
3. HUD present with every recorded field at non-zero mid-game values?
|
|
37
|
+
4. Every colour traceable to a draw-code literal, a gradient stop, `branding.css`, or a neutral?
|
|
38
|
+
5. Only lint-safe glyphs?
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# UI label evidence
|
|
2
|
+
|
|
3
|
+
Keep the exact UI label in `verbatim_evidence` and `action_coverage.target`. Do not remove a target, change the real label, edit application source, or add hidden text to a mockup to satisfy validation.
|
|
4
|
+
|
|
5
|
+
## Literal labels and translations
|
|
6
|
+
|
|
7
|
+
Use `{ "string": "Save changes", "found_in": "config/locales/en.yml" }` when the complete label exists in a source or translation file. Paths are relative to the application root. The shared validator checks the cited file and the mockup HTML. A locale key or a writer's explanation is not proof of an interpolated value.
|
|
8
|
+
|
|
9
|
+
## Default Rails submit labels
|
|
10
|
+
|
|
11
|
+
For an ERB `form_with(model: @record)` with an unlabeled `form.submit`, use structured evidence:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"string": "Create Invoice",
|
|
16
|
+
"found_in": "app/views/invoices/_form.html.erb",
|
|
17
|
+
"generated": {
|
|
18
|
+
"kind": "rails_submit",
|
|
19
|
+
"locale": "en",
|
|
20
|
+
"action": "create",
|
|
21
|
+
"binding": "@record",
|
|
22
|
+
"binding_source": "app/controllers/invoices_controller.rb",
|
|
23
|
+
"model_source": "app/models/invoice.rb"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The validator reads the files itself. `binding_source` must contain one unambiguous assignment of the bound variable to `Invoice.new` for `create`, or `Invoice.find(...)` for `update`. The template must contain one `form_with` bound to that variable and one default submit helper (no arguments, or a literal `class:` option). The model must directly inherit from `ApplicationRecord` or `ActiveRecord::Base` without custom behavior. Default English model humanization and literal English acronym declarations in `config/initializers/inflections.rb` are supported.
|
|
29
|
+
|
|
30
|
+
This is a conservative static resolver, not a Ruby interpreter. Custom builders, dynamic options, ambiguous bindings, custom model naming/inflections and translation overrides are unresolved rather than guessed. An explicit label that disagrees with the verified default is reported as a contradiction. A free-text `derivation` field does not bypass either check.
|
|
31
|
+
|
|
32
|
+
For unsupported cases, first look for a complete literal label in the application's actual translation/helper sources. If none exists, report the unresolved helper/locale/state and request resolver support or a verified runtime-capture path. Arbitrary screenshots, writer-authored capture JSON, and explanations are not currently accepted as runtime evidence. Do not claim the app's label is wrong merely because the static resolver cannot resolve it.
|
|
33
|
+
|
|
34
|
+
## Visible controls and accessible names
|
|
35
|
+
|
|
36
|
+
Render submit/button/reset inputs with their real `value`; the renderer checks that value and the control's bounds. For icon controls, preserve the source-backed `aria-label` or `aria-labelledby`. The renderer resolves the accessible name and separately checks the control's visibility inside the cropped frame; the name itself need not be painted text. Plain containers with `aria-label`, hidden inputs, password values, hidden/transparent ancestors, clipped controls and off-frame controls do not satisfy this check.
|
|
37
|
+
|
|
38
|
+
After changing evidence, rerun copy lint, fidelity lint and the required rendering/polish pipeline. Existing reports describe the prior inputs and are not proof that a revised article passes. Report completion only after the caller's finish/delivery command succeeds.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
### Macos mockup contract (macos projects ONLY — replaces the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "macos"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "macos"` projects every screenshot is a native Mac window, authored with the Puppertino widget classes (`p-*`), the `desktop-*` mac chrome, and the `macos-*` frame classes already shipped in `branding.css`. The generic contract still holds — verbatim copy from the `.xib` sources, realistic populated content, no invented colours, no annotations, chrome-once/clone-and-edit across steps — but the web rules about layouts and app CSS do not apply. Instead:
|
|
6
|
+
|
|
7
|
+
- **`view_sources.json` for macos:** `framework: "macos"`; per step, `url_or_route` = the view's key (`""`, `"preferences/transfers"`, …), `primary_view` = the view's `definition_file` from `view_index` (a real `.xib`/`.storyboard` path opened with Read), **omit the `layout` key**, `partials_expanded` = the entry's `controller` when its labels are code-defined + the main xib when the main window is visible, `verbatim_evidence` = ≥3 real strings from the xib — **no `&`, `<`, `>`, or `"` characters** (xib XML entity-encodes them, so `Support & Development` fails the source check) **and never composed accelerator strings** ("⌘," exists in no source file — labels only; `.strings`-file strings use the `{"string": …, "found_in": …}` form). **No emoji.** Persist newly-resolved views to `project_map.view_index`.
|
|
8
|
+
- **Skeleton** (chrome authored once, then cloned per step):
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<!doctype html>
|
|
12
|
+
<html>
|
|
13
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
14
|
+
<body class="desktop-stage" data-viewport="macos"> <!-- menu step: add macos-stage--menubar -->
|
|
15
|
+
<!-- MENU-NAVIGATION STEP ONLY (invoked_from names a menu): strip BEFORE the window -->
|
|
16
|
+
<div class="macos-menubar">
|
|
17
|
+
<span class="macos-menubar-apple"></span>
|
|
18
|
+
<span class="macos-menubar-item macos-menubar-item--app">AppName</span>
|
|
19
|
+
<span class="macos-menubar-item macos-menu-open">Edit
|
|
20
|
+
<ul class="macos-menu">
|
|
21
|
+
<li class="macos-menu-item macos-menu-item--hover">Target Item…<span class="macos-menu-shortcut">⌘K</span></li>
|
|
22
|
+
<li class="macos-menu-item">Other Item</li>
|
|
23
|
+
</ul>
|
|
24
|
+
</span>
|
|
25
|
+
<span class="macos-menubar-item">View</span> <!-- …every app_shell.menus key in order… -->
|
|
26
|
+
</div>
|
|
27
|
+
<div class="desktop-window desktop-window--mac">
|
|
28
|
+
<div class="desktop-titlebar desktop-titlebar--macos-unified">
|
|
29
|
+
<div class="desktop-traffic-lights"><span></span><span></span><span></span></div>
|
|
30
|
+
<div class="desktop-window-title">App name</div>
|
|
31
|
+
<div class="macos-toolbar-items"> <button class="macos-toolbar-item"><svg …></svg></button> … </div>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="desktop-window-content">
|
|
34
|
+
…source list / filterbar per app_shell…
|
|
35
|
+
<!-- list-based client areas: one .macos-list-cell per row, sub-elements = the view's row_anatomy.
|
|
36
|
+
.macos-table-header/.macos-table-row are ONLY for real column grids. -->
|
|
37
|
+
<div class="macos-list-cell">
|
|
38
|
+
<div class="macos-list-cell-title">item name</div>
|
|
39
|
+
<div class="macos-list-progress"><div class="macos-list-progress-fill" style="width: 64%;"></div></div>
|
|
40
|
+
<div class="macos-list-cell-status">secondary status line</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="macos-statusbar">…</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Pane-host steps** (Preferences/Settings pane, Inspector tab) use the compact-window skeleton — the tab strip is `.macos-tab-strip`, never text chips, and the window title is the **selected pane's title** (macOS convention), not the window's generic name:
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<body class="desktop-stage" data-viewport="macos">
|
|
53
|
+
<div class="desktop-window desktop-window--mac macos-window--compact" style="width: 700px;">
|
|
54
|
+
<div class="desktop-titlebar">
|
|
55
|
+
<div class="desktop-traffic-lights"><span></span><span></span><span></span></div>
|
|
56
|
+
<div class="desktop-window-title">Bandwidth</div>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="desktop-window-content">
|
|
59
|
+
<div class="macos-tab-strip">
|
|
60
|
+
<span class="macos-tab"><svg …></svg>General</span>
|
|
61
|
+
<span class="macos-tab macos-tab--selected"><svg …></svg>Bandwidth</span>
|
|
62
|
+
<!-- …every pane tab in order… -->
|
|
63
|
+
</div>
|
|
64
|
+
<div style="padding: 20px 26px;"> …controls[] top-to-bottom AS RECORDED — the xib order IS the layout… </div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</body>
|
|
68
|
+
```
|
|
69
|
+
`data-viewport="macos"` always. The titlebar forks on `app_shell.titlebar_style` — `"unified"` uses the modifier above with toolbar items from `app_shell.toolbar` (icons = simple inline-SVG approximations of the recorded SF Symbol name hints, **never the symbol name as text**; `toolbar: []` ⇒ traffic lights + title only); `"classic"` uses the plain 38px `.desktop-titlebar`. Exactly one `.desktop-titlebar` either way. One window size, light appearance only.
|
|
70
|
+
- **A step that navigates via a menu SHOWS the open menu.** When the step's instruction is "choose X from the Y menu" (the view's `invoked_from` names a menu path), that step's screenshot IS the menubar strip with Y open and X in the `--hover` state — a bare window for a menu-navigation step fails chrome. Add class `macos-stage--menubar` to `<body>` (it stacks strip-then-window; without it the strip sits beside the window) and author `<div class="macos-menubar"><span class="macos-menubar-apple"></span><span class="macos-menubar-item macos-menubar-item--app">AppName</span><span class="macos-menubar-item">File</span>…</div>` **before** the window, with every top-level menu from `app_shell.menus` in order. The open menu: `class="macos-menubar-item macos-menu-open"` + nested `<ul class="macos-menu"><li class="macos-menu-item">Label<span class="macos-menu-shortcut">⌘O</span></li>…</ul>` — each entry of `app_shell.menus["<menu>"]`, one row per item, accelerator glyphs from `accel` (⌘⇧⌥⌃ are lint-safe), `.macos-menu-divider` rows where `divider_before` says so, a `submenu` entry as a **single row with `macos-menu-sub`** (drawn cascade arrow) — never inline its children. **The dropdown hangs from the menubar strip and must never be inside `.desktop-window`** (the window's `overflow: hidden` clips it). Non-menu steps omit the strip and the body class.
|
|
71
|
+
- **Sheets attach, panes host, nothing dims the screen.** A dialog invoked from a window is a **sheet**: `<div class="macos-sheet">` as a child of `.desktop-window-content`, top-anchored under the titlebar, `.macos-sheet-buttons` right-aligned (`.p-btn` default + primary) — never `position: fixed`, no backdrop. A **pane** step (`kind: "pane"`) renders its HOST window's chrome with the pane's tab/category selected and the panel content from the pane's own `view_index` entry — not the host's `controls[]`. Secondary windows (Preferences, About, utility panels) add `macos-window--compact` to `.desktop-window` so they size to content instead of the fixed main-window geometry, and stand alone in the stage (a real Preferences window is its own window, not an overlay). Popovers use `.macos-popover` anchored near their control.
|
|
72
|
+
- **Widgets: author real controls; `controls[]` is the completeness checklist, not the artifact.** Puppertino's patterns must be printed exactly — checkbox/radio are **label-wrapped**: `<label class="p-form-checkbox-cont"><input type="checkbox" checked><span></span>Label</label>` (the `<span>` paints the box; a bare sibling-style `<input><label>` renders as an unstyled native box here — the inverse of the win32 trap); selects are `<div class="p-form-select"><select>…</select></div>`; switches `<label class="p-form-switch"><input type="checkbox"><span></span></label>`; buttons `.p-btn` (default button gets the accent). Every `controls[]` entry appears as its widget type, **in the recorded order** (the census is ordered because the xib is — reordering sections reads as a different dialog), none invented. Sectioned panes render each `groupBox` census entry as a `fieldset`+`legend` **in census order** — the census is visually ordered at detect time, so top-to-bottom transcription IS the layout. Tables use `.macos-table` (header + rows, `--alt` stripes, `--selected` on the acted-on row) and **every row renders the view's recorded `row_anatomy`** — when it says title + progress bar + secondary status line, a bare title+status row fails structure; sidebars `.macos-source-list`; pane-host tab rows use `.macos-tab-strip` with `.macos-tab` icon+label entries (`--selected` on the current pane) — never text-only chips for icon+label tab controls.
|
|
73
|
+
- **Never define classes in your own `<style>` block**; inline `style=` for layout only; colours via `var(--macos-accent)` / whitelisted hexes / neutrals.
|
|
74
|
+
- **Icons are inline SVG** (`currentColor`), never emoji, never icon-font classes. **Realism:** populate rows with plausible app-domain data; the statusbar shows realistic totals; menu bar clock/status icons are out of scope (right side of the strip may stay empty).
|
|
75
|
+
- **Pre-render self-check, per step** (fix before writing the next file, not after the lint; Phase 4 re-checks the same items on the rendered PNG, and a self-check you skip here comes back as a polish ticket):
|
|
76
|
+
1. If this view's `invoked_from` names a menu — is the menubar strip present with that menu open and the target item hovered?
|
|
77
|
+
2. Does my section/field order equal the census order top-to-bottom? (The census is visually ordered at detect time; the xib's raw XML order is NOT the layout — when they disagree, the census wins.)
|
|
78
|
+
3. Does every list row render the recorded `row_anatomy` via `.macos-list-cell` sub-elements — no bare title+status rows, no invented column grids?
|
|
79
|
+
4. Does each container match its `view_index.kind` — `sheet` attached under the titlebar via `.macos-sheet` (never a centered floating modal), `window`/`panel` as its own `.desktop-window` (compact for secondary), `pane` inside its host with `.macos-tab-strip`?
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
### Mobile mockup contract (mobile projects ONLY — replaces the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "mobile"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "mobile"` projects every screenshot is a phone rendered inside the vendored device frame, authored with the Framework7 + `device-*` classes already shipped in `branding.css`. The generic contract still holds — verbatim copy from source, realistic populated content, no invented colours, no annotations, chrome-once/clone-and-edit across steps — but the web rules about layouts and desktop shells do not apply. Instead:
|
|
6
|
+
|
|
7
|
+
- **`view_sources.json` for mobile steps:** `framework: "mobile"`; per step, `url_or_route` = the screen's route (from `screen_index`), `primary_view` = the screen's `definition_file` (a real path you opened with `Read`), **omit the `layout` key entirely**, `partials_expanded` = the shell definition file (`app_shell.definition_file`), the child components/widgets the screen composes, **`mobile_metadata.theme_module` (mandatory when non-null — open it: it tells you which surfaces the app tints, and mockups authored without it come out grey)**, and any localisation files the screen's strings live in (Flutter `.arb`, RN i18n JSON — listing them is what puts them in the lint's source corpus). `verbatim_evidence` = ≥3 real strings per step; for a string that lives in a l10n file rather than the widget, use the object form `{"string": "…", "found_in": "lib/l10n/app_en.arb"}` so the lint checks the right file — **never strings containing emoji**. `default_user_assumptions` as usual (signed-in default user; no debug banners or dev menus). Persist resolved screens back to `project_map.screen_index`, not `route_index`.
|
|
8
|
+
- **Document skeleton (mandatory):**
|
|
9
|
+
```
|
|
10
|
+
<!doctype html>
|
|
11
|
+
<html class="<platform_attr from branding.json>"> <!-- "ios" or "md" -->
|
|
12
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
13
|
+
<body class="device-stage" data-viewport="<platform from branding.json>"> <!-- "ios" or "android" -->
|
|
14
|
+
<div class="device device--ios"> <!-- or device--android -->
|
|
15
|
+
<div class="device-screen">
|
|
16
|
+
<div class="device-statusbar">
|
|
17
|
+
<span class="device-statusbar-time">9:41</span>
|
|
18
|
+
<span class="device-statusbar-icons"><span class="device-signal"></span><span class="device-wifi"></span><span class="device-battery"></span></span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="device-dynamic-island"></div> <!-- Android: <div class="device-camera-dot"></div> -->
|
|
21
|
+
<div class="framework7-root"><div class="view"><div class="page">
|
|
22
|
+
<div class="navbar"><div class="navbar-bg"></div><div class="navbar-inner"><div class="title">Screen title</div></div></div>
|
|
23
|
+
<div class="page-content">…this step's screen content…</div>
|
|
24
|
+
<div class="toolbar toolbar-bottom tabbar tabbar-icons"><div class="toolbar-inner">
|
|
25
|
+
<a class="tab-link tab-link-active"><i class="f7-icons">house_fill</i><span class="tabbar-label">Home</span></a>
|
|
26
|
+
…one tab-link per app_shell.nav_items entry…
|
|
27
|
+
</div></div>
|
|
28
|
+
</div></div></div>
|
|
29
|
+
<div class="device-home-indicator"></div> <!-- Android: <div class="device-gesture-pill"></div> -->
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</body>
|
|
33
|
+
```
|
|
34
|
+
The `<html>` platform class is required — without it neither theme's widget styles apply. `data-viewport` must be `ios` or `android` matching `branding.json.platform`; **never `data-viewport="mobile"`** (a legacy 375px responsive-web preset that clips the frame). One platform, one theme (light), one device per article — never mix frames across steps.
|
|
35
|
+
- **Shell-first, from `app_shell`.** Statusbar → navbar → content → tab bar, in that order, before any leaf content. **The screen's title appears exactly once** — as the navbar `.title`, or as an in-body heading when `app_shell.app_bar.pattern` says the app renders titles in the body; a screen with no title region at all fails realism. The tab bar renders **every** `app_shell.nav_items` entry with its real label and icon in real order, `tab-link-active` on the current screen's tab. A genuinely standalone screen (login, onboarding, a full-screen modal flow) omits the tab bar but keeps the frame, statusbar, and home indicator. If `app_shell.type` is `"none"`, the app has no tab bar — that's recorded, not your call to re-make per step.
|
|
36
|
+
- **Widgets from provided classes only.** Build content from Framework7's classes (they're all in `branding.css`): lists are the real skeleton `.list > ul > li > .item-content > .item-media? + .item-inner > .item-title (+ .item-after)`, with `.item-after` carrying the row's trailing control (chevron `<i class="f7-icons">chevron_right</i>`, a `.toggle`, a `.badge`); buttons are `.button` / `.button-fill`; segmented controls, searchbars, cards, chips, sheets, dialogs likewise. **Primary buttons: match the app's real CTA shape from its source component** — full-width vs compact, corner radius, text case — with inline sizing on the F7 `.button` (Framework7's compact uppercase default is rarely what the app actually ships). On `.page-content`, never override the `padding` **shorthand** (it wipes the computed navbar/safe-area top offset) — set `padding-left`/`-right`/`-bottom` individually. **Never define classes in your own `<style>` block** (the lint hard-fails any class absent from `branding.css`/source). Inline `style=` is allowed for content *layout* (flex, spacing, sizes) — but every **colour** must be `var(--f7-theme-color)` / `var(--brand-…)` / a hex present in `branding.css` or the step's listed source files; neutrals are always safe. **Flutter caveat:** a `Color(0xFF…)` literal in a `.dart` file does NOT whitelist its hex — use the CSS variables, which detect-project seeded from the app's real palette.
|
|
37
|
+
- **Icons.** `<i class="f7-icons">name</i>` ligatures from the vendored font — names MUST come from `detect-project/assets/mobileui/f7-icons-names.json` (the lint validates; an invented name renders as raw text) — or inline `<svg>` with `currentColor`. Never emoji (including in the statusbar), never `fa-*`/`material-icons` font classes (they trigger a network fetch the render container blocks).
|
|
38
|
+
- **Overlays.** A bottom sheet is `class="sheet-modal modal-in"`, an alert/confirm is `class="dialog modal-in"`, an action sheet is `class="actions-modal modal-in"` — author them as a direct child of `.device-screen`, preceded by their **matching** backdrop (`<div class="sheet-backdrop backdrop-in"></div>` / `dialog-backdrop` / `actions-backdrop` — a mismatched backdrop stacks ABOVE the overlay and dims it). F7 positions all of these `absolute`, so they anchor to the device screen, not the page. **JS-measured widget states must be authored inline**: a `.range-bar-active`'s width, a segmented-strong highlight's position — set the inline `width`/`left` yourself.
|
|
39
|
+
- **Sizing.** The screen is a fixed canvas (393×852 iOS / 412×915 Android); after statusbar, navbar, and tab bar roughly 650px remains — author what realistically fits (~7–8 list rows). A screen backed by a long list shows a **clipped viewport**: let the last row run under the tab bar / screen edge (`.device-screen`'s `overflow: hidden` does the cropping) — never stretch or shrink the frame to fit content, never let content overflow the bezel. Do not render the soft keyboard.
|
|
40
|
+
- **Realism.** Statusbar reads 9:41 with the standard indicators. Populate every data region with realistic values from the source's fields. Dark theme, tablets, and landscape are out of scope — light phone portrait only.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
### Terminal mockup contract (terminal projects ONLY — replaces the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "terminal"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "terminal"` projects every screenshot is a terminal window, authored with the WebTUI + terminal-frame classes already shipped in `branding.css`. The generic contract still holds — verbatim copy from source, realistic populated content, no invented colours, no annotations, chrome-once/clone-and-edit across steps — but the web rules about app shells, overlays, SVG icons, and light mode do not apply. Instead:
|
|
6
|
+
|
|
7
|
+
- **`view_sources.json` for terminal steps:** `framework: "cli"`; per step, `url_or_route` = the command invocation, `primary_view` = the command's `definition_file` from `command_index` (a real path you opened with `Read`), **omit the `layout` key entirely**, `partials_expanded` = any additional source files the step's output/help text is drawn from, `verbatim_evidence` = ≥3 real strings from those files (the command name, flag names, help/print literals — **never strings containing emoji**: the lint would force them into the mockup and then reject the mockup for containing them), `default_user_assumptions` as usual. Persist resolved commands back to `project_map.command_index`, not `route_index`.
|
|
8
|
+
- **Document skeleton (mandatory):**
|
|
9
|
+
```
|
|
10
|
+
<!doctype html>
|
|
11
|
+
<html data-webtui-theme="<terminal_theme from branding.json>">
|
|
12
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
13
|
+
<body class="terminal-page" data-viewport="wide">
|
|
14
|
+
<div class="terminal-window">
|
|
15
|
+
<div class="terminal-titlebar">
|
|
16
|
+
<div class="terminal-titlebar-dots"><span class="terminal-titlebar-dot"></span><span class="terminal-titlebar-dot"></span><span class="terminal-titlebar-dot"></span></div>
|
|
17
|
+
<div class="terminal-titlebar-title">user@host: ~/path</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="terminal-body">…command lines + output…</div>
|
|
20
|
+
</div>
|
|
21
|
+
</body>
|
|
22
|
+
```
|
|
23
|
+
The `data-webtui-theme` attribute is required — without it the theme falls back to default greys. Keep `data-viewport="wide"`; do **not** use the small legacy `terminal`/`tui` viewport presets.
|
|
24
|
+
- **Frame from provided classes only.** Build the window from the `.terminal-*` classes and WebTUI attribute components (`box-="round"` panels, `is-="button"`, `is-="badge"`, `is-="input"`, tables, `<pre>`). **Never define frame or window styles in your own `<style>` block** — the lint hard-fails classes that aren't in `branding.css` — and don't restyle the frame inline. Inside `.terminal-body`, command lines are `<div class="terminal-line"><span class="terminal-prompt">$</span><span class="terminal-cmd">…</span></div>` followed by `<span class="terminal-output">…</span>` blocks (`terminal-output--dim` for secondary text, `terminal-cursor` for a trailing prompt).
|
|
25
|
+
- **Sizing.** The window spans the padded column (~95–100 monospace columns) — don't center a narrower window (the screenshot crops to content width, so side margins go lopsided). Cap a step at roughly 40 output rows.
|
|
26
|
+
- **Realism.** One terminal window per step. The prompt line shows the real binary + subcommand + real flags from the definition file; the output below is modelled on the command's actual print/log/table statements — plausible values, real field names and phrasing. Sequential command + output pairs in one window are fine when the step genuinely runs commands in sequence. Output rows are consecutive — a blank line appears only where the real output prints one (author it as an empty `<span class="terminal-output"></span>`). A mockup whose only content is the typed prompt line is redundant — the article's fenced block carries the command; illustrate the output the reader must read, or the TUI state.
|
|
27
|
+
- **Full-screen TUI states** (commands `cli_metadata.has_tui` marks as full-screen) fill `.terminal-body` with the app's screen instead of line output — and its panels are built from the **provided `.tui-*` classes, never hand-drawn borders**: `.tui-screen` (the screen column), `.tui-cols` (side-by-side panels), `.tui-panel` with a `.tui-panel-title` span (a bordered block with its title riding the border line, exactly like a ratatui titled block — add `.tui-panel--focused` on the panel holding the cursor), `.tui-row` for content lines and `.tui-row--active` for the selected row. A full-screen TUI replaces the shell prompt — no `$ cmd` line above it. **Never draw a panel border out of box-drawing glyphs across multiple rows** — every row would need the exact same character width, one character off shatters the right edge; the `.tui-panel` border is CSS and always crisp. Box-drawing glyphs are for *inline content only* (separators, tree lines, spinners, progress bars).
|
|
28
|
+
- **Glyphs.** Box-drawing (`─ │ ┌ ┐ └ ┘ ├ ┤`), block elements (`▀ ▄ █ ░ ▒ ▓`), geometric shapes (`▲ ► ● ◆`), braille spinners (`⠋ ⠙ ⠹`), and `✓ ✔ ✗` are all safe. **NEVER use emoji or misc-symbol/dingbat characters** (`⚙ ★ ⚡ ✨ 🔗` and anything else in the emoji blocks, including their HTML entities) — the lint hard-fails them **even if the real CLI prints them**; substitute a safe glyph. No icon-font classes (`fa-*` / `bi-*` / `material-*` — they trigger a network fetch the render container blocks) and no SVG icon libraries.
|
|
29
|
+
- **Colour.** Dark theme is the norm for terminal mockups (this overrides the web light-mode rule). Use only the theme's palette — those values are in `branding.css` and pass the lint automatically; anything else must be a neutral grey.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
### Win32 mockup contract (win32 projects ONLY — replaces the web rules above)
|
|
2
|
+
|
|
3
|
+
> Extracted verbatim from `generate-illustrated-article/SKILL.md` (Phase 3) on 2026-09-07 so the skill body stays under cursor-agent's ~100k-character inline cap. SKILL.md's Phase 3 gate for `app_type: "win32"` points here; this file **is** the contract — follow it exactly as if it were printed there. Keep it in sync with the lint (`scripts/lint_mockup_fidelity.js`) like any other contract text.
|
|
4
|
+
|
|
5
|
+
For `app_type: "win32"` projects every screenshot is a native Windows window, authored with the 7.css widget classes, `[role=…]` attributes, and `desktop-*`/`win32-*` frame classes already shipped in `branding.css`. The generic contract still holds — verbatim copy from the `.rc` resources, realistic populated content, no invented colours, no annotations, chrome-once/clone-and-edit across steps — but the web rules about layouts, responsive state, and app CSS do not apply. Instead:
|
|
6
|
+
|
|
7
|
+
- **`view_sources.json` for win32:** `framework: "win32"`; per step, `url_or_route` = the dialog id (or `""` for the main window), `primary_view` = the dialog's `definition_file` from `dialog_index` (a real `.rc` path opened with Read), **omit the `layout` key**, `partials_expanded` = the main `.rc` (when the main window is visible) + related source files, `verbatim_evidence` = ≥3 real strings from the `.rc` — **choose strings without `&` accelerator marks** (`CAPTION` values, `&`-free control labels): the mockup renders labels with `&` stripped, and the lint asserts evidence appears verbatim in both the source and the mockup. **No emoji.** Persist newly-resolved dialogs to `project_map.dialog_index`.
|
|
8
|
+
- **Skeleton** (chrome authored once, then cloned per step):
|
|
9
|
+
|
|
10
|
+
```html
|
|
11
|
+
<!doctype html>
|
|
12
|
+
<html>
|
|
13
|
+
<head><meta charset="utf-8"><!-- INJECT_CSS --></head>
|
|
14
|
+
<body class="desktop-stage" data-viewport="windows">
|
|
15
|
+
<div class="desktop-window desktop-window--win">
|
|
16
|
+
<div class="desktop-titlebar">
|
|
17
|
+
<div class="desktop-window-title">new 1 - Notepad++ …real title pattern…</div>
|
|
18
|
+
<div class="desktop-caption-buttons"><span class="desktop-caption-min"></span><span class="desktop-caption-max"></span><span class="desktop-caption-close"></span></div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="desktop-window-content">
|
|
21
|
+
<ul role="menubar"> <li role="menuitem" tabindex="0">File</li> …every app_shell.nav_items entry… </ul>
|
|
22
|
+
<div class="win32-toolbar"> <button class="win32-toolbar-button"><svg …></svg></button> <span class="win32-toolbar-sep"></span> … </div>
|
|
23
|
+
<menu role="tablist"> <button aria-selected="true">document tab</button> … </menu>
|
|
24
|
+
<div class="win32-editor">
|
|
25
|
+
<div class="win32-editor-gutter">1
|
|
26
|
+
2
|
|
27
|
+
3</div>
|
|
28
|
+
<div class="win32-editor-code"><div class="win32-editor-line">…</div>…</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="status-bar"><p class="status-bar-field">…</p><p class="status-bar-field">…</p></div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</body>
|
|
34
|
+
</html>
|
|
35
|
+
```
|
|
36
|
+
`data-viewport="windows"` always (never the legacy `desktop` preset). The client area between the tab strip and status bar is whatever `win32_metadata.client_area` says — the `.win32-editor` block above is for editor apps; a list-view app renders a 7.css table/`.tree-view` instead. One window size, light theme only.
|
|
37
|
+
- **Shell-first, from `app_shell`.** Titlebar (real window-title pattern) → menu bar with **every** `nav_items` entry in real order (`&` stripped) → toolbar (when `app_shell.toolbar`) → doc tabs (when `app_shell.doc_tabs`) → client area → status bar (when `app_shell.statusbar`, with realistic `.status-bar-field` values). Dropping the menu bar or status bar fails realism the same way dropping a mobile tab bar does.
|
|
38
|
+
- **Open menus render `app_shell.menus`, one row per item.** A step showing a menu adds `class="win32-menu-open"` to exactly one `[role=menuitem]` and nests `<ul role="menu"><li role="menuitem">Label<span class="win32-menu-shortcut">Ctrl+…</span></li></ul>` with **each entry of `app_shell.menus["<that menu>"]`, in order, one row each** — accelerators from each entry's `accel` in `.win32-menu-shortcut` (never hand-floated), `.has-divider` where `divider_before` says so. A `submenu` entry is a **single row with class `win32-menu-sub`** (the frame draws the cascade arrow) — **never inline a submenu's children into the parent list**; a menu taller than the window is a structure failure. At most ONE submenu may additionally be shown open (nested `<ul role="menu">` inside its row) when the topic's action lives inside it. 7.css hides menus until hover — `.win32-menu-open` is the static-render escape hatch; never force them visible any other way.
|
|
39
|
+
- **Dialogs float, nothing dims — author widgets, not lists.** A dialog step shows the main window with the dialog floated over it: `<div class="desktop-window desktop-window--win win32-dialog" style="top: …; left: …; width: …;">` as a child of the main `.desktop-window`, with its own `.desktop-titlebar` (title + close button only) and a `.win32-dialog-body` of **real form widgets**: each `controls[]` entry renders as its element type — `checkbox`/`radio` → an `<input>` with its `<label>` (sibling `<input><label>` is the 7.css-drawn form; a wrapping `<label><input>…</label>` also paints via the frame fallback), `combobox` → `<select>`, `edit` → `<input type="text">`, `groupbox` → `fieldset`+`legend`, `button` → `<button>` (a `defpushbutton` highlighted as the default) — laid out in `.win32-field-row` rows, labels `&`-stripped. **`controls[]` is the completeness checklist, not the artifact**: every entry appears as its widget, none invented, but you are authoring a dialog, not printing the census. **Multi-panel dialogs** (a container DIALOGEX hosting a category list + panel area): render the container chrome with the topic's category selected, and fill the panel area from the topic panel's **own** `dialog_index` entry (e.g. an `IDD_*_SUB_*`), not the container's. Real Win32 dialogs do NOT dim their parent — no backdrop, ever.
|
|
40
|
+
- **Styled client content needs `win32_metadata.stylers_file`.** A step whose client area shows the app's own colouring (syntax highlighting, coloured markers) MUST list `stylers_file` in `partials_expanded` — the lint whitelists colours only from `branding.css` + listed sources, so with it listed you may use the app's real palette via inline `style="color: …"`, and without it the content stays monochrome. When `stylers_file` is null, monochrome is correct.
|
|
41
|
+
- **Widgets from provided classes/roles only.** 7.css styles plain `button`/`input`/`select`/`fieldset`/`table` — use bare elements; `[role=tablist]`/`[role=menubar]`/`[role=menu]`/`.tree-view`/`.searchbox`/`.status-bar` for the composites; `win32-*` frame classes for toolbar/editor/dialog scaffolding. **Never define classes in your own `<style>` block.** Inline `style=` for layout only; colours must be from `branding.css` or the step's listed source files — the app's real palette (e.g. syntax-highlight hexes in a theme XML) is usable **only** when that file is listed in `partials_expanded`. Neutrals always safe.
|
|
42
|
+
- **Editor content is text, not art.** Fill `.win32-editor-code` with a realistic file of the app's domain (plain lines; one `.win32-editor-line` per row, `.win32-editor-line--active` for the caret line, gutter numbers matching). No box-drawing, no ASCII art, no emoji. Syntax colouring via inline `style="color: …"` only with whitelisted hexes; plain black text is always acceptable.
|
|
43
|
+
- **Icons are inline SVG** (`currentColor`), never emoji, never icon-font classes.
|