openuispec 0.2.17 → 0.2.19
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/README.md +6 -13
- package/check/audit.ts +136 -1
- package/docs/cli.md +9 -4
- package/docs/images/how-it-works.svg +56 -0
- package/docs/images/workflows.svg +76 -0
- package/docs/implementation-notes.md +1 -1
- package/examples/social-app/openuispec/openuispec.yaml +10 -0
- package/examples/taskflow/openuispec/openuispec.yaml +9 -0
- package/examples/todo-orbit/openuispec/openuispec.yaml +11 -0
- package/package.json +1 -1
- package/prepare/index.ts +51 -0
- package/schema/openuispec.schema.json +8 -0
- package/spec/openuispec-v0.2.md +159 -13
- package/docs/images/how-it-works-dark.png +0 -0
- package/docs/images/how-it-works-light.png +0 -0
- package/docs/images/workflows-dark.png +0 -0
- package/docs/images/workflows-light.png +0 -0
package/README.md
CHANGED
|
@@ -19,19 +19,11 @@ The result: each platform feels native, but every app stays semantically consist
|
|
|
19
19
|
|
|
20
20
|
## How it works
|
|
21
21
|
|
|
22
|
-
<
|
|
23
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/how-it-works-dark.png">
|
|
24
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/how-it-works-light.png">
|
|
25
|
-
<img alt="How OpenUISpec works" src="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/how-it-works-light.png">
|
|
26
|
-
</picture>
|
|
22
|
+
<img alt="How OpenUISpec works" src="./docs/images/how-it-works.svg">
|
|
27
23
|
|
|
28
24
|
## Workflows
|
|
29
25
|
|
|
30
|
-
<
|
|
31
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/workflows-dark.png">
|
|
32
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/workflows-light.png">
|
|
33
|
-
<img alt="OpenUISpec workflows" src="https://raw.githubusercontent.com/rsktash/openuispec/main/docs/images/workflows-light.png">
|
|
34
|
-
</picture>
|
|
26
|
+
<img alt="OpenUISpec workflows" src="./docs/images/workflows.svg">
|
|
35
27
|
|
|
36
28
|
## Quick start
|
|
37
29
|
|
|
@@ -54,8 +46,9 @@ This scaffolds a spec directory, starter tokens, and **configures the MCP server
|
|
|
54
46
|
- **Data binding** — reactive state, format expressions, caching, and loading/error/empty states
|
|
55
47
|
- **Adaptive layout** — size classes (compact/regular/expanded) with per-section overrides
|
|
56
48
|
- **Platform adaptation** — per-target overrides for iOS, Android, and Web behaviors
|
|
57
|
-
- **Design intent** — `design` section
|
|
58
|
-
- **Anti-patterns** — `must_avoid` in contracts and `
|
|
49
|
+
- **Design intent** — `design` section captures brand personality, complexity level (`restrained`/`balanced`/`elaborate`), quality tier (`mvp`/`production`/`flagship`), and audience — generators match visual elaborateness and polish level accordingly
|
|
50
|
+
- **Anti-patterns** — `must_avoid` in contracts and `universal_anti_patterns` in the manifest (9 domains: typography, color, spacing, motion, elevation, layout, visual, interaction, accessibility) steer AI away from generic design mistakes. Platform-scoped with `[web]`/`[ios]`/`[android]` tags
|
|
51
|
+
- **Design quality audit** — `check --audit` scores the spec against 18 heuristic checks across all token and contract domains, producing a numeric score with CI-gatable thresholds
|
|
59
52
|
|
|
60
53
|
## The 7 contract families
|
|
61
54
|
|
|
@@ -101,7 +94,7 @@ Screenshots of the generated apps are in the [artifacts](./artifacts/) directory
|
|
|
101
94
|
|-----|-------------|
|
|
102
95
|
| [CLI & MCP Tools](./docs/cli.md) | All CLI commands, MCP tools, screenshot params, target workflow |
|
|
103
96
|
| [File Formats & Schemas](./docs/file-formats.md) | File types, JSON schemas, output directories, spec sections |
|
|
104
|
-
| [Full Specification](./spec/openuispec-v0.2.md) | Complete v0.2 spec (
|
|
97
|
+
| [Full Specification](./spec/openuispec-v0.2.md) | Complete v0.2 spec (16 sections) |
|
|
105
98
|
| [llms-full.txt](https://openuispec.rsteam.uz/llms-full.txt) | Spec + all schemas in one file (for AI consumption) |
|
|
106
99
|
|
|
107
100
|
## Status
|
package/check/audit.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* openuispec check --target web --audit --format json
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
14
14
|
import { join, resolve } from "node:path";
|
|
15
15
|
import YAML from "yaml";
|
|
16
16
|
|
|
@@ -103,6 +103,24 @@ function checkTypography(tokensDir: string, findings: AuditFinding[]): void {
|
|
|
103
103
|
message: `Only ${scaleKeys.length} type scale level(s) defined. Use ≥4 distinct levels for clear hierarchy.`,
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
+
|
|
107
|
+
// Weight hierarchy: at least 2 distinct weights
|
|
108
|
+
if (doc.typography.scale) {
|
|
109
|
+
const weights = new Set<number>();
|
|
110
|
+
for (const level of Object.values(doc.typography.scale)) {
|
|
111
|
+
if (typeof (level as any)?.weight === "number") {
|
|
112
|
+
weights.add((level as any).weight);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (weights.size > 0 && weights.size < 2) {
|
|
116
|
+
findings.push({
|
|
117
|
+
domain: "typography",
|
|
118
|
+
rule: "weight_hierarchy",
|
|
119
|
+
severity: "warning",
|
|
120
|
+
message: "Only 1 distinct font weight used across the type scale. Use ≥2 weights (e.g. 400 + 700) for clear hierarchy.",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
function checkColor(tokensDir: string, findings: AuditFinding[]): void {
|
|
@@ -139,6 +157,22 @@ function checkColor(tokensDir: string, findings: AuditFinding[]): void {
|
|
|
139
157
|
}
|
|
140
158
|
scanForPure(doc.color, "color");
|
|
141
159
|
|
|
160
|
+
// Semantic color completeness: success, warning, danger, info
|
|
161
|
+
if (doc.color.semantic) {
|
|
162
|
+
const required = ["success", "warning", "danger", "info"];
|
|
163
|
+
const defined = Object.keys(doc.color.semantic);
|
|
164
|
+
for (const name of required) {
|
|
165
|
+
if (!defined.includes(name)) {
|
|
166
|
+
findings.push({
|
|
167
|
+
domain: "color",
|
|
168
|
+
rule: "semantic_completeness",
|
|
169
|
+
severity: "warning",
|
|
170
|
+
message: `Semantic color "${name}" is missing. Define all four (success, warning, danger, info) for complete state coverage.`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
142
176
|
// Theme coverage: check themes.yaml for both light + dark
|
|
143
177
|
{
|
|
144
178
|
const themes = readYamlForAudit(join(tokensDir, "themes.yaml"), "color", findings);
|
|
@@ -219,6 +253,104 @@ function checkMotion(tokensDir: string, findings: AuditFinding[]): void {
|
|
|
219
253
|
message: "motion.reduced_motion is not defined. Must specify policy for prefers-reduced-motion.",
|
|
220
254
|
});
|
|
221
255
|
}
|
|
256
|
+
|
|
257
|
+
// Easing quality: enter + exit curves, at least one cubic-bezier
|
|
258
|
+
if (doc.motion.easing) {
|
|
259
|
+
const easings = doc.motion.easing;
|
|
260
|
+
const keys = Object.keys(easings);
|
|
261
|
+
if (!keys.includes("enter") || !keys.includes("exit")) {
|
|
262
|
+
findings.push({
|
|
263
|
+
domain: "motion",
|
|
264
|
+
rule: "easing_quality",
|
|
265
|
+
severity: "warning",
|
|
266
|
+
message: "Motion easing should define at least 'enter' and 'exit' curves for asymmetric transitions.",
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const hasCubicBezier = Object.values(easings).some(
|
|
270
|
+
(v) => typeof v === "string" && v.includes("cubic-bezier"),
|
|
271
|
+
);
|
|
272
|
+
if (!hasCubicBezier) {
|
|
273
|
+
findings.push({
|
|
274
|
+
domain: "motion",
|
|
275
|
+
rule: "easing_quality",
|
|
276
|
+
severity: "warning",
|
|
277
|
+
message: "All easing curves are generic keywords. Use at least one cubic-bezier() for nuanced motion.",
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function checkElevationProgression(tokensDir: string, findings: AuditFinding[]): void {
|
|
284
|
+
const doc = readYamlForAudit(join(tokensDir, "elevation.yaml"), "elevation", findings);
|
|
285
|
+
if (!doc?.elevation) return;
|
|
286
|
+
const levels = Object.keys(doc.elevation).filter((k) => k !== "none");
|
|
287
|
+
if (levels.length < 2) {
|
|
288
|
+
findings.push({
|
|
289
|
+
domain: "elevation",
|
|
290
|
+
rule: "level_count",
|
|
291
|
+
severity: "warning",
|
|
292
|
+
message: `Only ${levels.length} non-none elevation level(s) defined. Define ≥2 (e.g. sm, md, lg) for meaningful depth hierarchy.`,
|
|
293
|
+
});
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const androidValues: number[] = [];
|
|
297
|
+
for (const level of levels) {
|
|
298
|
+
const val = doc.elevation[level]?.platform?.android?.elevation;
|
|
299
|
+
if (typeof val === "number") androidValues.push(val);
|
|
300
|
+
}
|
|
301
|
+
if (androidValues.length >= 2) {
|
|
302
|
+
for (let i = 1; i < androidValues.length; i++) {
|
|
303
|
+
if (androidValues[i] <= androidValues[i - 1]) {
|
|
304
|
+
findings.push({
|
|
305
|
+
domain: "elevation",
|
|
306
|
+
rule: "progression",
|
|
307
|
+
severity: "warning",
|
|
308
|
+
message: "Elevation levels do not increase monotonically. Each level should cast a deeper shadow than the previous.",
|
|
309
|
+
});
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function checkLayoutSizeClasses(tokensDir: string, findings: AuditFinding[]): void {
|
|
317
|
+
const doc = readYamlForAudit(join(tokensDir, "layout.yaml"), "layout", findings);
|
|
318
|
+
if (!doc?.layout?.size_classes) return;
|
|
319
|
+
const classes = Object.keys(doc.layout.size_classes);
|
|
320
|
+
if (classes.length < 2) {
|
|
321
|
+
findings.push({
|
|
322
|
+
domain: "layout",
|
|
323
|
+
rule: "size_class_coverage",
|
|
324
|
+
severity: "warning",
|
|
325
|
+
message: `Only ${classes.length} size class(es) defined. Define at least compact + regular for responsive layouts.`,
|
|
326
|
+
});
|
|
327
|
+
} else if (!classes.includes("compact")) {
|
|
328
|
+
findings.push({
|
|
329
|
+
domain: "layout",
|
|
330
|
+
rule: "size_class_coverage",
|
|
331
|
+
severity: "warning",
|
|
332
|
+
message: "No 'compact' size class defined. Mobile-first layouts require a compact breakpoint.",
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function checkContractStateCoverage(contractsDir: string, findings: AuditFinding[]): void {
|
|
338
|
+
if (!existsSync(contractsDir)) return;
|
|
339
|
+
for (const file of readdirSync(contractsDir).filter((f) => f.endsWith(".yaml") && !f.startsWith("x_"))) {
|
|
340
|
+
const doc = readYamlForAudit(join(contractsDir, file), "contracts", findings);
|
|
341
|
+
if (!doc) continue;
|
|
342
|
+
const contractName = Object.keys(doc)[0];
|
|
343
|
+
const contract = doc[contractName];
|
|
344
|
+
const mustHandle: string[] = contract?.generation?.must_handle ?? [];
|
|
345
|
+
if (mustHandle.length === 0) {
|
|
346
|
+
findings.push({
|
|
347
|
+
domain: "contracts",
|
|
348
|
+
rule: "state_coverage",
|
|
349
|
+
severity: "warning",
|
|
350
|
+
message: `Contract "${contractName}" has no generation.must_handle entries. Define required states for AI compliance.`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
222
354
|
}
|
|
223
355
|
|
|
224
356
|
function checkContracts(contractsDir: string, findings: AuditFinding[]): void {
|
|
@@ -255,7 +387,10 @@ export function buildAuditResult(projectDir: string, threshold: number = 0): Aud
|
|
|
255
387
|
checkColor(tokensDir, findings);
|
|
256
388
|
checkSpacing(tokensDir, findings);
|
|
257
389
|
checkMotion(tokensDir, findings);
|
|
390
|
+
checkElevationProgression(tokensDir, findings);
|
|
391
|
+
checkLayoutSizeClasses(tokensDir, findings);
|
|
258
392
|
checkContracts(contractsDir, findings);
|
|
393
|
+
checkContractStateCoverage(contractsDir, findings);
|
|
259
394
|
|
|
260
395
|
const errors = findings.filter((f) => f.severity === "error").length;
|
|
261
396
|
const warnings = findings.filter((f) => f.severity === "warning").length;
|
package/docs/cli.md
CHANGED
|
@@ -289,10 +289,15 @@ openuispec check --target web --audit --json # machine-readable output
|
|
|
289
289
|
|
|
290
290
|
| Domain | What's checked |
|
|
291
291
|
|--------|---------------|
|
|
292
|
-
|
|
|
293
|
-
|
|
|
292
|
+
| Tokens | All 8 required token files exist |
|
|
293
|
+
| Typography | Primary font not an AI default · ≥4 scale levels · ≥2 distinct weights |
|
|
294
|
+
| Color | No pure #000000/#FFFFFF · success/warning/danger/info semantic colors · light + dark themes |
|
|
294
295
|
| Spacing | ≥4 scale values · `page_margin` and `card_padding` aliases present |
|
|
295
|
-
| Motion | ≥2 distinct durations · `reduced_motion` policy
|
|
296
|
-
|
|
|
296
|
+
| Motion | ≥2 distinct durations · `reduced_motion` policy · enter/exit easing · ≥1 cubic-bezier curve |
|
|
297
|
+
| Elevation | ≥2 non-none levels · monotonically increasing progression |
|
|
298
|
+
| Layout | ≥2 size classes · compact class defined |
|
|
299
|
+
| Contracts | `collection` has `empty_state` in `must_handle` · all contracts have non-empty `must_handle` |
|
|
297
300
|
|
|
298
301
|
The `audit_threshold` in `generation_guidance` sets the project-wide minimum score. `--min-score` overrides it per-run.
|
|
302
|
+
|
|
303
|
+
See [Section 16 of the spec](../spec/openuispec-v0.2.md#16-design-intent-and-generation-guidance) for complete documentation of design intent, anti-patterns, and quality tiers.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 470" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></marker>
|
|
4
|
+
|
|
5
|
+
<mask id="imagine-text-gaps-o7de63" maskUnits="userSpaceOnUse"><rect x="0" y="0" width="680" height="470" fill="white"/><rect x="256.6324462890625" y="12.305379867553711" width="166.73512268066406" height="20.52798843383789" fill="black" rx="2"/><rect x="69.6505126953125" y="62.305381774902344" width="90.69898223876953" height="20.527990341186523" fill="black" rx="2"/><rect x="46.96881103515625" y="84.19429016113281" width="136.0624237060547" height="18.16684913635254" fill="black" rx="2"/><rect x="91.05573272705078" y="120.19429779052734" width="47.88853454589844" height="18.16684913635254" fill="black" rx="2"/><rect x="83.20494079589844" y="156.1942901611328" width="63.590126037597656" height="18.16684913635254" fill="black" rx="2"/><rect x="75.04055786132812" y="192.19430541992188" width="79.91889953613281" height="18.16684913635254" fill="black" rx="2"/><rect x="88.12275695800781" y="228.19430541992188" width="53.75449752807617" height="18.16684913635254" fill="black" rx="2"/><rect x="94.92210388183594" y="264.1943054199219" width="40.15579605102539" height="18.16684913635254" fill="black" rx="2"/><rect x="69.73905181884766" y="300.1943054199219" width="90.52189636230469" height="18.16684913635254" fill="black" rx="2"/><rect x="67.63247680664062" y="336.1943054199219" width="94.73506164550781" height="18.16684913635254" fill="black" rx="2"/><rect x="73.51688385009766" y="372.1943054199219" width="82.96624755859375" height="18.16684913635254" fill="black" rx="2"/><rect x="217" y="214.1942901611328" width="35.17526435852051" height="18.16684913635254" fill="black" rx="2"/><rect x="292.1412048339844" y="152.30538940429688" width="89.71763610839844" height="20.527990341186523" fill="black" rx="2"/><rect x="300.2318115234375" y="174.1942901611328" width="73.53643798828125" height="18.16684913635254" fill="black" rx="2"/><rect x="280.6084899902344" y="208.1942901611328" width="112.78303527832031" height="18.16684913635254" fill="black" rx="2"/><rect x="272.58062744140625" y="244.1942901611328" width="128.83879852294922" height="18.16684913635254" fill="black" rx="2"/><rect x="288.5773620605469" y="280.1943054199219" width="96.84532928466797" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="138.1942901611328" width="36.606706619262695" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="214.1942901611328" width="39.89016914367676" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="304.1943054199219" width="69.11670303344727" height="18.16684913635254" fill="black" rx="2"/><rect x="519.6734619140625" y="106.30538177490234" width="98.65308380126953" height="20.527990341186523" fill="black" rx="2"/><rect x="507.6279602050781" y="128.1942901611328" width="122.74410247802734" height="18.16684913635254" fill="black" rx="2"/><rect x="497.83660888671875" y="208.30538940429688" width="142.3268280029297" height="20.527990341186523" fill="black" rx="2"/><rect x="505.4365234375" y="230.1942901611328" width="127.12696838378906" height="18.16684913635254" fill="black" rx="2"/><rect x="521.5771484375" y="314.3053894042969" width="94.84574127197266" height="20.527990341186523" fill="black" rx="2"/><rect x="499.4488220214844" y="336.1943054199219" width="139.10238647460938" height="18.16684913635254" fill="black" rx="2"/><rect x="138.05886840820312" y="434.1943054199219" width="403.8822937011719" height="18.16684913635254" fill="black" rx="2"/></mask></defs>
|
|
6
|
+
|
|
7
|
+
<rect width="680" height="460" rx="12" fill="#F5F1E8" style="fill:rgb(245, 241, 232);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
8
|
+
|
|
9
|
+
<text x="340" y="28" text-anchor="middle" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">How OpenUISpec works</text>
|
|
10
|
+
|
|
11
|
+
<rect x="40" y="52" width="150" height="370" rx="12" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
12
|
+
<text x="115" y="78" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">OpenUISpec</text>
|
|
13
|
+
<text x="115" y="98" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Semantic spec (YAML)</text>
|
|
14
|
+
|
|
15
|
+
<rect x="56" y="116" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="134" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Tokens</text>
|
|
16
|
+
<rect x="56" y="152" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="170" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Contracts</text>
|
|
17
|
+
<rect x="56" y="188" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="206" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Components</text>
|
|
18
|
+
<rect x="56" y="224" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="242" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Screens</text>
|
|
19
|
+
<rect x="56" y="260" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="278" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Flows</text>
|
|
20
|
+
<rect x="56" y="296" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="314" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Actions & data</text>
|
|
21
|
+
<rect x="56" y="332" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="350" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Platform config</text>
|
|
22
|
+
<rect x="56" y="368" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="386" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Design intent</text>
|
|
23
|
+
|
|
24
|
+
<line x1="194" y1="237" x2="248" y2="237" stroke="#BA7517" stroke-width="1.5" stroke-dasharray="4 3" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-dasharray:4px, 3px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
25
|
+
<text x="221" y="228" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">spec</text>
|
|
26
|
+
|
|
27
|
+
<rect x="252" y="140" width="170" height="194" rx="12" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
28
|
+
<text x="337" y="168" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">AI generator</text>
|
|
29
|
+
<text x="337" y="188" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">MCP server</text>
|
|
30
|
+
|
|
31
|
+
<rect x="268" y="204" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="222" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Read spec context</text>
|
|
32
|
+
<rect x="268" y="240" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="258" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Generate native code</text>
|
|
33
|
+
<rect x="268" y="276" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="294" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Validate & audit</text>
|
|
34
|
+
|
|
35
|
+
<line x1="426" y1="198" x2="490" y2="134" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" mask="url(#imagine-text-gaps-o7de63)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
36
|
+
<line x1="426" y1="237" x2="490" y2="237" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
37
|
+
<line x1="426" y1="276" x2="490" y2="340" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" mask="url(#imagine-text-gaps-o7de63)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
38
|
+
|
|
39
|
+
<text x="446" y="152" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Swift</text>
|
|
40
|
+
<text x="446" y="228" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Kotlin</text>
|
|
41
|
+
<text x="446" y="318" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">TypeScript</text>
|
|
42
|
+
|
|
43
|
+
<rect x="494" y="92" width="150" height="80" rx="10" fill="#E6F1FB" stroke="#85B7EB" stroke-width="0.5" style="fill:rgb(230, 241, 251);stroke:rgb(133, 183, 235);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
44
|
+
<text x="569" y="122" text-anchor="middle" fill="#042C53" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">iOS — SwiftUI</text>
|
|
45
|
+
<text x="569" y="142" text-anchor="middle" fill="#185FA5" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Native, platform feel</text>
|
|
46
|
+
|
|
47
|
+
<rect x="494" y="198" width="150" height="80" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
48
|
+
<text x="569" y="224" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Android — Compose</text>
|
|
49
|
+
<text x="569" y="244" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Material You theming</text>
|
|
50
|
+
|
|
51
|
+
<rect x="494" y="304" width="150" height="80" rx="10" fill="#FAECE7" stroke="#F0997B" stroke-width="0.5" style="fill:rgb(250, 236, 231);stroke:rgb(240, 153, 123);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
52
|
+
<text x="569" y="330" text-anchor="middle" fill="#4A1B0C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Web — React</text>
|
|
53
|
+
<text x="569" y="350" text-anchor="middle" fill="#993C1D" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Responsive, accessible</text>
|
|
54
|
+
|
|
55
|
+
<text x="340" y="448" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Share the intent · generate native code · each platform feels like home</text>
|
|
56
|
+
</svg>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 530" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></marker>
|
|
4
|
+
|
|
5
|
+
</defs>
|
|
6
|
+
|
|
7
|
+
<rect width="680" height="520" rx="12" fill="#F5F1E8" style="fill:rgb(245, 241, 232);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
8
|
+
|
|
9
|
+
<text x="340" y="28" text-anchor="middle" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Workflows</text>
|
|
10
|
+
|
|
11
|
+
<rect x="40" y="48" width="106" height="26" rx="13" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="93" y="65" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Design mode</text>
|
|
12
|
+
<text x="158" y="65" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Spec-first — new features, design system changes</text>
|
|
13
|
+
|
|
14
|
+
<rect x="40" y="86" width="152" height="106" rx="10" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
15
|
+
<text x="116" y="108" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">1 · Define</text>
|
|
16
|
+
<text x="116" y="128" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Author spec YAML</text>
|
|
17
|
+
<text x="116" y="144" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Tokens, contracts,</text>
|
|
18
|
+
<text x="116" y="160" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">screens, flows</text>
|
|
19
|
+
<text x="116" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec validate</text>
|
|
20
|
+
|
|
21
|
+
<line x1="196" y1="139" x2="228" y2="139" stroke="#BA7517" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
22
|
+
|
|
23
|
+
<rect x="232" y="86" width="162" height="106" rx="10" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
24
|
+
<text x="313" y="108" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">2 · Generate</text>
|
|
25
|
+
<text x="313" y="128" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">AI reads spec via MCP</text>
|
|
26
|
+
<text x="313" y="144" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Produces native code</text>
|
|
27
|
+
<text x="313" y="160" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">per platform target</text>
|
|
28
|
+
<text x="313" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec prepare</text>
|
|
29
|
+
|
|
30
|
+
<line x1="398" y1="139" x2="430" y2="139" stroke="#BA7517" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
31
|
+
|
|
32
|
+
<rect x="434" y="86" width="152" height="106" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
33
|
+
<text x="510" y="108" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">3 · Refine</text>
|
|
34
|
+
<text x="510" y="128" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Platform teams adjust</text>
|
|
35
|
+
<text x="510" y="144" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">for native polish</text>
|
|
36
|
+
<text x="510" y="160" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Snapshot baseline</text>
|
|
37
|
+
<text x="510" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec drift --snapshot</text>
|
|
38
|
+
|
|
39
|
+
<line x1="590" y1="139" x2="610" y2="139" stroke="#B4B2A9" stroke-width="0.5" stroke-dasharray="3 2" style="fill:rgb(0, 0, 0);stroke:rgb(180, 178, 169);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:3px, 2px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
40
|
+
<rect x="614" y="115" width="52" height="48" rx="8" fill="#E1F5EE" stroke="#5DCAA5" stroke-width="0.5" style="fill:rgb(225, 245, 238);stroke:rgb(93, 202, 165);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="640" y="135" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Native</text><text x="640" y="149" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">apps</text>
|
|
41
|
+
|
|
42
|
+
<line x1="40" y1="242" x2="640" y2="242" stroke="#D3D1C7" stroke-width="0.5" stroke-dasharray="6 4" style="fill:rgb(0, 0, 0);stroke:rgb(211, 209, 199);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:6px, 4px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
43
|
+
<text x="340" y="258" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">or</text>
|
|
44
|
+
|
|
45
|
+
<rect x="40" y="274" width="132" height="26" rx="13" fill="#E6F1FB" stroke="#85B7EB" stroke-width="0.5" style="fill:rgb(230, 241, 251);stroke:rgb(133, 183, 235);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="106" y="291" text-anchor="middle" fill="#0C447C" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Development mode</text>
|
|
46
|
+
<text x="184" y="291" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Platform-first — day-to-day iteration, fixes, polish</text>
|
|
47
|
+
|
|
48
|
+
<rect x="40" y="312" width="152" height="106" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
49
|
+
<text x="116" y="334" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">1 · Code</text>
|
|
50
|
+
<text x="116" y="354" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Edit native code</text>
|
|
51
|
+
<text x="116" y="370" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Live preview, hot reload</text>
|
|
52
|
+
<text x="116" y="386" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Fix, tweak, polish</text>
|
|
53
|
+
|
|
54
|
+
<line x1="196" y1="365" x2="228" y2="365" stroke="#185FA5" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(24, 95, 165);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
55
|
+
|
|
56
|
+
<rect x="232" y="312" width="162" height="106" rx="10" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
57
|
+
<text x="313" y="334" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">2 · Sync</text>
|
|
58
|
+
<text x="313" y="354" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">AI reads code changes</text>
|
|
59
|
+
<text x="313" y="370" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Updates spec YAML</text>
|
|
60
|
+
<text x="313" y="386" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">to match platform code</text>
|
|
61
|
+
<text x="313" y="434" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec drift --explain</text>
|
|
62
|
+
|
|
63
|
+
<line x1="398" y1="365" x2="430" y2="365" stroke="#185FA5" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(24, 95, 165);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
64
|
+
|
|
65
|
+
<rect x="434" y="312" width="152" height="106" rx="10" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
66
|
+
<text x="510" y="334" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">3 · Propagate</text>
|
|
67
|
+
<text x="510" y="354" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Other platforms see</text>
|
|
68
|
+
<text x="510" y="370" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">spec diff and update</text>
|
|
69
|
+
<text x="510" y="386" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">their code accordingly</text>
|
|
70
|
+
<text x="510" y="434" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec status</text>
|
|
71
|
+
|
|
72
|
+
<line x1="590" y1="365" x2="610" y2="365" stroke="#B4B2A9" stroke-width="0.5" stroke-dasharray="3 2" style="fill:rgb(0, 0, 0);stroke:rgb(180, 178, 169);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:3px, 2px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
|
73
|
+
<rect x="614" y="341" width="52" height="48" rx="8" fill="#E1F5EE" stroke="#5DCAA5" stroke-width="0.5" style="fill:rgb(225, 245, 238);stroke:rgb(93, 202, 165);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, "system-ui", "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="640" y="361" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">All in</text><text x="640" y="375" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">sync</text>
|
|
74
|
+
|
|
75
|
+
<text x="340" y="500" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Spec lives in version control · diffs are human-readable · drift is detected, not hidden</text>
|
|
76
|
+
</svg>
|
|
@@ -166,6 +166,6 @@
|
|
|
166
166
|
|
|
167
167
|
`openuispec check --audit` runs design quality heuristics against token and contract files, returning a numeric score (`max(0, 100 - errors × 10 - warnings × 3)`) and categorized findings. The `audit_threshold` in `generation_guidance` sets a project-wide minimum; `--min-score N` overrides per-run.
|
|
168
168
|
|
|
169
|
-
`openuispec prepare` includes `anti_patterns` (universal + contract-specific + project-specific, filtered by target platform) and `design_context` (personality, complexity, audience, complexity_rule) in its output when the manifest defines `generation_guidance` and `design` sections.
|
|
169
|
+
`openuispec prepare` includes `anti_patterns` (universal + contract-specific + project-specific, filtered by target platform) and `design_context` (personality, complexity, quality_tier, audience, complexity_rule, quality_tier_rule, quality_test) in its output when the manifest defines `generation_guidance` and `design` sections. The `quality_test` field is an auto-generated AI-slop checklist tuned to the project's complexity and quality tier.
|
|
170
170
|
|
|
171
171
|
`generation.extra_rules` in the manifest is included in prepare output and filtered by platform tag.
|
|
@@ -57,6 +57,15 @@ generation_guidance:
|
|
|
57
57
|
layout:
|
|
58
58
|
- "Do not assume large-screen layouts work on compact — every multi-pane pattern needs an explicit compact fallback"
|
|
59
59
|
- "Do not use pixel breakpoints — reference size classes by name (compact, regular, expanded)"
|
|
60
|
+
visual:
|
|
61
|
+
- "Do not flatten depth — use elevation tokens to separate layers and give content visual weight"
|
|
62
|
+
- "Do not use generic drop shadows — map every shadow to a specific elevation level from tokens"
|
|
63
|
+
- "Do not apply glassmorphism to interactive controls — reserve frosted effects for non-interactive overlays only"
|
|
64
|
+
interaction:
|
|
65
|
+
- "Do not make swipe gestures the only way to access actions — provide a visible alternative"
|
|
66
|
+
- "Do not delay visual feedback on tap — social content requires instant response"
|
|
67
|
+
- "[web] Do not use :focus for focus rings — use :focus-visible to show rings only for keyboard navigation"
|
|
68
|
+
- "[ios] Do not replace native swipe-back with custom gestures — users expect system navigation"
|
|
60
69
|
accessibility:
|
|
61
70
|
- "Do not use color as the only differentiator between states — combine with icon, border, or text changes"
|
|
62
71
|
- "Do not skip focus ring styles — keyboard users must see where focus is at all times"
|
|
@@ -66,6 +75,7 @@ generation_guidance:
|
|
|
66
75
|
design:
|
|
67
76
|
personality: "Vibrant, social, content-rich — engagement and discovery are primary, utility is secondary"
|
|
68
77
|
complexity: "elaborate"
|
|
78
|
+
quality_tier: "flagship"
|
|
69
79
|
audience: "Mobile-first social media users who expect rich media, smooth animations, and expressive interactions"
|
|
70
80
|
avoid:
|
|
71
81
|
- "Do not use muted or desaturated brand colors — the palette should feel energetic"
|
|
@@ -64,6 +64,14 @@ generation_guidance:
|
|
|
64
64
|
layout:
|
|
65
65
|
- "Do not assume large-screen layouts work on compact — every multi-pane pattern needs an explicit compact fallback"
|
|
66
66
|
- "Do not use pixel breakpoints — reference size classes by name (compact, regular, expanded)"
|
|
67
|
+
visual:
|
|
68
|
+
- "Do not use glassmorphism or frosted-glass effects — this is a professional productivity tool"
|
|
69
|
+
- "Do not apply gradient text — it fails contrast checks and looks dated"
|
|
70
|
+
- "[web] Do not use box-shadow on every container — reserve elevation for interactive or raised elements"
|
|
71
|
+
interaction:
|
|
72
|
+
- "Do not treat hover and focus as the same state — keyboard users never see hover"
|
|
73
|
+
- "Do not use confirmation dialogs for reversible actions — use undo with a toast instead"
|
|
74
|
+
- "[web] Do not use :focus for focus rings — use :focus-visible to show rings only for keyboard navigation"
|
|
67
75
|
accessibility:
|
|
68
76
|
- "Do not use color as the only differentiator between states — combine with icon, border, or text changes"
|
|
69
77
|
- "Do not skip focus ring styles — keyboard users must see where focus is at all times"
|
|
@@ -73,6 +81,7 @@ generation_guidance:
|
|
|
73
81
|
design:
|
|
74
82
|
personality: "Clean, focused, productivity-first — no decorative flourishes. Color is used for priority and status clarity, not aesthetics."
|
|
75
83
|
complexity: "balanced"
|
|
84
|
+
quality_tier: "production"
|
|
76
85
|
audience: "Individual contributors and small teams managing personal and shared task lists"
|
|
77
86
|
avoid:
|
|
78
87
|
- "Do not use playful or rounded UI patterns — this is a professional productivity tool"
|
|
@@ -63,6 +63,16 @@ generation_guidance:
|
|
|
63
63
|
layout:
|
|
64
64
|
- "Do not assume large-screen layouts work on compact — every multi-pane pattern needs an explicit compact fallback"
|
|
65
65
|
- "Do not use pixel breakpoints — reference size classes by name (compact, regular, expanded)"
|
|
66
|
+
visual:
|
|
67
|
+
- "Do not mix rounded and sharp corners within the same card or surface — the spec uses cut-corner shapes exclusively"
|
|
68
|
+
- "Do not add decorative gradients, glows, or background textures — this is a restrained design"
|
|
69
|
+
- "Do not apply gradient text — it fails contrast checks and undermines the minimal aesthetic"
|
|
70
|
+
- "[web] Do not use box-shadow on every container — reserve elevation for interactive or raised elements"
|
|
71
|
+
interaction:
|
|
72
|
+
- "Do not treat hover and focus as the same state — keyboard users never see hover"
|
|
73
|
+
- "Do not use long-press as the primary action trigger — use explicit buttons or swipe actions"
|
|
74
|
+
- "Do not delay visual feedback on tap — the press_feedback pattern requires instant response"
|
|
75
|
+
- "[web] Do not use :focus for focus rings — use :focus-visible to show rings only for keyboard navigation"
|
|
66
76
|
accessibility:
|
|
67
77
|
- "Do not use color as the only differentiator between states — combine with icon, border, or text changes"
|
|
68
78
|
- "Do not skip focus ring styles — keyboard users must see where focus is at all times"
|
|
@@ -72,6 +82,7 @@ generation_guidance:
|
|
|
72
82
|
design:
|
|
73
83
|
personality: "Minimal and calm — orbital metaphor suggests clarity and organization without visual noise"
|
|
74
84
|
complexity: "restrained"
|
|
85
|
+
quality_tier: "production"
|
|
75
86
|
audience: "Bilingual individuals who prefer a clean, low-distraction task environment"
|
|
76
87
|
avoid:
|
|
77
88
|
- "Do not add decorative illustrations or background patterns"
|
package/package.json
CHANGED
package/prepare/index.ts
CHANGED
|
@@ -180,8 +180,11 @@ export interface PrepareResult {
|
|
|
180
180
|
design_context?: {
|
|
181
181
|
personality?: string;
|
|
182
182
|
complexity: 'restrained' | 'balanced' | 'elaborate';
|
|
183
|
+
quality_tier: 'mvp' | 'production' | 'flagship';
|
|
183
184
|
audience?: string;
|
|
184
185
|
complexity_rule: string;
|
|
186
|
+
quality_tier_rule: string;
|
|
187
|
+
quality_test: string;
|
|
185
188
|
};
|
|
186
189
|
next_steps: string[];
|
|
187
190
|
}
|
|
@@ -681,15 +684,63 @@ function complexityRule(complexity: string): string {
|
|
|
681
684
|
}
|
|
682
685
|
}
|
|
683
686
|
|
|
687
|
+
function qualityTierRule(tier: string): string {
|
|
688
|
+
switch (tier) {
|
|
689
|
+
case 'mvp':
|
|
690
|
+
return 'Functional-only. Use semantic tokens but tolerate simple layouts. Skip elevation, motion patterns, and adaptive breakpoints.';
|
|
691
|
+
case 'flagship':
|
|
692
|
+
return 'Pixel-perfect. Every token, motion pattern, elevation level, and adaptive breakpoint must be implemented. All contract states required. No shortcuts.';
|
|
693
|
+
default:
|
|
694
|
+
return 'Production-quality. Apply all tokens, handle accessibility, support adaptive breakpoints. Motion and elevation expected but minor shortcuts acceptable.';
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function buildQualityTest(complexity: string, qualityTier: string, personality?: string): string {
|
|
699
|
+
const items: string[] = [
|
|
700
|
+
'Inter/Roboto/Arial as the primary font when the spec defines a custom font_family.',
|
|
701
|
+
'Pure black (#000000) or pure white (#FFFFFF) — all colors must resolve through tokens.',
|
|
702
|
+
'Cyan-on-dark, purple-to-blue gradient, or neon accent color schemes not in color tokens.',
|
|
703
|
+
'Card-wrapping every content group — cards are for distinct, comparable items only.',
|
|
704
|
+
'Identical spacing values throughout — the spec defines a scale with distinct levels.',
|
|
705
|
+
'Bounce or elastic easing — use only the easing curves from motion tokens.',
|
|
706
|
+
'Shadows on elements with no elevation token assigned.',
|
|
707
|
+
'A single font weight everywhere — the type scale defines multiple weights for hierarchy.',
|
|
708
|
+
];
|
|
709
|
+
|
|
710
|
+
if (complexity === 'restrained') {
|
|
711
|
+
items.push('Any decorative animation, gradient, glassmorphism, or background effect — this is a restrained design.');
|
|
712
|
+
} else if (complexity === 'elaborate') {
|
|
713
|
+
items.push('Missing entrance animations or transition effects — this is an elaborate design that expects rich motion.');
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (qualityTier === 'flagship') {
|
|
717
|
+
items.push('Any adaptive breakpoint missing — flagship quality requires all size classes implemented.');
|
|
718
|
+
items.push('Any must_handle state not implemented — flagship requires full contract compliance.');
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const numbered = items.map((item, i) => `${i + 1}. ${item}`);
|
|
722
|
+
numbered.unshift('After generation, verify the output does NOT exhibit these AI-slop indicators:');
|
|
723
|
+
|
|
724
|
+
if (personality) {
|
|
725
|
+
numbered.push(`Design personality check: "${personality}" — verify the output tone matches.`);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return numbered.join('\n');
|
|
729
|
+
}
|
|
730
|
+
|
|
684
731
|
function buildDesignContext(manifest: Record<string, any>): PrepareResult['design_context'] {
|
|
685
732
|
const design = manifest.design;
|
|
686
733
|
if (!design) return undefined;
|
|
687
734
|
const complexity = (design.complexity as 'restrained' | 'balanced' | 'elaborate') ?? 'balanced';
|
|
735
|
+
const tier = (design.quality_tier as 'mvp' | 'production' | 'flagship') ?? 'production';
|
|
688
736
|
return {
|
|
689
737
|
...(design.personality ? { personality: design.personality } : {}),
|
|
690
738
|
complexity,
|
|
739
|
+
quality_tier: tier,
|
|
691
740
|
...(design.audience ? { audience: design.audience } : {}),
|
|
692
741
|
complexity_rule: complexityRule(complexity),
|
|
742
|
+
quality_tier_rule: qualityTierRule(tier),
|
|
743
|
+
quality_test: buildQualityTest(complexity, tier, design.personality),
|
|
693
744
|
};
|
|
694
745
|
}
|
|
695
746
|
|
|
@@ -271,6 +271,12 @@
|
|
|
271
271
|
"description": "How elaborate animations, effects, and visual details should be"
|
|
272
272
|
},
|
|
273
273
|
"audience": { "type": "string", "description": "Who uses this app — informs tone and complexity" },
|
|
274
|
+
"quality_tier": {
|
|
275
|
+
"type": "string",
|
|
276
|
+
"enum": ["mvp", "production", "flagship"],
|
|
277
|
+
"default": "production",
|
|
278
|
+
"description": "Quality bar — mvp: functional-only, production: polished with full tokens, flagship: pixel-perfect with every state and motion pattern"
|
|
279
|
+
},
|
|
274
280
|
"avoid": {
|
|
275
281
|
"type": "array",
|
|
276
282
|
"items": { "type": "string" },
|
|
@@ -293,6 +299,8 @@
|
|
|
293
299
|
"motion": { "type": "array", "items": { "type": "string" } },
|
|
294
300
|
"elevation": { "type": "array", "items": { "type": "string" } },
|
|
295
301
|
"layout": { "type": "array", "items": { "type": "string" } },
|
|
302
|
+
"visual": { "type": "array", "items": { "type": "string" } },
|
|
303
|
+
"interaction": { "type": "array", "items": { "type": "string" } },
|
|
296
304
|
"accessibility": { "type": "array", "items": { "type": "string" } }
|
|
297
305
|
},
|
|
298
306
|
"additionalProperties": false
|
package/spec/openuispec-v0.2.md
CHANGED
|
@@ -92,19 +92,23 @@ generation:
|
|
|
92
92
|
ios: { language: swift, framework: swiftui }
|
|
93
93
|
android: { language: kotlin, framework: compose }
|
|
94
94
|
web: { language: typescript, framework: react }
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
|
|
96
|
+
generation_guidance: # Section 16.2
|
|
97
|
+
universal_anti_patterns:
|
|
98
|
+
typography:
|
|
99
|
+
- "Do not fall back to Inter, Roboto, Arial, or system defaults"
|
|
100
|
+
color:
|
|
101
|
+
- "Do not use pure black (#000000) or pure white (#FFFFFF)"
|
|
102
|
+
# ... additional domains: spacing, motion, elevation, layout, visual, interaction, accessibility
|
|
103
|
+
audit_threshold: 70
|
|
104
|
+
|
|
105
|
+
design: # Section 16.1
|
|
106
|
+
personality: "Clean, focused..."
|
|
107
|
+
complexity: "balanced" # restrained | balanced | elaborate
|
|
108
|
+
quality_tier: "production" # mvp | production | flagship
|
|
109
|
+
audience: "..."
|
|
110
|
+
avoid:
|
|
111
|
+
- "Do not use decorative gradients"
|
|
108
112
|
```
|
|
109
113
|
|
|
110
114
|
---
|
|
@@ -4098,6 +4102,148 @@ Each `.yaml` file in the components directory defines one component. The file mu
|
|
|
4098
4102
|
|
|
4099
4103
|
---
|
|
4100
4104
|
|
|
4105
|
+
## 16. Design intent and generation guidance
|
|
4106
|
+
|
|
4107
|
+
This section defines how the manifest communicates design intent, anti-patterns, and quality expectations to AI generators.
|
|
4108
|
+
|
|
4109
|
+
### 16.1 Design section
|
|
4110
|
+
|
|
4111
|
+
The `design` section in `openuispec.yaml` captures the project's visual identity and quality bar:
|
|
4112
|
+
|
|
4113
|
+
```yaml
|
|
4114
|
+
design:
|
|
4115
|
+
personality: "Minimal and calm — clarity over decoration"
|
|
4116
|
+
complexity: "restrained" # restrained | balanced | elaborate
|
|
4117
|
+
quality_tier: "production" # mvp | production | flagship
|
|
4118
|
+
audience: "Professionals who prefer low-distraction tools"
|
|
4119
|
+
avoid:
|
|
4120
|
+
- "Do not add decorative illustrations or background patterns"
|
|
4121
|
+
- "[web] Do not use CSS animations for non-interactive purposes"
|
|
4122
|
+
```
|
|
4123
|
+
|
|
4124
|
+
| Field | Type | Default | Description |
|
|
4125
|
+
|-------|------|---------|-------------|
|
|
4126
|
+
| `personality` | string | — | Brief description of the brand's visual personality |
|
|
4127
|
+
| `complexity` | enum | `balanced` | How elaborate animations, effects, and visual details should be |
|
|
4128
|
+
| `quality_tier` | enum | `production` | Quality bar for this project |
|
|
4129
|
+
| `audience` | string | — | Who uses this app — informs tone and complexity |
|
|
4130
|
+
| `avoid` | string[] | — | Project-specific anti-patterns. May use `[web]`/`[ios]`/`[android]` scope tags |
|
|
4131
|
+
|
|
4132
|
+
**Complexity levels:**
|
|
4133
|
+
|
|
4134
|
+
| Level | Meaning |
|
|
4135
|
+
|-------|---------|
|
|
4136
|
+
| `restrained` | Minimal motion (required state transitions only). No decorative shadows. Clean whitespace. No background effects. |
|
|
4137
|
+
| `balanced` | Apply all motion patterns. Use elevation tokens fully. Standard state animations. |
|
|
4138
|
+
| `elaborate` | Rich animations with staggered reveals. Creative elevation. Platform-specific flourishes. |
|
|
4139
|
+
|
|
4140
|
+
**Quality tiers:**
|
|
4141
|
+
|
|
4142
|
+
| Tier | Meaning |
|
|
4143
|
+
|------|---------|
|
|
4144
|
+
| `mvp` | Functional-only. Use semantic tokens but tolerate simple layouts. Skip elevation, motion patterns, and adaptive breakpoints. |
|
|
4145
|
+
| `production` | Production-quality. Apply all tokens, handle accessibility, support adaptive breakpoints. Motion and elevation expected. |
|
|
4146
|
+
| `flagship` | Pixel-perfect. Every token, motion pattern, elevation level, and adaptive breakpoint must be implemented. All contract states required. No shortcuts. |
|
|
4147
|
+
|
|
4148
|
+
### 16.2 Generation guidance
|
|
4149
|
+
|
|
4150
|
+
The `generation_guidance` section in `openuispec.yaml` provides cross-contract anti-patterns and quality thresholds:
|
|
4151
|
+
|
|
4152
|
+
```yaml
|
|
4153
|
+
generation_guidance:
|
|
4154
|
+
universal_anti_patterns:
|
|
4155
|
+
typography:
|
|
4156
|
+
- "Do not fall back to Inter, Roboto, Arial, or system defaults when the spec defines a custom font_family"
|
|
4157
|
+
color:
|
|
4158
|
+
- "Do not use pure black (#000000) or pure white (#FFFFFF)"
|
|
4159
|
+
visual:
|
|
4160
|
+
- "Do not apply gradient text — it fails contrast checks"
|
|
4161
|
+
interaction:
|
|
4162
|
+
- "Do not treat hover and focus as the same state"
|
|
4163
|
+
# ... additional domains
|
|
4164
|
+
audit_threshold: 70
|
|
4165
|
+
```
|
|
4166
|
+
|
|
4167
|
+
**Anti-pattern domains:**
|
|
4168
|
+
|
|
4169
|
+
| Domain | Scope |
|
|
4170
|
+
|--------|-------|
|
|
4171
|
+
| `typography` | Font choices, weights, scale usage |
|
|
4172
|
+
| `color` | Palettes, contrast, pure values |
|
|
4173
|
+
| `spacing` | Scale adherence, alias usage |
|
|
4174
|
+
| `motion` | Easing, duration, reduced-motion |
|
|
4175
|
+
| `elevation` | Shadow usage, depth hierarchy |
|
|
4176
|
+
| `layout` | Size classes, breakpoints, card usage |
|
|
4177
|
+
| `visual` | Decoration, gradients, glassmorphism |
|
|
4178
|
+
| `interaction` | State handling, focus vs hover, gestures |
|
|
4179
|
+
| `accessibility` | Color-only differentiation, focus rings, tab order |
|
|
4180
|
+
|
|
4181
|
+
Anti-patterns are scoped with platform tags (`[web]`, `[ios]`, `[android]`). The `prepare` command filters them to the target platform before delivery to the generator.
|
|
4182
|
+
|
|
4183
|
+
Anti-patterns exist at three levels:
|
|
4184
|
+
1. **Universal** — `generation_guidance.universal_anti_patterns` in the manifest (cross-contract)
|
|
4185
|
+
2. **Contract-specific** — `generation.must_avoid` in each contract file
|
|
4186
|
+
3. **Project-specific** — `design.avoid` in the manifest
|
|
4187
|
+
|
|
4188
|
+
### 16.3 Design quality audit
|
|
4189
|
+
|
|
4190
|
+
The `check --audit` command scores the spec against design quality heuristics.
|
|
4191
|
+
|
|
4192
|
+
**Score formula:** `max(0, 100 - errors × 10 - warnings × 3)`
|
|
4193
|
+
|
|
4194
|
+
**Checks performed:**
|
|
4195
|
+
|
|
4196
|
+
| Domain | Rule | Severity | What it catches |
|
|
4197
|
+
|--------|------|----------|----------------|
|
|
4198
|
+
| tokens | `missing_file` | error | Required token file not found |
|
|
4199
|
+
| typography | `font_diversity` | error | Primary font is an AI default (Inter, Roboto, Arial, Open Sans) |
|
|
4200
|
+
| typography | `scale_usage` | warning | Fewer than 4 type scale levels |
|
|
4201
|
+
| typography | `weight_hierarchy` | warning | Single font weight across the entire type scale |
|
|
4202
|
+
| color | `pure_black` | error | Literal #000000 in token values |
|
|
4203
|
+
| color | `pure_white` | error | Literal #FFFFFF in token values |
|
|
4204
|
+
| color | `semantic_completeness` | warning | Missing success, warning, danger, or info semantic color |
|
|
4205
|
+
| color | `theme_coverage` | warning | Missing light or dark theme |
|
|
4206
|
+
| spacing | `scale_usage` | warning | Fewer than 4 spacing scale values |
|
|
4207
|
+
| spacing | `alias_page_margin` | warning | No page_margin alias defined |
|
|
4208
|
+
| spacing | `alias_card_padding` | warning | No card_padding alias defined |
|
|
4209
|
+
| motion | `duration_variety` | warning | Single duration value for all animations |
|
|
4210
|
+
| motion | `reduced_motion` | error | No reduced_motion policy |
|
|
4211
|
+
| motion | `easing_quality` | warning | Missing enter/exit curves or no cubic-bezier easing |
|
|
4212
|
+
| elevation | `level_count` | warning | Fewer than 2 non-none elevation levels |
|
|
4213
|
+
| elevation | `progression` | warning | Elevation levels not monotonically increasing |
|
|
4214
|
+
| layout | `size_class_coverage` | warning | Fewer than 2 size classes or no compact class |
|
|
4215
|
+
| contracts | `collection_empty_state` | warning | Collection missing empty_state in must_handle |
|
|
4216
|
+
| contracts | `state_coverage` | warning | Contract with empty must_handle |
|
|
4217
|
+
|
|
4218
|
+
The `audit_threshold` in `generation_guidance` sets the project-wide minimum score. The `--min-score` CLI flag overrides it per-run.
|
|
4219
|
+
|
|
4220
|
+
### 16.4 Prepare output
|
|
4221
|
+
|
|
4222
|
+
The `prepare` command includes `design_context` and `anti_patterns` in its output for AI generators:
|
|
4223
|
+
|
|
4224
|
+
```json
|
|
4225
|
+
{
|
|
4226
|
+
"design_context": {
|
|
4227
|
+
"personality": "Minimal and calm...",
|
|
4228
|
+
"complexity": "restrained",
|
|
4229
|
+
"quality_tier": "production",
|
|
4230
|
+
"audience": "...",
|
|
4231
|
+
"complexity_rule": "Minimal motion (required state transitions only)...",
|
|
4232
|
+
"quality_tier_rule": "Production-quality. Apply all tokens...",
|
|
4233
|
+
"quality_test": "After generation, verify the output does NOT exhibit these AI-slop indicators:\n1. Inter/Roboto/Arial as the primary font..."
|
|
4234
|
+
},
|
|
4235
|
+
"anti_patterns": {
|
|
4236
|
+
"universal": { "typography": ["..."], "color": ["..."] },
|
|
4237
|
+
"contract_specific": { "action_trigger": ["..."] },
|
|
4238
|
+
"project_specific": ["..."]
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
```
|
|
4242
|
+
|
|
4243
|
+
The `quality_test` field is an auto-generated checklist tuned to the project's complexity and quality tier. AI generators should use it as a post-generation self-review step.
|
|
4244
|
+
|
|
4245
|
+
---
|
|
4246
|
+
|
|
4101
4247
|
## Appendix A: Type reference
|
|
4102
4248
|
|
|
4103
4249
|
| Type | Description | Example |
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|