@easysociable/cli 0.1.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 +21 -0
- package/README.md +95 -0
- package/bin/easysociable.js +15 -0
- package/dist/easysociable.js +35464 -0
- package/dist/easysociable.js.map +1 -0
- package/package.json +58 -0
- package/skills/ONBOARDING.md +61 -0
- package/skills/easysociable-content/SKILL.md +115 -0
- package/skills/easysociable-content/platforms/claude.md +5 -0
- package/skills/easysociable-content/platforms/codex.md +5 -0
- package/skills/easysociable-content/platforms/hermes.md +5 -0
- package/skills/easysociable-content/platforms/openclaw.md +5 -0
- package/skills/easysociable-content/references/CLI.md +27 -0
- package/skills/easysociable-content/references/MCP.md +20 -0
- package/skills/easysociable-content/references/PAGE_PACK.md +6 -0
- package/skills/easysociable-content/references/TROUBLESHOOTING.md +11 -0
- package/skills/easysociable-content/references/VAULT.md +20 -0
- package/skills/easysociable-content/scripts/setup.mjs +156 -0
- package/skills/easysociable-content/scripts/setup.test.mjs +71 -0
- package/skills/easysociable-content/scripts/starter.mjs +53 -0
- package/skills/easysociable-content/workflows/ANALYSIS_AND_COVERAGE.md +8 -0
- package/skills/easysociable-content/workflows/CONTENT_EXPORT.md +19 -0
- package/skills/easysociable-content/workflows/DEVICE_TASKS.md +5 -0
- package/skills/easysociable-content/workflows/EXPERIMENTS.md +6 -0
- package/skills/easysociable-content/workflows/MCP_FIRST.md +10 -0
- package/skills/easysociable-content/workflows/PUBLICATION.md +5 -0
- package/skills/easysociable-content/workflows/TOPIC_DRAFT.md +5 -0
- package/skills/easysociable-content/workflows/WORKING_DRAFT.md +10 -0
- package/skills/easysociable-slideshow/SKILL.md +77 -0
- package/skills/easysociable-slideshow/references/CONTENT_PACK.md +25 -0
- package/skills/easysociable-slideshow/references/GATEWAY.md +16 -0
- package/skills/easysociable-slideshow/references/PLATFORM_CAPS.md +17 -0
- package/skills/easysociable-slideshow/references/VAULT.md +18 -0
- package/skills/easysociable-slideshow/workflows/CREATE_RUN.md +7 -0
- package/skills/easysociable-slideshow/workflows/MCP_FIRST.md +14 -0
- package/skills/easysociable-slideshow/workflows/OUT_OF_SCOPE.md +8 -0
- package/skills/easysociable-slideshow/workflows/PUBLISH_RUN.md +4 -0
- package/skills/easysociable-slideshow/workflows/RENDER_RUN.md +6 -0
- package/skills/easysociable-template/SKILL.md +106 -0
- package/skills/easysociable-template/references/AUTHORING_SOURCE.md +129 -0
- package/skills/easysociable-template/references/CATALOG_METADATA.md +221 -0
- package/skills/easysociable-template/references/DESIGN_INTELLIGENCE.md +69 -0
- package/skills/easysociable-template/references/DESIGN_V2_1.md +278 -0
- package/skills/easysociable-template/references/EXTERNAL_RESOURCES.md +52 -0
- package/skills/easysociable-template/references/GATEWAY.md +25 -0
- package/skills/easysociable-template/references/PLATFORM_SPECS.md +134 -0
- package/skills/easysociable-template/references/SLOTS.md +104 -0
- package/skills/easysociable-template/references/THEME_PRESETS.md +48 -0
- package/skills/easysociable-template/references/THEME_TOKENS.md +89 -0
- package/skills/easysociable-template/references/fixtures/surface-gradient.design-plan.json +74 -0
- package/skills/easysociable-template/references/theme-presets.json +95 -0
- package/skills/easysociable-template/scripts/generate-theme-from-hex.mjs +402 -0
- package/skills/easysociable-template/scripts/validate-authoring-source.mjs +228 -0
- package/skills/easysociable-template/scripts/validate-design-v2.mjs +318 -0
- package/skills/easysociable-template/workflows/ASSET_PLAN.md +34 -0
- package/skills/easysociable-template/workflows/AUTHORING_FROM_BRIEF.md +52 -0
- package/skills/easysociable-template/workflows/AUTHORING_FROM_IMAGE.md +52 -0
- package/skills/easysociable-template/workflows/AUTHORING_STUDIO.md +122 -0
- package/skills/easysociable-template/workflows/DESIGN_BRIEF.md +92 -0
- package/skills/easysociable-template/workflows/DESIGN_CONCEPTS.md +41 -0
- package/skills/easysociable-template/workflows/DESIGN_PHILOSOPHY.md +69 -0
- package/skills/easysociable-template/workflows/FILL_AND_RENDER.md +86 -0
- package/skills/easysociable-template/workflows/MCP_FIRST.md +9 -0
- package/skills/easysociable-template/workflows/OUT_OF_SCOPE.md +15 -0
- package/skills/easysociable-template/workflows/PALETTE_REVIEW.md +71 -0
- package/skills/easysociable-template/workflows/PUBLISH_FROM_DRAFT.md +60 -0
- package/skills/easysociable-template/workflows/SURFACE_REVIEW.md +178 -0
- package/skills/easysociable-template/workflows/THEME_FROM_BRAND.md +73 -0
- package/skills/easysociable-template/workflows/VISUAL_QA.md +55 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Design concepts (text brief V2.1)
|
|
2
|
+
|
|
3
|
+
Run after `DESIGN_PHILOSOPHY.md` (and `DESIGN_BRIEF.md` for text intake). Act as an art director expressing one shared philosophy, not a slogan generator.
|
|
4
|
+
|
|
5
|
+
## Output
|
|
6
|
+
|
|
7
|
+
Create **2–3 materially different concepts**. They are **spatial variations of the same `philosophy`**, like canvas-design multi-page twists — not three unrelated moods.
|
|
8
|
+
|
|
9
|
+
Each concept must specify:
|
|
10
|
+
|
|
11
|
+
- `id`, name, one-sentence rationale, and a recognisable visual motif
|
|
12
|
+
- `philosophyExpression` — how this layout expresses the shared philosophy in space (required)
|
|
13
|
+
- Canvas zones with approximate `x/y/width/height`
|
|
14
|
+
- Focal hierarchy: primary, secondary, attribution
|
|
15
|
+
- Typography system: display/body contrast and approximate scale ratio (traceable to `philosophy.typographyAccent`)
|
|
16
|
+
- Color strategy: canvas/ink/muted/one dominant accent (mood only; hex via Theme pipeline)
|
|
17
|
+
- `paletteCandidates` (optional but recommended): named options such as `[{ "name": "Ocean Depths", "presetId": "ocean-depths", "brandHex": "#1A6B6B", "mode": "light", "bestFor": "…" }]` — prefer `references/THEME_PRESETS.md` when user has no brand color
|
|
18
|
+
- Asset strategy: none, CSS/SVG, reuse, or generate
|
|
19
|
+
- Whitespace/density strategy and concrete risks
|
|
20
|
+
|
|
21
|
+
Changing only colors, radius, or shadows does not create a different concept. Change at least two of: composition, focal placement, type treatment, visual motif, asset role.
|
|
22
|
+
|
|
23
|
+
`layout` / `hierarchy` / `typography` must be clearly derivable from `philosophy.space` / `composition` / `rhythm` / `typographyAccent`.
|
|
24
|
+
|
|
25
|
+
## Selection
|
|
26
|
+
|
|
27
|
+
- Show concise concept summaries when the user asked to choose or collaborate.
|
|
28
|
+
- Otherwise recommend and select the strongest concept; state why it best serves the one-glance job **and** the shared philosophy.
|
|
29
|
+
- Keep rejected concepts in `design-plan.json` so the decision remains auditable.
|
|
30
|
+
- Use one concept only for `source.kind = image_reference`, where the reference already determines composition (still require `philosophyExpression`).
|
|
31
|
+
|
|
32
|
+
## Guardrails
|
|
33
|
+
|
|
34
|
+
- Use one dominant focal idea.
|
|
35
|
+
- Prefer editorial hierarchy over a grid of generic SaaS cards.
|
|
36
|
+
- Make decorative choices reinforce the philosophy’s rhythm; do not add illustration by default.
|
|
37
|
+
- Keep replaceable text, numbers, avatars, and logos editable.
|
|
38
|
+
- Design for realistic stress content: long name, large number, missing optional asset.
|
|
39
|
+
- Do not invent a second philosophy per concept.
|
|
40
|
+
|
|
41
|
+
Continue to `ASSET_PLAN.md`, then `PALETTE_REVIEW.md` and `THEME_FROM_BRAND.md` when co-creating a theme. Validate `design-plan.json` and `theme-tokens.json` using `references/DESIGN_V2_1.md`.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Design philosophy (after brief, before concepts)
|
|
2
|
+
|
|
3
|
+
Borrow canvas-design’s order: name a visual movement, write the aesthetic worldview, then express it as layout concepts. This is **not** a free-art poster workflow — the philosophy must serve a one-glance social template with editable slots.
|
|
4
|
+
|
|
5
|
+
## When to run
|
|
6
|
+
|
|
7
|
+
- After `DESIGN_BRIEF.md` for `source.kind = text_brief`
|
|
8
|
+
- After image inspection for `AUTHORING_FROM_IMAGE.md` (short reverse-engineered philosophy is enough)
|
|
9
|
+
- Before `DESIGN_CONCEPTS.md`
|
|
10
|
+
|
|
11
|
+
Skip only when reusing an already validated `design-plan.json` that already contains `philosophy`.
|
|
12
|
+
|
|
13
|
+
## Goal
|
|
14
|
+
|
|
15
|
+
Produce one shared philosophy that later concepts will express differently in space. Do **not** invent three unrelated slogans.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
19
|
+
### 1. Name the movement (1–2 words)
|
|
20
|
+
|
|
21
|
+
Examples adapted for social templates: `Editorial Ledger`, `Terminal Pulse`, `Quiet Proof`, `Monument Metric`, `Warm Folio`.
|
|
22
|
+
|
|
23
|
+
Seed from `references/DESIGN_INTELLIGENCE.md` when stuck.
|
|
24
|
+
|
|
25
|
+
### 2. Write the philosophy (4–6 short paragraphs or structured fields)
|
|
26
|
+
|
|
27
|
+
Cover each once (no redundancy):
|
|
28
|
+
|
|
29
|
+
| Field | Ask |
|
|
30
|
+
|-------|-----|
|
|
31
|
+
| `space` | Margins, breathing room, density, where emptiness works |
|
|
32
|
+
| `color` | Mood and limit strategy (not final hex — that comes from Theme pipeline) |
|
|
33
|
+
| `rhythm` | Repeating system: rules, dots, grids, cadence of decoration |
|
|
34
|
+
| `composition` | Zones, focal placement, what stays quiet |
|
|
35
|
+
| `typographyAccent` | Display vs body ratio; where type is a gesture vs metadata |
|
|
36
|
+
| `craftBar` | One sentence: museum-grade spacing, no overlap, one focal, refine before adding |
|
|
37
|
+
|
|
38
|
+
Optional but recommended:
|
|
39
|
+
|
|
40
|
+
| Field | Ask |
|
|
41
|
+
|-------|-----|
|
|
42
|
+
| `subtleReference` | Quiet conceptual DNA (jazz quote, not a label sticker) |
|
|
43
|
+
| `templateConstraints` | Slots stay bindable; flat absolute siblings; Theme owns color; never flatten copy into a poster |
|
|
44
|
+
|
|
45
|
+
Also write companion `design-philosophy.md` for humans using the structure in `references/DESIGN_V2_1.md`.
|
|
46
|
+
|
|
47
|
+
### 3. Template hard constraints (must appear in philosophy or `templateConstraints`)
|
|
48
|
+
|
|
49
|
+
Rewrite canvas-design’s “minimal text / pure art” into template-safe rules:
|
|
50
|
+
|
|
51
|
+
1. **Slots win clarity** — required brief slots become bindable nodes; philosophy may demand sparse chrome, not missing content.
|
|
52
|
+
2. **Theme owns hex** — philosophy states mood/limit only; concrete colors go through `PALETTE_REVIEW.md` + `THEME_FROM_BRAND.md`.
|
|
53
|
+
3. **Decoration is rhythm** — prefer CSS/SVG repeats (lines, dots, grids) over new illustrations.
|
|
54
|
+
4. **Flat absolute layout** — zones are canvas siblings; card chrome is a background sibling, never a nested absolute group.
|
|
55
|
+
5. **Readable focal** — subtle reference is allowed, but title/metric must be one-glance clear on social canvases.
|
|
56
|
+
|
|
57
|
+
### 4. Hand off
|
|
58
|
+
|
|
59
|
+
Continue to `DESIGN_CONCEPTS.md`. Every concept must include `philosophyExpression` describing how **this** spatial plan expresses the shared philosophy.
|
|
60
|
+
|
|
61
|
+
Embed `philosophy` into `design-plan.json` before validation.
|
|
62
|
+
|
|
63
|
+
## Do not
|
|
64
|
+
|
|
65
|
+
- Skip philosophy and jump to SaaS three-card layouts
|
|
66
|
+
- Write a philosophy that forbids required text slots
|
|
67
|
+
- Encode final brand hex only inside philosophy prose (use Theme pipeline)
|
|
68
|
+
- Treat philosophy as a PNG art brief that replaces `authoringSource`
|
|
69
|
+
- Ship canvas-design font files; map voice → Theme fonts via `DESIGN_INTELLIGENCE.md`
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Fill slots and Hosted Render (published template)
|
|
2
|
+
|
|
3
|
+
Primary **Agent use** of a published single-page template: read the public slot table, fill values, submit a Hosted Render Job, poll for Artifact / Manifest.
|
|
4
|
+
|
|
5
|
+
This path belongs to **Template Skill** (ADR-0021 / AC-25~26). Do **not** hand off to Content Skill for single-page fill-slots out图.
|
|
6
|
+
|
|
7
|
+
## Preconditions
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
easysociable auth status --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Prefer Template MCP tools when available; CLI is the fallback.
|
|
14
|
+
|
|
15
|
+
## Steps
|
|
16
|
+
|
|
17
|
+
### 1. Get template + public slots
|
|
18
|
+
|
|
19
|
+
**MCP:** `get_template({ templateId })`
|
|
20
|
+
**CLI:** `easysociable templates get --id <id> --json`
|
|
21
|
+
|
|
22
|
+
Response MUST include `slots[]` with `key`, `type`, `required`, optional `maxCharacters` / `overflow` / `aiHint` / `label`.
|
|
23
|
+
MUST NOT include AST, Binding Map, or RenderPlan.
|
|
24
|
+
|
|
25
|
+
### 2. Fill slots
|
|
26
|
+
|
|
27
|
+
| Slot type | Agent action |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `text` / `number` | Generate from user brief; respect `maxCharacters` / required |
|
|
30
|
+
| `image` | Ask user: upload or choose an existing account image. After confirmation, use `import_template_image` / the unified image import flow so the bytes are stored through Gateway → R2 and the metadata is recorded in the existing Directus `Image` collection; put the returned **`imageId`** in the slot. Never pass temporary Unsplash/Pexels/Pinterest URLs, local paths or transient asset IDs as authority. |
|
|
31
|
+
|
|
32
|
+
Omit optional empty slots (`null` / `''`) rather than inventing filler.
|
|
33
|
+
|
|
34
|
+
All V1 image uploads use the account image import flow. There is no separate
|
|
35
|
+
transient render-asset command.
|
|
36
|
+
|
|
37
|
+
### 3. Create Hosted Render Job
|
|
38
|
+
|
|
39
|
+
**MCP:** `create_render_job({ templateId, slots, outputFormats, idempotencyKey? })`
|
|
40
|
+
**CLI:**
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
easysociable renders create \
|
|
44
|
+
--template-id <id> \
|
|
45
|
+
--slots '{"title":"Hello","caption":"World"}' \
|
|
46
|
+
--format png \
|
|
47
|
+
--idempotency-key fill_1 \
|
|
48
|
+
--json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Forbidden inputs:** `ContentDocument`, `contentDocumentHash`, client `RenderPlan`, AST, Binding Map.
|
|
52
|
+
|
|
53
|
+
### 4. Poll Job / Manifest
|
|
54
|
+
|
|
55
|
+
**MCP:** `get_render_job({ jobId })` → when completed, `get_render_manifest` if needed
|
|
56
|
+
**CLI:** `easysociable renders wait --id <id> --json`
|
|
57
|
+
|
|
58
|
+
Success: signed Artifact URL(s) on the public Manifest.
|
|
59
|
+
Job may also return `previewUrl` + `capture` (signed Studio-parity page). Deliver the **Hosted Artifact**, not a local screenshot of that preview URL.
|
|
60
|
+
|
|
61
|
+
### 5. Hosted Capture failure
|
|
62
|
+
|
|
63
|
+
V1 does not expose a second local capture command. If Hosted Capture fails,
|
|
64
|
+
surface the Gateway error and retry only when it is marked retryable; do not
|
|
65
|
+
invent a browser URL, selector or viewport and do not treat an Authoring Studio
|
|
66
|
+
screenshot as a billable final Artifact.
|
|
67
|
+
|
|
68
|
+
#### Error-code table
|
|
69
|
+
|
|
70
|
+
| Code / signal | Local capture? | Agent action |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Job `completed` + Manifest Artifact | No | Deliver signed Artifact URL(s) |
|
|
73
|
+
| Retryable worker/queue/5xx error | No | Retry Hosted with the same idempotency key |
|
|
74
|
+
| Rate limit | No | Respect retry-after/backoff and retry once if allowed |
|
|
75
|
+
| `VALIDATION_ERROR` / missing required slots | **No** | Fix slots; no fallback expected |
|
|
76
|
+
| Auth / entitlement / tier denied | **No** | Fix credentials/plan; no fallback |
|
|
77
|
+
Failed jobs without a retryable error are surfaced to the user; no freestyle
|
|
78
|
+
browser screenshot is accepted as final output.
|
|
79
|
+
|
|
80
|
+
## Anti-patterns
|
|
81
|
+
|
|
82
|
+
- Building or submitting a local RenderPlan / AST / Binding Map
|
|
83
|
+
- Using ContentDocument export as a render prerequisite
|
|
84
|
+
- Treating Studio html-to-image as Hosted delivery or as the default on success
|
|
85
|
+
- Local capture when Hosted succeeded or when `fallback.capture` is absent
|
|
86
|
+
- Calling Content MCP/CLI for this single-page fill-slots flow
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# MCP-first
|
|
2
|
+
|
|
3
|
+
Use the unified EasySociable MCP for Template authoring, images, icons, Profiles,
|
|
4
|
+
Themes and Render Jobs. Fall back to the equivalent `easysociable` CLI command
|
|
5
|
+
only when MCP is unavailable.
|
|
6
|
+
|
|
7
|
+
Neither path may call Local API, SQLite, Directus, R2, Stripe, private Template
|
|
8
|
+
Service or a third-party provider through EasySociable. Host-installed image
|
|
9
|
+
MCPs are optional discovery tools and are never auto-installed.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Out of scope for template-skill
|
|
2
|
+
|
|
3
|
+
If the user asks for any of the following, **do not** execute them under this skill:
|
|
4
|
+
|
|
5
|
+
| Request | Hand off |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Generate爆款 copy / topic / Working Draft as Content product | Content Skill |
|
|
8
|
+
| Export `ContentDocument` / checkpoint Content Version | Content Skill |
|
|
9
|
+
| Compose or render a **multi-slide** slideshow Run | **easysociable-slideshow** |
|
|
10
|
+
| Pick Theme as slideshow “Look” for a whole Run | **easysociable-slideshow** + Profile Theme |
|
|
11
|
+
| Local Obsidian content authoring | Content Skill |
|
|
12
|
+
| UGC/publication/social posting | Deferred in V1 |
|
|
13
|
+
| Submit `contentDocumentHash` / ContentDocument to Template render | **Forbidden** — use fill-slots (`FILL_AND_RENDER.md`) |
|
|
14
|
+
|
|
15
|
+
**In scope:** single-page template authoring/publish **and** fill-slots Hosted Render of one published PageTemplate (`get_template` → slots → `create_render_job`).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Palette review
|
|
2
|
+
|
|
3
|
+
Choose between 2–3 palette directions and lock theme tokens before layout authoring.
|
|
4
|
+
Adapted from Anthropic `theme-factory`: **show → ask → wait for explicit choice → apply**.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
- After concept selection in `DESIGN_CONCEPTS.md`
|
|
9
|
+
- Before `AUTHORING_FROM_BRIEF.md` or `AUTHORING_FROM_IMAGE.md` build step
|
|
10
|
+
- When co-creating Theme (no reusable `themeId`)
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Build **2–3 named candidates** (not anonymous A/B hexes):
|
|
15
|
+
- From user brand hex → light/dark (or slight hex variants) via generator
|
|
16
|
+
- Or from `references/THEME_PRESETS.md` / `theme-presets.json` when no brand hex
|
|
17
|
+
- Each candidate needs: `name`, `brandHex`, `mode`, `bestFor` (and optional `notFor` / `presetId`)
|
|
18
|
+
2. Generate a candidate file per option:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node scripts/generate-theme-from-hex.mjs --preset ocean-depths -o theme-candidate-ocean.json
|
|
22
|
+
node scripts/generate-theme-from-hex.mjs --preset tech-innovation -o theme-candidate-tech.json
|
|
23
|
+
node scripts/generate-theme-from-hex.mjs #0D9488 --mode light -o theme-candidate-custom.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. **Showcase (required)** — present a swatch table before asking the user to choose. Do not dump raw JSON as the only view:
|
|
27
|
+
|
|
28
|
+
| Name | Preset / custom | Mode | brandHex | Accent | Contrast | bestFor |
|
|
29
|
+
|------|-----------------|------|----------|--------|----------|---------|
|
|
30
|
+
| Ocean Depths | ocean-depths | light | #1A6B6B | … | pass | Finance, trust metrics |
|
|
31
|
+
| Tech Innovation | tech-innovation | dark | #2563EB | … | pass | Startups, launches |
|
|
32
|
+
|
|
33
|
+
Include one-line canvas/accent feel from each candidate’s `themeTokens.colors`.
|
|
34
|
+
|
|
35
|
+
4. **Ask and wait** — which theme to apply? Do **not** call `theme.create` or finalize `theme-tokens.json` until the user explicitly confirms (or they already said “直接用 X / 你定”).
|
|
36
|
+
5. On confirmation, copy the winner to `theme-tokens.json` and set Theme create **name** to the candidate `name` (e.g. `Ocean Depths`), never `Theme draft_xxx`.
|
|
37
|
+
6. Update `design-plan.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
"themePreview": {
|
|
41
|
+
"name": "Ocean Depths",
|
|
42
|
+
"presetId": "ocean-depths",
|
|
43
|
+
"brandHex": "#1A6B6B",
|
|
44
|
+
"activeMode": "light",
|
|
45
|
+
"contrastPass": true,
|
|
46
|
+
"bestFor": "Finance, consulting, trust-building metric cards",
|
|
47
|
+
"themeTokensPath": "theme-tokens.json",
|
|
48
|
+
"userConfirmed": true
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
7. Run `node scripts/validate-design-v2.mjs design-plan.json` and `theme-tokens.json`.
|
|
53
|
+
8. Continue to `THEME_FROM_BRAND.md` only if tokens still need regeneration; otherwise proceed to authoring with the locked file.
|
|
54
|
+
|
|
55
|
+
## Contrast checklist (before authoring)
|
|
56
|
+
|
|
57
|
+
- [ ] `text` on `canvas` ≥ 4.5:1 (AA body text)
|
|
58
|
+
- [ ] `muted` on `canvas` ≥ 4.5:1
|
|
59
|
+
- [ ] `accent` on `canvas` ≥ 3:1 (accent text / links)
|
|
60
|
+
- [ ] `label` on `primary` ≥ 3:1 (filled buttons — light text on dark primary in dark mode)
|
|
61
|
+
- [ ] Screenshot spot-check: no neon-on-neon or gray-on-gray failures
|
|
62
|
+
|
|
63
|
+
If any pair fails, regenerate or switch mode — do not proceed to `authoringSource`.
|
|
64
|
+
|
|
65
|
+
## Do not
|
|
66
|
+
|
|
67
|
+
- Apply a theme without showcase + explicit confirmation (unless user waived choice)
|
|
68
|
+
- Offer palettes that differ only by one shade step
|
|
69
|
+
- Skip `theme-tokens.json` when creating a new theme
|
|
70
|
+
- Override failed contrast with arbitrary hex without re-running the generator
|
|
71
|
+
- Name Gateway themes as `Theme <draftId>`
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Publish from saved draft (Agent path)
|
|
2
|
+
|
|
3
|
+
Authoring Studio has **Save only** — no Publish button.
|
|
4
|
+
After the user saves and says 「publish」/「发布该模板」, the Agent analyzes the draft, completes catalog metadata, and publishes via Gateway.
|
|
5
|
+
|
|
6
|
+
## When to run
|
|
7
|
+
|
|
8
|
+
- User finished editing in `/authoring/{draftId}` and clicked **Save**
|
|
9
|
+
- User explicitly asks to publish (do not auto-publish on create)
|
|
10
|
+
|
|
11
|
+
## Flow
|
|
12
|
+
|
|
13
|
+
1. Load the saved draft:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
easysociable templates get --id <draftId> --json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Analyze public fields only (`authoringSource`, canvas, themeId, existing `selectionMetadata`):
|
|
20
|
+
- Infer `platforms` / `canvasPreset` from canvas + brief
|
|
21
|
+
- Infer `supportedRoles` (1–2) from layout intent / node types
|
|
22
|
+
- Derive `slotSummary` / `requiresImage` / `imageRoles` from fillable slots
|
|
23
|
+
- Fill `contentFamily`, `contentArchetypes`, `density`, `textDensityRange`
|
|
24
|
+
- Prefer P1: `bestFor`, `notFor`, `selectionHints`, `visualStyle`, `locale`
|
|
25
|
+
|
|
26
|
+
3. Show a short P0/P1 summary to the user. Wait for confirmation unless they already said 「直接发布」.
|
|
27
|
+
|
|
28
|
+
4. Write metadata, then publish:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
easysociable templates publish --id <draftId> --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or two steps:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
easysociable templates update --id <draftId> --file ./draft-patch.json --json
|
|
38
|
+
easysociable templates publish --id <draftId> --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
5. Verify catalog discoverability:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
easysociable templates list --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Rules
|
|
48
|
+
|
|
49
|
+
- Never invent private AST / Binding Map from Agent-side.
|
|
50
|
+
- Gateway rejects Publish if any P0 field is missing — fix metadata and retry.
|
|
51
|
+
- Incomplete published pages must not appear in `list` (enforced server-side).
|
|
52
|
+
- Theme co-create drafts may still be published via theme APIs when product requires it; page publish is independent.
|
|
53
|
+
|
|
54
|
+
## Failure recovery
|
|
55
|
+
|
|
56
|
+
| Error | Action |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `VALIDATION_ERROR` missing P0 | Fill missing fields, `update` + `publish` again |
|
|
59
|
+
| `NOT_FOUND` | Confirm `draftId`; user may not have saved |
|
|
60
|
+
| `VERSION_IMMUTABLE` | Draft already published — create a new template instead |
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Surface review (atmosphere layer)
|
|
2
|
+
|
|
3
|
+
Choose and confirm the canvas **surface** before authoring. Surface is independent of Theme semantic colors.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Theme = identity (solid semantic colors + fonts)
|
|
7
|
+
Surface = atmosphere (flat | gradient | image)
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Aligned with ADR-0020 (photos) and ADR-0023 (icons): photo discovery may use host MCPs; icon discovery uses Gateway Icon Catalog; materialization only through Template Gateway.
|
|
11
|
+
|
|
12
|
+
## When to run
|
|
13
|
+
|
|
14
|
+
- After concept selection (`DESIGN_CONCEPTS.md`) and Theme lock (`PALETTE_REVIEW` / `THEME_FROM_BRAND`) when co-creating
|
|
15
|
+
- During `ASSET_PLAN.md` when the brief needs wash, photography backdrop, or icons
|
|
16
|
+
- Skip only when surface is clearly `flat` (typography-only / Theme.canvas) and no icons/photos are required
|
|
17
|
+
|
|
18
|
+
## Surface kinds
|
|
19
|
+
|
|
20
|
+
| `kind` | Discovery | After user confirms | Authoring result |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `flat` | None | — | Theme.canvas only |
|
|
23
|
+
| `gradient` | Template MCP/CLI `gradients list\|search\|get` | Inline CSS decoration sibling (no `bindingKey`) | Atmosphere wash / band |
|
|
24
|
+
| `image` | Host **Pinterest / Unsplash / Pexels** MCP (not Template MCP) | Gateway draft image import → stable CDN `imageId` | Background usually `fixed` |
|
|
25
|
+
| (+ icons) | Template MCP/CLI `search_icons` / `get_icon` | Materialize `TemplateIconAsset` → inline `canonicalSvg` / `iconAssetId` (Theme via `currentColor`) | Icon chrome |
|
|
26
|
+
|
|
27
|
+
Photography for **slots** (avatar, hero well) also uses host image MCPs + Gateway import; ask `fixed` vs `slot_default` (surface background defaults to **`fixed`**).
|
|
28
|
+
|
|
29
|
+
## Steps
|
|
30
|
+
|
|
31
|
+
### 1. Decide kind
|
|
32
|
+
|
|
33
|
+
From brief + philosophy `color` / `rhythm` + selected concept:
|
|
34
|
+
|
|
35
|
+
- Sparse copy + atmospheric mood → prefer `gradient` or soft `image`
|
|
36
|
+
- Dense metrics / checklist → prefer `flat` or a thin gradient band (not full-bleed noisy photo)
|
|
37
|
+
- User asks for photo backdrop / Unsplash vibe → `image`
|
|
38
|
+
- User asks for gradient / wash → `gradient`
|
|
39
|
+
- Default when unsure → `flat`, then ask
|
|
40
|
+
|
|
41
|
+
Record intent in `design-plan.json` → `surfacePreview.kind` (may be unconfirmed).
|
|
42
|
+
|
|
43
|
+
### 2. Discover (bounded candidates only)
|
|
44
|
+
|
|
45
|
+
**Gradient**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
easysociable templates gradients search --q "<mood>" --limit 8 --json
|
|
49
|
+
# or MCP: search_gradients / list_gradients
|
|
50
|
+
easysociable templates gradients get --id <id> --json # only after shortlist interest
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Show a **text table** (MVP: no thumbnails): name, stopSummary, tags, textSafeZone, bestFor.
|
|
54
|
+
|
|
55
|
+
**Image (surface or slot)**
|
|
56
|
+
|
|
57
|
+
1. Call host Unsplash / Pexels / Pinterest MCP with a short query.
|
|
58
|
+
2. Show ≤8 candidates (thumb + attribution if the host MCP returns them).
|
|
59
|
+
3. If the MCP is missing → degrade: say which provider is missing; offer `flat`, `gradient`, user upload, or skip. Do **not** invent URLs or proxy search through Template MCP.
|
|
60
|
+
|
|
61
|
+
**Icons (hard rule)**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
easysociable icons search --query "<concept>" --limit 8 --json
|
|
65
|
+
# or MCP: search_icons
|
|
66
|
+
easysociable icons get --icon-id <iconId> --idempotency-key <key> --json # only after user confirms
|
|
67
|
+
# or MCP: get_icon
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**MUST path (every icon, including “just add an arrow”):**
|
|
71
|
+
|
|
72
|
+
1. Call Template `search_icons` / CLI `icons search` (Gateway Icon Catalog). Show ≤8 candidates with `iconId`, collection, style, license.
|
|
73
|
+
2. Wait for user choice — or explicit waive of choice: “你定 / 用第 N 个 / 随便好看一点的向右箭头”.
|
|
74
|
+
Unselected search hits produce **zero** `TemplateIconAsset` writes.
|
|
75
|
+
3. After confirm, call `get_icon` / CLI `icons get` with a **stable** `idempotencyKey`.
|
|
76
|
+
Embed returned **`canonicalSvg`** only; record **`iconAssetId`**, `iconId`, collection, license, contentHash on the decoration node (e.g. `data-icon-asset-id`, `data-icon-id`).
|
|
77
|
+
4. Color with Theme `currentColor` / `--es-*` on the wrapper; never bake Theme hex into the SVG paths.
|
|
78
|
+
5. If Gateway Icon Catalog / auth **fails** → say so → degrade to **omit** or temporary CSS/SVG shape **only after user agrees**.
|
|
79
|
+
Do **not** fall back to Better Icons MCP, client Iconify, or silent hand-drawn paths.
|
|
80
|
+
|
|
81
|
+
**Forbidden by default (not a shortcut):**
|
|
82
|
+
|
|
83
|
+
- Hand-writing SVG `<path d="…">` for arrows, chevrons, checks, social marks, “next page” cues, or any symbol the catalog can supply.
|
|
84
|
+
- Using emoji as a substitute for catalog icons.
|
|
85
|
+
- Skipping search because “it’s only a small arrow” or “faster to draw”.
|
|
86
|
+
|
|
87
|
+
**Allowed without catalog (not icons):** pure geometry with no symbol meaning — hairlines, solid rails, anonymous disc washes. If it **reads as a UI/icon glyph**, it is an icon → catalog path.
|
|
88
|
+
|
|
89
|
+
### 3. Confirm gate (required)
|
|
90
|
+
|
|
91
|
+
Do **not** mutate Draft / Authoring Source until the user:
|
|
92
|
+
|
|
93
|
+
- picks one candidate, or
|
|
94
|
+
- explicitly waives (“flat 就行 / 你定 / 不要背景”)
|
|
95
|
+
|
|
96
|
+
Unselected candidates produce **zero** EasySociable writes (no R2, no Directus Image, no decoration node, no gradient get baked into draft).
|
|
97
|
+
|
|
98
|
+
### 4. Materialize (Gateway / Authoring only)
|
|
99
|
+
|
|
100
|
+
| Kind | Materialize |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `flat` | Nothing extra |
|
|
103
|
+
| `gradient` | `gradients get` → write absolute background decoration with `style.backgroundImage = <css>`; record `recipeId`, provider, license in `surfacePreview` / node comment |
|
|
104
|
+
| `image` | Import via Template Gateway draft images (when available) or document the import step for TMP-024; Authoring references **CDN / imageId only** — never third-party temp URLs. Mode: surface background → `fixed`; slot → ask `fixed` \| `slot_default` |
|
|
105
|
+
| icon | Inline sanitized SVG as decoration sibling; record `iconAssetId`, provider, collection, license, contentHash |
|
|
106
|
+
|
|
107
|
+
Prefer band or panel geometry over full-bleed when copy is dense. Keep Theme.canvas as a safe solid under translucent washes when needed (`textSafeZone` / `needs_scrim`).
|
|
108
|
+
|
|
109
|
+
### 5. Record in `design-plan.json`
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
"surfacePreview": {
|
|
113
|
+
"kind": "gradient",
|
|
114
|
+
"userConfirmed": true,
|
|
115
|
+
"recipeId": "grad_001_warm-flame",
|
|
116
|
+
"name": "Warm Flame",
|
|
117
|
+
"provider": "webgradients",
|
|
118
|
+
"textSafeZone": "light_end",
|
|
119
|
+
"contrastAnchor": "#FAD0C4",
|
|
120
|
+
"placement": "full_bleed",
|
|
121
|
+
"notes": "Dark type on light end"
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
For image:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
"surfacePreview": {
|
|
129
|
+
"kind": "image",
|
|
130
|
+
"userConfirmed": true,
|
|
131
|
+
"imageMode": "fixed",
|
|
132
|
+
"imageId": "img_…",
|
|
133
|
+
"provider": "unsplash",
|
|
134
|
+
"query": "soft paper texture",
|
|
135
|
+
"rightsState": "licensed_for_publish",
|
|
136
|
+
"placement": "full_bleed"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For flat: `{ "kind": "flat", "userConfirmed": true }`.
|
|
141
|
+
|
|
142
|
+
Also mirror assets in `assetPlan` with sources `gradient_catalog` | `external_photo` | `template_icon_catalog` when used.
|
|
143
|
+
|
|
144
|
+
### 6. Validate
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
node scripts/validate-design-v2.mjs design-plan.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If `surfacePreview.kind` is `gradient` or `image`, `userConfirmed` must be `true` and required ids must be present before authoring.
|
|
151
|
+
|
|
152
|
+
## Fixture paths (Skill smoke)
|
|
153
|
+
|
|
154
|
+
| Path | Expectation |
|
|
155
|
+
|---|---|
|
|
156
|
+
| flat | No host MCP; no gradients get into draft |
|
|
157
|
+
| gradient | Template `gradients.*` only; confirmation → CSS decoration |
|
|
158
|
+
| image | Host image MCP → confirm → CDN/`imageId`; no temp URL in source |
|
|
159
|
+
| icon | `search_icons` → confirm → `get_icon` → inline canonical SVG / `iconAssetId` |
|
|
160
|
+
| none / waive | Explicit waive; remain flat |
|
|
161
|
+
|
|
162
|
+
## Do not
|
|
163
|
+
|
|
164
|
+
- Proxy Unsplash / Pexels / Pinterest **search** through Template MCP/CLI
|
|
165
|
+
- Require Better Icons MCP, client Iconify credentials, or runtime Provider fetches for icons
|
|
166
|
+
- **Hand-draw icon paths when Icon Catalog search works** (arrows, chevrons, checks, …)
|
|
167
|
+
- Put third-party temporary URLs or local paths into Authoring Source / Publish
|
|
168
|
+
- Call `theme.create` with gradient CSS (Theme stays solid semantics)
|
|
169
|
+
- Stack a second rainbow signature when a full-bleed gradient is already the signature
|
|
170
|
+
- Treat unselected search hits as EasySociable assets
|
|
171
|
+
- Require `easysociable-media` Skill/CLI/MCP
|
|
172
|
+
|
|
173
|
+
## Agent self-check before Save handoff (icons)
|
|
174
|
+
|
|
175
|
+
- [ ] Every symbol-like decoration has `iconAssetId` / came from `get_icon`
|
|
176
|
+
- [ ] No hand-authored icon `<path>` when catalog was available
|
|
177
|
+
- [ ] User confirmed pick (or explicit “你定 / 第 N 个”) before `get_icon`
|
|
178
|
+
- [ ] Icon color uses `currentColor` / `--es-*` (dark/light safe)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Theme from brand color
|
|
2
|
+
|
|
3
|
+
Generate deterministic, WCAG-checked theme tokens from a brand hex or curated preset before `theme.create`.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- User provides a brand color (hex) or brand kit with primary color
|
|
8
|
+
- User confirmed a preset from `PALETTE_REVIEW.md` / `references/THEME_PRESETS.md`
|
|
9
|
+
- Selected concept has a concrete color direction (not only free-text `colorStrategy`)
|
|
10
|
+
- No existing `themeId` to reuse
|
|
11
|
+
|
|
12
|
+
Skip when the user already selected a published theme or only wants to tweak an existing theme.
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
| Input | Required | Notes |
|
|
17
|
+
|-------|----------|-------|
|
|
18
|
+
| `brandHex` **or** `--preset <id>` | Yes | Preset supplies hex + fonts + suggested mode |
|
|
19
|
+
| `activeMode` | Yes | `light` or `dark` — match concept / preset bias |
|
|
20
|
+
| `heading` / `body` font | No | Default from preset or `Inter` |
|
|
21
|
+
| Theme `name` | Yes for create | Human name (preset `name` or custom), not `Theme draft_xxx` |
|
|
22
|
+
| User confirmation | Yes | From `PALETTE_REVIEW` unless user waived |
|
|
23
|
+
|
|
24
|
+
## Steps
|
|
25
|
+
|
|
26
|
+
1. Resolve inputs:
|
|
27
|
+
- Brand hex from brief / brand kit / user message, **or**
|
|
28
|
+
- `--preset` id from `references/theme-presets.json` after user confirmation
|
|
29
|
+
2. Pick `activeMode` from selected concept / preset:
|
|
30
|
+
- Light canvas / editorial paper → `light`
|
|
31
|
+
- Dark canvas / terminal / neon → `dark`
|
|
32
|
+
3. Run:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node scripts/generate-theme-from-hex.mjs <#hex> \
|
|
36
|
+
--mode <light|dark> \
|
|
37
|
+
--heading "<Font>" \
|
|
38
|
+
--body "<Font>" \
|
|
39
|
+
--output theme-tokens.json
|
|
40
|
+
|
|
41
|
+
# or
|
|
42
|
+
node scripts/generate-theme-from-hex.mjs --preset ocean-depths \
|
|
43
|
+
--output theme-tokens.json
|
|
44
|
+
|
|
45
|
+
node scripts/generate-theme-from-hex.mjs --list-presets
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
4. Validate:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
node scripts/validate-design-v2.mjs theme-tokens.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
5. If `contrastPass` is `false`, adjust before authoring:
|
|
55
|
+
- Try the other mode (`light` ↔ `dark`)
|
|
56
|
+
- Shift brand hex slightly (darker/lighter) and regenerate
|
|
57
|
+
- Try another preset
|
|
58
|
+
- Document the trade-off in `design-plan.json` `selectionReason`
|
|
59
|
+
6. **Confirmation gate:** do not call Gateway `theme.create` until `themePreview.userConfirmed` is true (or the user explicitly waived palette choice).
|
|
60
|
+
7. Use `themeTokens` from `theme-tokens.json` for Gateway `theme.create` — includes embedded `palette` for `theme_schema_v2`. Pass a readable `name` (preset name or custom label).
|
|
61
|
+
8. Keep `theme-tokens.json` alongside `design-plan.json` for Visual QA contrast reference.
|
|
62
|
+
|
|
63
|
+
## Output artifact
|
|
64
|
+
|
|
65
|
+
`theme-tokens.json` — schema `theme_tokens_v2`. See `references/DESIGN_V2_1.md`. May include `preset: { id, name, bestFor, notFor }` when generated from `--preset`.
|
|
66
|
+
|
|
67
|
+
## Do not
|
|
68
|
+
|
|
69
|
+
- Hand-pick four colors without running the generator when a brand hex or preset exists
|
|
70
|
+
- Put scale shades (`500`, `700`) directly on page nodes as hard-coded hex — prefer `--es-color-*` / `--es-scale-*`
|
|
71
|
+
- Skip contrast validation when `colorContrast` is scored in Visual QA
|
|
72
|
+
- Create `authoringSource` or `theme.create` before `theme-tokens.json` validates and the user confirmed (when no `themeId`)
|
|
73
|
+
- Create themes named only after draft ids
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Screenshot-based Visual QA (V2.1)
|
|
2
|
+
|
|
3
|
+
Run after draft creation and before the user handoff. Source inspection alone is not visual QA.
|
|
4
|
+
|
|
5
|
+
## Render evidence
|
|
6
|
+
|
|
7
|
+
1. Prefer opening `authoringStudioUrl` with available browser control and capture the rendered canvas.
|
|
8
|
+
2. If browser control is unavailable, record QA as pending; the unified CLI has
|
|
9
|
+
no separate `easysociable-template preview` command. A final render is not a
|
|
10
|
+
substitute for inspecting Authoring Studio.
|
|
11
|
+
3. Record an inspectable screenshot path or URL in `visual-qa.json`.
|
|
12
|
+
4. Never mark QA as passed when the page did not render or the screenshot could not be inspected.
|
|
13
|
+
|
|
14
|
+
## Review order
|
|
15
|
+
|
|
16
|
+
0. If `theme-tokens.json` exists, compare screenshot contrast to its `contrast` report for the active mode. Failed pairs are hard failures or cap `colorContrast` at 5. When `surfacePreview.kind` is `gradient` or `image`, also check text against `contrastAnchor` / scrim — do not assume Theme.canvas alone matches the wash.
|
|
17
|
+
|
|
18
|
+
1. **Craft Pass (philosophy discipline)** — before numeric scoring:
|
|
19
|
+
- Read `design-plan.json` → `philosophy.craftBar` and the selected concept’s `philosophyExpression`
|
|
20
|
+
- If the screenshot contradicts the philosophy (e.g. generic SaaS three-card grid vs “monumental single metric”), treat that as a composition/hierarchy issue and plan a revise toward the stated expression
|
|
21
|
+
- For `iteration >= 1`, default revisions **tighten existing nodes** (size, position, whitespace, type scale, contrast). Do **not** add large new decoration layers or new illustrations to chase points
|
|
22
|
+
- If a full-bleed gradient or photo surface is already the signature, do not add a second competing atmosphere layer
|
|
23
|
+
- Prefer high-impact changes: focal size/position, whitespace, alignment, type scale, contrast, then decoration
|
|
24
|
+
|
|
25
|
+
2. Check hard failures:
|
|
26
|
+
|
|
27
|
+
- render/runtime error
|
|
28
|
+
- clipped or overflowing text
|
|
29
|
+
- overlapping content
|
|
30
|
+
- off-canvas elements or unsafe margins
|
|
31
|
+
- unreadable contrast
|
|
32
|
+
- missing required slot content/image
|
|
33
|
+
- background or decoration obscuring the focal message
|
|
34
|
+
- third-party temp URLs or broken CDN for image surface/slots
|
|
35
|
+
3. Score the fixed rubric in `references/DESIGN_V2_1.md`:
|
|
36
|
+
|
|
37
|
+
- hierarchy 20
|
|
38
|
+
- composition 15
|
|
39
|
+
- spacing/alignment 15
|
|
40
|
+
- typography 15
|
|
41
|
+
- color/contrast 10
|
|
42
|
+
- asset relevance 10
|
|
43
|
+
- content resilience 10
|
|
44
|
+
- editability 5
|
|
45
|
+
|
|
46
|
+
## Revision loop
|
|
47
|
+
|
|
48
|
+
- Pass only with no hard failures and total score `>= 80`.
|
|
49
|
+
- For a failure, list concrete issues by region/node and revise `authoringSource`.
|
|
50
|
+
- In `changesMade`, describe refine-first edits; avoid “added new decorative panel/illustration” unless the user explicitly asked or an assetPlan required asset was missing.
|
|
51
|
+
- Validate the updated source, update the same `draftId`, and capture a new screenshot.
|
|
52
|
+
- Perform at most **two automatic revisions** (`iteration` 0, 1, 2). Ask before doing more.
|
|
53
|
+
- Do not hide a layout problem by rasterising the whole design.
|
|
54
|
+
|
|
55
|
+
Validate the final `visual-qa.json` with `scripts/validate-design-v2.mjs`. If visual tools are unavailable, disclose the missing QA instead of fabricating a passing artifact.
|