launchframe 0.2.5 → 0.2.6
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/package.json +1 -1
- package/template/.amazonq/cli-agents/clone-website.json +1 -1
- package/template/.amazonq/rules/project.md +28 -18
- package/template/.augment/commands/clone-website.md +25 -25
- package/template/.claude/skills/clone-website/SKILL.md +25 -25
- package/template/.claude/skills/marketing-social-proof-motion/SKILL.md +47 -0
- package/template/.clinerules +33 -19
- package/template/.codex/skills/clone-website/SKILL.md +25 -25
- package/template/.continue/commands/clone-website.md +25 -25
- package/template/.continue/rules/project.md +28 -18
- package/template/.cursor/commands/clone-website.md +25 -25
- package/template/.cursor/commands/marketing-social-proof-motion.md +42 -0
- package/template/.cursor/rules/project.mdc +1 -4
- package/template/.gemini/commands/clone-website.toml +25 -25
- package/template/.github/copilot-instructions.md +28 -18
- package/template/.github/skills/clone-website/SKILL.md +25 -25
- package/template/.opencode/commands/clone-website.md +25 -25
- package/template/.windsurf/workflows/clone-website.md +25 -25
- package/template/AGENTS.md +24 -12
- package/template/docs/research/INSPECTION_GUIDE.md +11 -8
- package/template/package-lock.json +8795 -0
- package/template/scripts/recon-playwright.mjs +90 -17
- package/template/src/components/marketing/scribewise-landing.tsx +34 -0
- package/template/.claude/skills/marketing-landing-production/SKILL.md +0 -36
- package/template/.cursor/commands/marketing-landing-production.md +0 -31
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Reads URL from launchframe.config.json (or --url). Writes:
|
|
6
6
|
* - docs/design-references/playwright-<host>-<w>px.png (full page)
|
|
7
|
-
* - docs/research/computed-snapshot.json (styles + asset inventory + bot-wall hint)
|
|
7
|
+
* - docs/research/computed-snapshot.json (styles + merged asset inventory + bot-wall hint)
|
|
8
8
|
* - docs/research/MEDIA_MANIFEST.md (table of discovered media URLs)
|
|
9
9
|
*
|
|
10
10
|
* Usage:
|
|
@@ -52,27 +52,91 @@ function safeHost(url) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Scroll the full document depth slowly so lazy-loaded media and below-fold DOM resolve.
|
|
57
|
+
* Repeats until scrollHeight stabilizes (handles incremental infinite layouts up to max rounds).
|
|
58
|
+
*/
|
|
56
59
|
async function scrollFullPage(page) {
|
|
57
60
|
await page.evaluate(async () => {
|
|
58
61
|
const delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
const stepSize = () => Math.max(1, Math.floor(window.innerHeight * 0.85));
|
|
63
|
+
|
|
64
|
+
let unchangedStreak = 0;
|
|
65
|
+
let prevTotal = -1;
|
|
66
|
+
|
|
67
|
+
for (let round = 0; round < 12; round++) {
|
|
68
|
+
let y = 0;
|
|
69
|
+
let limit = document.documentElement.scrollHeight;
|
|
70
|
+
|
|
71
|
+
while (y < limit) {
|
|
72
|
+
y = Math.min(y + stepSize(), limit);
|
|
73
|
+
window.scrollTo(0, y);
|
|
74
|
+
await delay(130);
|
|
75
|
+
limit = document.documentElement.scrollHeight;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
window.scrollTo(0, document.documentElement.scrollHeight);
|
|
79
|
+
await delay(420);
|
|
80
|
+
|
|
81
|
+
const h = document.documentElement.scrollHeight;
|
|
82
|
+
|
|
83
|
+
window.scrollTo(0, 0);
|
|
84
|
+
await delay(220);
|
|
85
|
+
|
|
86
|
+
if (h === prevTotal) unchangedStreak++;
|
|
87
|
+
else unchangedStreak = 0;
|
|
88
|
+
prevTotal = h;
|
|
89
|
+
|
|
90
|
+
if (unchangedStreak >= 2) break;
|
|
66
91
|
}
|
|
67
|
-
window.scrollTo(0, 0);
|
|
68
|
-
await delay(300);
|
|
69
92
|
});
|
|
70
93
|
}
|
|
71
94
|
|
|
95
|
+
function mergeAssetInventory(base, extra) {
|
|
96
|
+
if (!extra) return base;
|
|
97
|
+
const imgKey = (i) => i.src || "";
|
|
98
|
+
const seenImg = new Set(base.images.map(imgKey));
|
|
99
|
+
const images = [...base.images];
|
|
100
|
+
for (const i of extra.images) {
|
|
101
|
+
const k = imgKey(i);
|
|
102
|
+
if (k && !seenImg.has(k)) {
|
|
103
|
+
seenImg.add(k);
|
|
104
|
+
images.push(i);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const vidKey = (v) => `${v.src || ""}|${v.poster || ""}`;
|
|
109
|
+
const seenVid = new Set(base.videos.map(vidKey));
|
|
110
|
+
const videos = [...base.videos];
|
|
111
|
+
for (const v of extra.videos) {
|
|
112
|
+
const k = vidKey(v);
|
|
113
|
+
if ((v.src || v.poster) && !seenVid.has(k)) {
|
|
114
|
+
seenVid.add(k);
|
|
115
|
+
videos.push(v);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const seenBg = new Set(base.backgroundImages.map((b) => b.url));
|
|
120
|
+
const backgroundImages = [...base.backgroundImages];
|
|
121
|
+
for (const b of extra.backgroundImages) {
|
|
122
|
+
if (b.url && !seenBg.has(b.url)) {
|
|
123
|
+
seenBg.add(b.url);
|
|
124
|
+
backgroundImages.push(b);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
images,
|
|
130
|
+
videos,
|
|
131
|
+
backgroundImages,
|
|
132
|
+
svgCount: Math.max(base.svgCount ?? 0, extra.svgCount ?? 0),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
72
136
|
async function gatherPageData(page) {
|
|
73
137
|
return page.evaluate(() => {
|
|
74
138
|
const title = document.title || "";
|
|
75
|
-
const text = (document.body?.innerText || "").slice(0,
|
|
139
|
+
const text = (document.body?.innerText || "").slice(0, 80000);
|
|
76
140
|
const likelyBotWall =
|
|
77
141
|
/just a moment/i.test(title) ||
|
|
78
142
|
/checking your browser/i.test(text) ||
|
|
@@ -145,7 +209,7 @@ async function gatherPageData(page) {
|
|
|
145
209
|
return {
|
|
146
210
|
title,
|
|
147
211
|
likelyBotWall,
|
|
148
|
-
textSample: text.slice(0,
|
|
212
|
+
textSample: text.slice(0, 24000),
|
|
149
213
|
assetInventory: {
|
|
150
214
|
images: imgs.filter((i) => i.src),
|
|
151
215
|
videos,
|
|
@@ -272,23 +336,32 @@ async function main() {
|
|
|
272
336
|
await new Promise((r) => setTimeout(r, 2500));
|
|
273
337
|
snapshot.finalUrl = page.url();
|
|
274
338
|
|
|
339
|
+
let mergedInventory = null;
|
|
340
|
+
let desktopLandmarks = null;
|
|
341
|
+
|
|
275
342
|
for (const w of [1440, 390]) {
|
|
276
343
|
await page.setViewportSize({ width: w, height: w === 1440 ? 900 : 844 });
|
|
277
|
-
|
|
344
|
+
await scrollFullPage(page);
|
|
278
345
|
|
|
279
346
|
const shotPath = join(ROOT, "docs", "design-references", `playwright-${host}-${w}px.png`);
|
|
280
347
|
await page.screenshot({ path: shotPath, fullPage: true });
|
|
281
348
|
snapshot.viewports[w] = { screenshot: `docs/design-references/playwright-${host}-${w}px.png` };
|
|
282
349
|
|
|
350
|
+
const data = await gatherPageData(page);
|
|
351
|
+
|
|
283
352
|
if (w === 1440) {
|
|
284
|
-
const data = await gatherPageData(page);
|
|
285
353
|
snapshot.title = data.title;
|
|
286
354
|
snapshot.likelyBotWall = data.likelyBotWall;
|
|
287
|
-
|
|
288
|
-
|
|
355
|
+
mergedInventory = data.assetInventory;
|
|
356
|
+
desktopLandmarks = data.computedLandmarks;
|
|
289
357
|
snapshot.textSample = data.textSample;
|
|
358
|
+
} else {
|
|
359
|
+
mergedInventory = mergeAssetInventory(mergedInventory, data.assetInventory);
|
|
290
360
|
}
|
|
291
361
|
}
|
|
362
|
+
|
|
363
|
+
snapshot.assetInventory = mergedInventory;
|
|
364
|
+
snapshot.computedLandmarks = desktopLandmarks;
|
|
292
365
|
} finally {
|
|
293
366
|
await browser.close();
|
|
294
367
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
export function ScribewiseLanding() {
|
|
6
|
+
return (
|
|
7
|
+
<main className="relative flex flex-1 flex-col items-center justify-center gap-8 overflow-hidden px-6 py-24 text-center">
|
|
8
|
+
<div
|
|
9
|
+
aria-hidden
|
|
10
|
+
className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,color-mix(in_oklab,var(--primary)_28%,transparent),transparent)]"
|
|
11
|
+
/>
|
|
12
|
+
<p className="text-muted-foreground text-xs font-medium tracking-[0.2em] uppercase">
|
|
13
|
+
Launchframe template
|
|
14
|
+
</p>
|
|
15
|
+
<div className="max-w-2xl space-y-4">
|
|
16
|
+
<h1 className="text-balance font-semibold text-4xl tracking-tight sm:text-5xl">
|
|
17
|
+
Ready for `/clone-website`
|
|
18
|
+
</h1>
|
|
19
|
+
<p className="text-muted-foreground text-balance text-lg">
|
|
20
|
+
Add your target URL and SaaS idea via <code className="text-foreground">launchframe.config.json</code>,
|
|
21
|
+
run recon if needed, then let your agent ship the full landing.
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
<div className="flex flex-wrap items-center justify-center gap-3">
|
|
25
|
+
<Button nativeButton={false} render={<Link href="https://github.com/evangruhlkey/launchframe" />}>
|
|
26
|
+
Launchframe docs
|
|
27
|
+
</Button>
|
|
28
|
+
<Button variant="outline" nativeButton={false} render={<Link href="/" />}>
|
|
29
|
+
Replace this page
|
|
30
|
+
</Button>
|
|
31
|
+
</div>
|
|
32
|
+
</main>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: marketing-landing-production
|
|
3
|
-
description: Elevate an authored or minimalist marketing landing to production quality — layered SVG illustration, pixel-art accents, choreographed motion (Framer Motion tiers A–E), accent tokens, OG/favicon cohesion. Use when the user asks for prod polish, more motion, stronger branding, SVG scenes, or pixel art on `src/app/page.tsx` / `src/components/marketing/**`.
|
|
4
|
-
argument-hint: "[optional paths or sections to prioritize]"
|
|
5
|
-
user-invocable: true
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Marketing Landing — Production Polish
|
|
9
|
-
|
|
10
|
-
You are upgrading a **marketing landing** so it feels shipped — not “fine for a demo.” Read **`AGENTS.md` → Production polish for marketing landings** first; this skill is the executable checklist.
|
|
11
|
-
|
|
12
|
-
## When to run
|
|
13
|
-
|
|
14
|
-
- Clone/rebrand finished but the page still reads **flat** (mostly black text on white + gray placeholders).
|
|
15
|
-
- User explicitly wants **more images**, **motion**, **SVG / illustration**, **pixel art**, **brandability**, **production-ready**.
|
|
16
|
-
- Feature cards use **off-topic filler art** — replace with scenes tied to copy.
|
|
17
|
-
|
|
18
|
-
## Hard requirements
|
|
19
|
-
|
|
20
|
-
1. **`framer-motion`** — staggered hero load (**tier A**), scroll reveals + nested staggers (**tier B**), at least **one** ambient loop (**tier C**: marquee, typing caret, SVG dash drift, gradient pulse — pick what fits brand).
|
|
21
|
-
2. **Interaction polish (tier D)** — measurable hover/tap on primary surfaces (buttons, cards): subtle lift, shadow ramp, scale ≤ 1.02.
|
|
22
|
-
3. **Decorative depth (tier E, optional)** — light pointer parallax **or** scroll-linked transforms; keep translation ≤ ~8px and rotation ≤ ~2deg.
|
|
23
|
-
4. **`useReducedMotion()`** — disable or simplify looping motion and shorten entrances when the user prefers reduced motion.
|
|
24
|
-
5. **SVG illustration layers** — dedicated React components (prefer `src/components/marketing/art/`); use **`currentColor`** where possible so theme tokens drive strokes/fills.
|
|
25
|
-
6. **Pixel art** — if requested: declare palette (hex table in component comment), crisp scaling (`imageRendering: "pixelated"` for intentional upscale), consistent grid logic.
|
|
26
|
-
7. **Brand spine** — motif repeats once in hero + once in a card or footer glyph cluster; define **accent CSS variables** if the page is only monochrome gray today.
|
|
27
|
-
8. **Artifacts** — write **`docs/research/PRODUCTION_UPLIFT.md`**: bullets for SVG modules added, motion tiers shipped, accent tokens, OG/favicon edits.
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
|
|
31
|
-
- `npm run build` passes.
|
|
32
|
-
- Lighthouse/visual sanity: no layout shift explosions from animations; loops are subtle at default amplitude.
|
|
33
|
-
|
|
34
|
-
## Out of scope unless asked
|
|
35
|
-
|
|
36
|
-
Backend, CMS wiring, analytics, full accessibility audit beyond motion preferences.
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<!-- Mirrors .claude/skills/marketing-landing-production/SKILL.md — edit skill first, then sync this body if drift occurs. -->
|
|
2
|
-
|
|
3
|
-
# Marketing Landing — Production Polish
|
|
4
|
-
|
|
5
|
-
You are upgrading a **marketing landing** so it feels shipped — not “fine for a demo.” Read **`AGENTS.md` → Production polish for marketing landings** first; treat this command as the executable checklist.
|
|
6
|
-
|
|
7
|
-
## When to run
|
|
8
|
-
|
|
9
|
-
- Clone/rebrand finished but the page still reads **flat** (mostly black text on white + gray placeholders).
|
|
10
|
-
- User explicitly wants **more images**, **motion**, **SVG / illustration**, **pixel art**, **brandability**, **production-ready**.
|
|
11
|
-
- Feature cards use **off-topic filler art** — replace with scenes tied to copy.
|
|
12
|
-
|
|
13
|
-
## Hard requirements
|
|
14
|
-
|
|
15
|
-
1. **`framer-motion`** — staggered hero load (**tier A**), scroll reveals + nested staggers (**tier B**), at least **one** ambient loop (**tier C**: marquee, typing caret, SVG dash drift, gradient pulse — pick what fits brand).
|
|
16
|
-
2. **Interaction polish (tier D)** — measurable hover/tap on primary surfaces (buttons, cards): subtle lift, shadow ramp, scale ≤ 1.02.
|
|
17
|
-
3. **Decorative depth (tier E, optional)** — light pointer parallax **or** scroll-linked transforms; keep translation ≤ ~8px and rotation ≤ ~2deg.
|
|
18
|
-
4. **`useReducedMotion()`** — disable or simplify looping motion and shorten entrances when the user prefers reduced motion.
|
|
19
|
-
5. **SVG illustration layers** — dedicated React components (prefer `src/components/marketing/art/`); use **`currentColor`** where possible so theme tokens drive strokes/fills.
|
|
20
|
-
6. **Pixel art** — if requested: declare palette (hex table in component comment), crisp scaling (`imageRendering: "pixelated"` for intentional upscale), consistent grid logic.
|
|
21
|
-
7. **Brand spine** — motif repeats once in hero + once in a card or footer glyph cluster; define **accent CSS variables** if the page is only monochrome gray today.
|
|
22
|
-
8. **Artifacts** — write **`docs/research/PRODUCTION_UPLIFT.md`**: bullets for SVG modules added, motion tiers shipped, accent tokens, OG/favicon edits.
|
|
23
|
-
|
|
24
|
-
## Verification
|
|
25
|
-
|
|
26
|
-
- `npm run build` passes.
|
|
27
|
-
- Lighthouse/visual sanity: no layout shift explosions from animations; loops are subtle at default amplitude.
|
|
28
|
-
|
|
29
|
-
## Out of scope unless asked
|
|
30
|
-
|
|
31
|
-
Backend, CMS wiring, analytics, full accessibility audit beyond motion preferences.
|