dreative 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ # Dreative Specialist Skill — Refined Clean Business
2
+
3
+ Load this file when `plan.skills` includes `refined`, or the brief/prompt asks
4
+ for a "clean modern business site", premium-but-calm marketing, DTC/e-commerce
5
+ polish, "professional, not flashy", or names references like ch.maswitzerland.com
6
+ or lovvelavva.com. This is the OPPOSITE pole from immersive/cinematic: quality
7
+ expressed through restraint — spacing, photography, and type doing all the work,
8
+ with motion barely above zero. Most real client work lands here; treat it as a
9
+ craft discipline, not the absence of one.
10
+
11
+ It EXTENDS DESIGN.md (everything applies; this file tightens the dials). It does
12
+ NOT stack with `immersive`/`cinematic` — those are different registers. It pairs
13
+ well with a light dose of `interaction` (press states, underline draws) and the
14
+ first tier of `motion` (one hero sequence, 2-3 in-view reveals).
15
+
16
+ ## 0. The register: expensive silence
17
+
18
+ What separates premium-clean from generic-clean is not any element — it's the
19
+ ratios:
20
+
21
+ - **Whitespace is the brand.** Section padding 96-160px desktop / 56-80px
22
+ mobile; content max-width 1200-1320px with WIDE outer gutters; one idea per
23
+ viewport. If a section feels empty, that's the look working — resist filling.
24
+ - **Photography carries the emotion.** Real product/lifestyle imagery, art-
25
+ directed to one consistent grade (one light temperature, one background
26
+ family). Full-bleed image sections alternate with contained text sections —
27
+ the rhythm image / text / image IS the page structure. Never decorate around
28
+ weak imagery; demand or generate better imagery instead.
29
+ - **Type does hierarchy, color stays out of the way.** Near-monochrome palette:
30
+ warm or cool neutral family + ONE accent used almost exclusively on the
31
+ primary CTA and links. Backgrounds shift between 2-3 tints of the neutral
32
+ (e.g. white / #f6f5f2 / #111) to separate sections without borders.
33
+ - **Motion whispers.** Motion dial effectively ≤ 4: fade-rise entrances
34
+ (300-400ms, once), a sticky nav that gains a hairline+blur, underline draws,
35
+ press states. No parallax beyond 4%, no pinning, no canvas. A single
36
+ restrained signature (a slow ken-burns on the hero image, or a marquee of
37
+ press logos) is the ceiling.
38
+
39
+ ## 1. Page anatomy (marketing/DTC form)
40
+
41
+ The proven skeleton — vary the composition per DESIGN.md §5, not the order
42
+ logic:
43
+
44
+ 1. **Hero**: one full-width image or split layout; headline ≤ 8 words stating
45
+ the value in plain language; one CTA. No feature bullets in the hero.
46
+ 2. **Credibility strip**: press/client logos, real marks, grayscale or
47
+ single-tint (lovvelavva runs Forbes/Women's Health/Real Simple here —
48
+ this section converts and belongs high on DTC pages).
49
+ 3. **Value sections** (2-4): alternating image/text, each making ONE claim
50
+ with 1-2 sentences of support. Icons only if custom-drawn; three-generic-
51
+ icon-cards is the tell this register must avoid most.
52
+ 4. **Product/collection grid**: large images, generous gaps (24-32px), minimal
53
+ card chrome — image, name, price/one-liner; hover = image swap or subtle
54
+ zoom-crop INSIDE a fixed frame (no card growth).
55
+ 5. **Social proof**: 1-3 real testimonials with names/photos, editorial layout
56
+ (big quote type), never a 3-card testimonial row.
57
+ 6. **Closing CTA**: calm full-width section, one sentence, one button.
58
+ 7. **Footer**: structured, generous, quiet — the footer's polish is a trust
59
+ signal in this register; give it real columns, legal, newsletter.
60
+
61
+ E-commerce specifics: sticky add-to-cart on product pages (mobile bottom bar),
62
+ price always visible, shipping/returns reassurance near the CTA, cart as a
63
+ slide-over drawer not a page.
64
+
65
+ ## 2. The discovery-grid variant (cosmos.so-like)
66
+
67
+ For content/discovery products (galleries, moodboards, catalogs): near-zero
68
+ chrome around a masonry/justified image grid; dark or paper-white surface;
69
+ images at native aspect ratios (never uniform crops); hover = slight lift +
70
+ metadata fade-in on top of the image; infinite scroll with a sentinel loader;
71
+ the search/filter bar is the only persistent UI. The product IS the grid —
72
+ navigation, branding, and controls stay almost invisible until needed.
73
+
74
+ ## 3. What "modern" means here (2024+, not 2016 flat)
75
+
76
+ - Hairline borders (1px, 8-12% alpha) instead of shadows for structure; the
77
+ 2-3 stacked tinted shadows (interaction.md §3) reserved for genuinely
78
+ floating elements (dropdowns, drawers).
79
+ - Larger type than feels safe: body 17-18px on marketing pages, display
80
+ clamped 2.5-4.5rem, tight leading. Small timid type is the #1 dated tell.
81
+ - Radius system: one value family — either near-square (2-4px, editorial/
82
+ luxury) or soft (12-16px, DTC/consumer) — never mixed.
83
+ - Buttons: solid accent primary + quiet text-link secondary. Pill shape only
84
+ in the consumer/DTC variant. No outlined-button armies.
85
+ - Real `<img>`/`<picture>` with proper aspect-ratio boxes; no CSS-drawn
86
+ product mockups; `object-fit: cover` with art-directed focal points.
87
+
88
+ ## 4. Guardrails
89
+
90
+ - If you're adding an effect to make a section interesting, the section's
91
+ content or imagery is the problem — fix that instead.
92
+ - No gradient meshes, no glassmorphism cards, no floating blob backgrounds,
93
+ no emoji in UI copy: all instantly cheapen this register.
94
+ - Accessibility floor is easy here — don't squander it: AA contrast on the
95
+ tinted neutrals (test the #767676-gray-on-white trap), visible focus,
96
+ semantic landmarks.
97
+ - Performance IS the aesthetic: LCP image preloaded, fonts ≤ 2 files,
98
+ zero animation libraries unless motion is actually used — a clean site
99
+ that loads instantly reads as more premium than any effect.
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
- }