dreative 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -27
- package/dist/cli/audit.js +206 -0
- package/dist/cli/audit.test.js +79 -0
- package/dist/cli/docsCheck.js +163 -0
- package/dist/cli/docsCheck.test.js +8 -0
- package/dist/cli/index.js +45 -9
- package/dist/server/preview.js +73 -73
- package/dist/server/store.js +11 -0
- package/dist/shared/artifacts.js +162 -0
- package/dist/shared/design.js +42 -22
- package/dist/shared/ruleSystem.js +130 -0
- package/dist/shared/ruleSystem.test.js +187 -0
- package/dist/shared/skillSystem.js +173 -0
- package/dist/shared/skillSystem.test.js +110 -0
- package/dist/ui/assets/{index--vztc_MR.js → index-CKwmbx2j.js} +13 -13
- package/dist/ui/index.html +12 -12
- package/package.json +5 -3
- package/skill/dreative/DESIGN.md +121 -93
- package/skill/dreative/PLAN.md +229 -92
- package/skill/dreative/SKILL.md +218 -137
- package/skill/dreative/frameworks/nextjs.md +13 -0
- package/skill/dreative/frameworks/react-vite.md +12 -0
- package/skill/dreative/frameworks/styling.md +14 -0
- package/skill/dreative/frameworks/sveltekit.md +10 -0
- package/skill/dreative/frameworks/vue-nuxt.md +12 -0
- package/skill/dreative/recipes/3d-recipes.md +44 -0
- package/skill/dreative/recipes/cinematic-recipes.md +19 -0
- package/skill/dreative/recipes/immersive-recipes.md +18 -0
- package/skill/dreative/recipes/media-recipes.md +60 -0
- package/skill/dreative/recipes/motion-recipes.md +44 -0
- package/skill/dreative/references/ARTIFACTS.md +180 -0
- package/skill/dreative/references/REFLEX_FONTS.json +44 -0
- package/skill/dreative/references/RULES.json +186 -0
- package/skill/dreative/references/SKILL_CONTRACT.md +30 -0
- package/skill/dreative/references/TIERS.md +42 -0
- package/skill/dreative/schemas/plan.schema.json +241 -0
- package/skill/dreative/schemas/verify.schema.json +61 -0
- package/skill/dreative/skills/3d.md +94 -267
- package/skill/dreative/skills/cinematic.md +56 -232
- package/skill/dreative/skills/experimental.md +108 -95
- package/skill/dreative/skills/immersive.md +61 -223
- package/skill/dreative/skills/interaction.md +9 -1
- package/skill/dreative/skills/media.md +135 -564
- package/skill/dreative/skills/mobile.md +128 -117
- package/skill/dreative/skills/motion.md +89 -256
- package/skill/dreative/skills/refined.md +116 -102
- package/skill/dreative/skills/ux.md +155 -144
- package/dist/server/ai.js +0 -177
|
@@ -1,144 +1,155 @@
|
|
|
1
|
-
# Dreative Specialist Skill — Functional UX (everything works)
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
order —
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
1
|
+
# Dreative Specialist Skill — Functional UX (everything works)
|
|
2
|
+
|
|
3
|
+
## Contract
|
|
4
|
+
|
|
5
|
+
Universal foundation: ux and baseline mobile apply to every web page.
|
|
6
|
+
|
|
7
|
+
Follow `../references/SKILL_CONTRACT.md`. This universal foundation has no
|
|
8
|
+
specialist dependency; pair it with `mobile` for all web delivery. Deliver the
|
|
9
|
+
preservation manifest, state inventory, semantic/keyboard behavior, feedback,
|
|
10
|
+
and functional audit evidence. It may never be deselected to fund visual work.
|
|
11
|
+
Done means routes, controls, forms, states, focus, hit areas, and failure paths
|
|
12
|
+
work without visual effects.
|
|
13
|
+
|
|
14
|
+
Load this file when `plan.skills` includes `ux`, for ANY product-register page,
|
|
15
|
+
and whenever a redesign touches navigation, forms, or stateful views. It EXTENDS
|
|
16
|
+
DESIGN.md §9 (the product floor) into a full working-page contract. Its premise:
|
|
17
|
+
a beautiful page where the menu doesn't open, a link 404s, or an effect eats
|
|
18
|
+
clicks is a FAILED page — visual craft cannot compensate for broken function.
|
|
19
|
+
This skill is the reason "immersive but broken" never ships: it defines what
|
|
20
|
+
"works" means, mechanically, and the runtime verification pass (SKILL.md) tests
|
|
21
|
+
against it.
|
|
22
|
+
|
|
23
|
+
## 0. The working-page contract
|
|
24
|
+
|
|
25
|
+
Every page you ship satisfies, verifiably:
|
|
26
|
+
|
|
27
|
+
1. Every visible control does something real (or is explicitly disabled with a
|
|
28
|
+
reason). No dead buttons, no `href="#"`, no `onClick={() => {}}`.
|
|
29
|
+
2. Every navigation target resolves — internal routes exist, anchors match real
|
|
30
|
+
ids, external links open safely (`rel="noopener"`, `target="_blank"` only
|
|
31
|
+
for true externals).
|
|
32
|
+
3. Every stateful view renders all its states (loading/empty/error/success),
|
|
33
|
+
not just the happy path.
|
|
34
|
+
4. Keyboard alone can operate everything a pointer can.
|
|
35
|
+
5. Nothing decorative intercepts input, blocks scroll, or steals focus.
|
|
36
|
+
|
|
37
|
+
## 1. Navigation
|
|
38
|
+
|
|
39
|
+
- **Links resolve.** Before shipping, list every `href`/`to`/`navigate` target
|
|
40
|
+
and check each exists (route table, file, or real URL). A designed 404 is
|
|
41
|
+
still a 404.
|
|
42
|
+
- **Active state**: the nav marks the current page/section (aria-current +
|
|
43
|
+
visual). Section-scroll pages update it via IntersectionObserver.
|
|
44
|
+
- **Mobile menu is a component, not a hope**: opens AND closes (button, Esc,
|
|
45
|
+
backdrop click, and on route change); scroll-locks the body while open
|
|
46
|
+
(`overflow:hidden` on html, restore on close — with scrollbar-gutter
|
|
47
|
+
compensation so the page doesn't shift); traps focus while open and returns
|
|
48
|
+
focus to the trigger on close; the toggle reflects state
|
|
49
|
+
(`aria-expanded`, icon morph). Test the open→navigate→back sequence — stale
|
|
50
|
+
open menus after route changes are the #1 shipped-menu bug.
|
|
51
|
+
- **Anchors under fixed headers**: every in-page anchor target gets
|
|
52
|
+
`scroll-margin-top` ≥ header height; smooth-scroll respects reduced-motion.
|
|
53
|
+
- **Logo → home. Back button works** — spatial/SPA transitions must not break
|
|
54
|
+
history (immersive.md §2); modals and drawers close on back where users
|
|
55
|
+
expect it (mobile especially).
|
|
56
|
+
- **Custom scroll (Lenis)** must not break anchors, keyboard scrolling
|
|
57
|
+
(space/PgDn/arrows), or focus-into-view; wire `lenis.scrollTo` for anchor
|
|
58
|
+
clicks and leave native behavior for the rest.
|
|
59
|
+
|
|
60
|
+
## 2. Forms
|
|
61
|
+
|
|
62
|
+
- Every form submits somewhere real, or is explicitly wired to a stub with a
|
|
63
|
+
visible success simulation — never a button that swallows the click.
|
|
64
|
+
- Labels above inputs (placeholder-as-label banned, DESIGN.md §9);
|
|
65
|
+
autocomplete attributes on identity fields; correct `type`/`inputmode`
|
|
66
|
+
(email, tel, numeric) so mobile keyboards match.
|
|
67
|
+
- Validate on submit first (not on first keystroke); after first submit,
|
|
68
|
+
re-validate per field on blur/change. Errors inline, next to the field,
|
|
69
|
+
specific ("Enter a valid email"), with `aria-describedby` wiring and focus
|
|
70
|
+
moved to the first invalid field.
|
|
71
|
+
- Submit feedback: button enters loading state (spinner inside, fixed width,
|
|
72
|
+
interaction.md §5), double-submit prevented, success confirmed visibly
|
|
73
|
+
(inline message or state change — not just a toast that may be missed),
|
|
74
|
+
failure recoverable (inputs keep their values; never wipe a form on error).
|
|
75
|
+
- Enter submits single-field forms (newsletter). Required fields marked; the
|
|
76
|
+
disabled-until-valid pattern only when errors show on hover/focus of the
|
|
77
|
+
disabled button, otherwise keep the button enabled and validate on click.
|
|
78
|
+
|
|
79
|
+
## 3. State coverage (every data view)
|
|
80
|
+
|
|
81
|
+
For each list/table/feed/detail view, all four states are designed and
|
|
82
|
+
reachable: **loading** (skeleton shaped like the content, DESIGN.md §9),
|
|
83
|
+
**empty** (teaches the interface: what this will show + the action that fills
|
|
84
|
+
it — never a blank area or a lonely "No data"), **error** (what happened + a
|
|
85
|
+
retry affordance), **populated** (including the long-content case: 100 items,
|
|
86
|
+
40-character names, overflow handled per DESIGN.md §15). Async actions get
|
|
87
|
+
optimistic UI only when low-stakes (DESIGN.md §6); destructive actions get
|
|
88
|
+
confirmation and, ideally, undo instead of a scary modal.
|
|
89
|
+
|
|
90
|
+
## 4. Keyboard, focus, and the hit-area audit
|
|
91
|
+
|
|
92
|
+
- Full tab walk: every interactive element reachable in visual order, operable
|
|
93
|
+
(Enter/Space), with a visible `:focus-visible` ring (interaction.md §0), and
|
|
94
|
+
escapable (no traps outside intentional modal traps).
|
|
95
|
+
- Whatever hover reveals, focus reveals (cards' secondary actions, hover-woken
|
|
96
|
+
media, dropdown menus). Custom gestures (drag, click-and-hold) always have a
|
|
97
|
+
plain keyboard/click equivalent (cinematic.md §3).
|
|
98
|
+
- **The pointer-events audit** (the #1 cause of "cool but broken"): walk every
|
|
99
|
+
overlay in the stacking order — canvases, gradient/grain layers, custom
|
|
100
|
+
cursor layers, transition curtains, closed menus, preloaders — and verify
|
|
101
|
+
each is `pointer-events: none` (or removed from the DOM) whenever it is not
|
|
102
|
+
actively being interacted with. A finished preloader or a closed fullscreen
|
|
103
|
+
menu sitting at `opacity:0` with pointer-events on is an invisible wall over
|
|
104
|
+
the whole page. Then hit-test the controls: click every button/link at its
|
|
105
|
+
visual position — if something above it swallows the click, that's a §15
|
|
106
|
+
spatial-integrity fail, fix the layer not the button.
|
|
107
|
+
- Modals/drawers: focus trapped inside, Esc closes, focus returns to trigger,
|
|
108
|
+
`aria-modal` + labelled; scrim click closes (unless data-loss risk).
|
|
109
|
+
- Semantic HTML first: real `<button>`/`<a>`/`<nav>`/`<main>`/headings in
|
|
110
|
+
order — divs-with-onClick fail half this section automatically.
|
|
111
|
+
|
|
112
|
+
## 5. Scroll and layout stability
|
|
113
|
+
|
|
114
|
+
- Zero layout shift from async content: media boxes sized up front (media.md
|
|
115
|
+
§5), fonts `swap` with metric-compatible fallbacks, skeletons the same size
|
|
116
|
+
as what replaces them, no banners that push content after load.
|
|
117
|
+
- Scroll restoration: back/forward returns to the previous position (default
|
|
118
|
+
browser behavior — don't break it with manual scroll-to-top on every route;
|
|
119
|
+
scroll to top only on forward navigation to a NEW page).
|
|
120
|
+
- Fixed bars: content padded so nothing hides beneath them (DESIGN.md §15);
|
|
121
|
+
100dvh not 100vh; no horizontal body scroll at 320px.
|
|
122
|
+
- Long pages get orientation aids: sticky nav or progress indication, and a
|
|
123
|
+
footer that actually ends the page (no infinite-feeling voids).
|
|
124
|
+
|
|
125
|
+
## 6. Feedback and perceived performance
|
|
126
|
+
|
|
127
|
+
- Every async action acknowledges input within 100ms (pressed state, spinner,
|
|
128
|
+
optimistic change) — silence after a click reads as broken even when it
|
|
129
|
+
works.
|
|
130
|
+
- Toasts only for transient global events; they stack in ONE corner slot
|
|
131
|
+
(DESIGN.md §15), auto-dismiss ≥ 4s, pause on hover, and are `aria-live`.
|
|
132
|
+
- Destructive/irreversible actions: confirm with specifics ("Delete 3 items?"),
|
|
133
|
+
never bare "Are you sure?"; prefer undo-toast over confirm-modal when safe.
|
|
134
|
+
- Copy per DESIGN.md §8's UX-writing rules: buttons say what they do, errors
|
|
135
|
+
say what to do next.
|
|
136
|
+
|
|
137
|
+
## 7. The functional audit (run at verification time)
|
|
138
|
+
|
|
139
|
+
This is the checklist the runtime verification pass (SKILL.md) executes with
|
|
140
|
+
browser tools — or walks mentally, file by file, when no browser exists:
|
|
141
|
+
|
|
142
|
+
1. Click every nav link + the logo; confirm each lands where labeled.
|
|
143
|
+
2. Open and close the mobile menu (both directions, plus Esc, plus navigate-
|
|
144
|
+
while-open) at 390px width.
|
|
145
|
+
3. Submit each form empty → see inline errors; submit valid → see success
|
|
146
|
+
state; confirm no double-submit.
|
|
147
|
+
4. Tab through the page start to finish; note any unreachable/invisible-focus/
|
|
148
|
+
trapped stop.
|
|
149
|
+
5. Hit-test 5+ controls in effect-heavy regions (hero, canvas overlays,
|
|
150
|
+
floating elements) — every click must land.
|
|
151
|
+
6. Trigger each data view's empty/error state if reachable (or verify the
|
|
152
|
+
branch exists in code).
|
|
153
|
+
7. Console: zero uncaught errors during all of the above.
|
|
154
|
+
|
|
155
|
+
Report the result as a pass/fail list, fix fails, re-run the failed items once.
|
package/dist/server/ai.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
const BLOCK_SCHEMA = `
|
|
3
|
-
A block is a JSON object:
|
|
4
|
-
{
|
|
5
|
-
"id": "string (short unique id)",
|
|
6
|
-
"type": "section|row|column|nav|hero|card-grid|list|form|footer|text|image|button",
|
|
7
|
-
"label": "short human label, e.g. 'Hero', 'Pricing cards'",
|
|
8
|
-
"direction": "row" | "column" (optional, layout of children),
|
|
9
|
-
"sizeHint": "sm" | "md" | "lg" (optional, relative vertical size),
|
|
10
|
-
"intents": ["optional behavior notes, e.g. 'CTA scrolls to pricing'"],
|
|
11
|
-
"children": [ ...nested blocks ] (optional)
|
|
12
|
-
}
|
|
13
|
-
Keep trees shallow (max depth 3) and wireframe-level: structure, not styling.`;
|
|
14
|
-
/** Run an Agent SDK query and return the final result text, reporting progress. */
|
|
15
|
-
async function run(prompt, opts = {}) {
|
|
16
|
-
let result = "";
|
|
17
|
-
const q = query({
|
|
18
|
-
prompt,
|
|
19
|
-
options: {
|
|
20
|
-
allowedTools: opts.allowRead ? ["Read"] : [],
|
|
21
|
-
permissionMode: "bypassPermissions",
|
|
22
|
-
maxTurns: opts.allowRead ? 6 : 2,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
for await (const message of q) {
|
|
26
|
-
if (message.type === "assistant") {
|
|
27
|
-
const blocks = message.message?.content ?? [];
|
|
28
|
-
for (const b of blocks) {
|
|
29
|
-
if (b.type === "tool_use")
|
|
30
|
-
opts.progress?.("Looking at the reference image...");
|
|
31
|
-
else if (b.type === "text")
|
|
32
|
-
opts.progress?.("Writing...");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
else if (message.type === "result") {
|
|
36
|
-
if (message.subtype === "success")
|
|
37
|
-
result = message.result;
|
|
38
|
-
else
|
|
39
|
-
throw new Error(`AI call failed: ${message.subtype}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (!result)
|
|
43
|
-
throw new Error("AI call returned no result");
|
|
44
|
-
return result;
|
|
45
|
-
}
|
|
46
|
-
/** Run + parse, with one retry that feeds the failure back to the model. */
|
|
47
|
-
async function runParsed(prompt, parse, opts = {}) {
|
|
48
|
-
const text = await run(prompt, opts);
|
|
49
|
-
try {
|
|
50
|
-
return parse(text);
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
opts.progress?.("Output was malformed - retrying...");
|
|
54
|
-
const retryText = await run(`${prompt}\n\nIMPORTANT: Your previous response could not be parsed (${String(err)}). Respond again, strictly following the output format instructions.`, opts);
|
|
55
|
-
return parse(retryText);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/** Extract the first JSON value (object or array) from model output. */
|
|
59
|
-
function extractJson(text) {
|
|
60
|
-
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
61
|
-
const candidate = fenced ? fenced[1] : text;
|
|
62
|
-
const start = candidate.search(/[[{]/);
|
|
63
|
-
if (start === -1)
|
|
64
|
-
throw new Error("No JSON found in AI response");
|
|
65
|
-
for (let end = candidate.length; end > start; end--) {
|
|
66
|
-
const ch = candidate[end - 1];
|
|
67
|
-
if (ch !== "}" && ch !== "]")
|
|
68
|
-
continue;
|
|
69
|
-
try {
|
|
70
|
-
return JSON.parse(candidate.slice(start, end));
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
/* keep scanning */
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
throw new Error("Could not parse JSON from AI response");
|
|
77
|
-
}
|
|
78
|
-
function extractCode(text) {
|
|
79
|
-
const fence = text.match(/```(?:tsx|jsx|typescript|ts)?\s*([\s\S]*?)```/);
|
|
80
|
-
const code = fence ? fence[1].trim() : text.trim();
|
|
81
|
-
if (!code.includes("export default"))
|
|
82
|
-
throw new Error("Generated code has no default export");
|
|
83
|
-
return code;
|
|
84
|
-
}
|
|
85
|
-
export async function proposeSkeletons(userPrompt, progress) {
|
|
86
|
-
progress?.("Proposing page layouts...");
|
|
87
|
-
return runParsed(`You are a UX/information-architecture expert. Propose 3 distinct page layout skeletons (wireframe-level) for this request:
|
|
88
|
-
|
|
89
|
-
"${userPrompt}"
|
|
90
|
-
|
|
91
|
-
${BLOCK_SCHEMA}
|
|
92
|
-
|
|
93
|
-
Respond with ONLY a JSON array of 3 items, each: {"name": "page variant name", "layout": <block tree with root type "section">}. No prose.`, (t) => extractJson(t), { progress });
|
|
94
|
-
}
|
|
95
|
-
export async function proposeVariants(pageName, layout, progress) {
|
|
96
|
-
progress?.(`Proposing variants of "${pageName}"...`);
|
|
97
|
-
return runParsed(`You are a UX expert. Here is the current wireframe skeleton for the page "${pageName}":
|
|
98
|
-
|
|
99
|
-
${JSON.stringify(layout, null, 2)}
|
|
100
|
-
|
|
101
|
-
Propose 2 meaningfully different alternative layouts for the SAME content and purpose (e.g. different section order, grid vs list, split vs stacked). Preserve all "intents" values, attached to the equivalent blocks. Use fresh ids.
|
|
102
|
-
|
|
103
|
-
${BLOCK_SCHEMA}
|
|
104
|
-
|
|
105
|
-
Respond with ONLY a JSON array of 2 items: {"name": "<pageName> - <variant descriptor>", "layout": <block tree>}. No prose.`, (t) => extractJson(t), { progress });
|
|
106
|
-
}
|
|
107
|
-
export async function editBlock(block, instruction, progress) {
|
|
108
|
-
progress?.("Editing block...");
|
|
109
|
-
return runParsed(`You are editing one block of a page wireframe. Current block subtree:
|
|
110
|
-
|
|
111
|
-
${JSON.stringify(block, null, 2)}
|
|
112
|
-
|
|
113
|
-
User instruction: "${instruction}"
|
|
114
|
-
|
|
115
|
-
${BLOCK_SCHEMA}
|
|
116
|
-
|
|
117
|
-
Apply the instruction. Structural changes go into the tree; behavior/functionality changes go into "intents" arrays on the relevant blocks. If the instruction replaces an existing behavior, replace the corresponding intent instead of appending. Keep existing ids where blocks are unchanged; give new blocks new ids.
|
|
118
|
-
Respond with ONLY the updated block subtree as JSON. No prose.`, (t) => extractJson(t), { progress });
|
|
119
|
-
}
|
|
120
|
-
export async function designPage(args) {
|
|
121
|
-
const { progress } = args;
|
|
122
|
-
progress?.("Designing page...");
|
|
123
|
-
const refPart = args.refImagePath
|
|
124
|
-
? `First, use the Read tool to view the reference image at: ${args.refImagePath}\nMatch its visual style (colors, typography feel, spacing, mood) closely.`
|
|
125
|
-
: "No page-level reference image provided; choose a distinctive, non-generic visual style appropriate to the content.";
|
|
126
|
-
const blockRefPart = args.blockRefs?.length
|
|
127
|
-
? `These specific blocks have their own style reference images. Use the Read tool to view each, and match that image's style for that block specifically (it overrides the page-level style for that block):\n${args.blockRefs
|
|
128
|
-
.map((r) => `- block "${r.id}" (${r.label}): ${r.path}`)
|
|
129
|
-
.join("\n")}`
|
|
130
|
-
: "";
|
|
131
|
-
const previousPart = args.previousCode
|
|
132
|
-
? `A previous version of this page exists below. The user may have made deliberate element-level edits to it. Where a block from the skeleton already exists in the previous version, PRESERVE its styling and content choices; only restructure/add/remove what the updated skeleton requires.
|
|
133
|
-
|
|
134
|
-
Previous version:
|
|
135
|
-
\`\`\`tsx
|
|
136
|
-
${args.previousCode}
|
|
137
|
-
\`\`\`
|
|
138
|
-
`
|
|
139
|
-
: "";
|
|
140
|
-
const siblingPart = args.siblingPages?.length
|
|
141
|
-
? `Other pages in this project (use these names for nav/footer links, href="#"): ${args.siblingPages.join(", ")}.`
|
|
142
|
-
: "";
|
|
143
|
-
return runParsed(`${refPart}
|
|
144
|
-
${blockRefPart}
|
|
145
|
-
|
|
146
|
-
Then generate a complete React component for the page "${args.pageName}" implementing this wireframe skeleton exactly (same structure and order of blocks):
|
|
147
|
-
|
|
148
|
-
${JSON.stringify(args.layout, null, 2)}
|
|
149
|
-
|
|
150
|
-
${previousPart}
|
|
151
|
-
Every "intents" entry describes required behavior - implement it with React state/handlers (mock data is fine, no network calls).
|
|
152
|
-
${args.designPrompt ? `Additional design direction: "${args.designPrompt}"` : ""}
|
|
153
|
-
${siblingPart}
|
|
154
|
-
|
|
155
|
-
Requirements:
|
|
156
|
-
- Single self-contained .tsx file, default-exporting the page component.
|
|
157
|
-
- Import only from "react". Style with Tailwind CSS utility classes (Tailwind is available globally).
|
|
158
|
-
- Put data-dreative-id="<block id>" on the top-level element rendered for each block from the skeleton.
|
|
159
|
-
- Realistic placeholder copy, no lorem ipsum. For images use https://picsum.photos placeholders or CSS.
|
|
160
|
-
|
|
161
|
-
Respond with ONLY the .tsx source in a single \`\`\`tsx code fence. No prose.`, extractCode, { allowRead: !!args.refImagePath || !!args.blockRefs?.length, progress });
|
|
162
|
-
}
|
|
163
|
-
export async function editDesignedElement(args) {
|
|
164
|
-
args.progress?.("Editing element...");
|
|
165
|
-
const refPart = args.refImagePath
|
|
166
|
-
? `First, use the Read tool to view the style reference image at: ${args.refImagePath}\nMatch its visual style when applying the change.\n\n`
|
|
167
|
-
: "";
|
|
168
|
-
return runParsed(`${refPart}Here is a React+Tailwind page component:
|
|
169
|
-
|
|
170
|
-
\`\`\`tsx
|
|
171
|
-
${args.code}
|
|
172
|
-
\`\`\`
|
|
173
|
-
|
|
174
|
-
Modify ONLY the element (and its contents) marked data-dreative-id="${args.elementId}" according to this instruction: "${args.instruction}". Keep everything else byte-identical where possible, keep all data-dreative-id attributes.
|
|
175
|
-
|
|
176
|
-
Respond with ONLY the full updated .tsx source in a single \`\`\`tsx code fence. No prose.`, extractCode, { allowRead: !!args.refImagePath, progress: args.progress });
|
|
177
|
-
}
|