launchframe 0.4.0 → 0.4.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.
@@ -0,0 +1,39 @@
1
+ <!-- AUTO-GENERATED from .claude/skills/launchframe/SKILL.md — do not edit directly.
2
+ Run `node scripts/sync-skills.mjs` to regenerate. -->
3
+
4
+
5
+ # Launchframe
6
+
7
+ Help the user create a **new** Launchframe project. The CLI is **parameterless**:
8
+
9
+ ```bash
10
+ npx launchframe@latest
11
+ ```
12
+
13
+ It unpacks the full template into the **current working directory** (the folder root where the user runs the command). They should `mkdir`, `cd` into an **empty** folder first.
14
+
15
+ ## What you do
16
+
17
+ 1. Ensure the user has an **empty** directory (no existing `package.json`, `src/`, or `next.config.ts` there). If the workspace is already a Launchframe/Next project, they may only need `/clone-website` instead — clarify.
18
+
19
+ 2. Run exactly:
20
+
21
+ ```bash
22
+ npx launchframe@latest
23
+ ```
24
+
25
+ Optional: `LAUNCHFRAME_SOURCE_URL` and `LAUNCHFRAME_SAAS_IDEA` environment variables in the same shell if they want values pre-filled without editing files later.
26
+
27
+ 3. **Never** run this with the output target **inside** the `launchframe` package directory (the npm-installed template). If the open folder is this monorepo/template, have them `mkdir ../my-app && cd ../my-app` (sibling path), then run `npx launchframe@latest` there.
28
+
29
+ 4. Optional flags (same as CLI): `--dir <path>` to scaffold into another folder instead of cwd, `--skip-install` to skip `npm install`.
30
+
31
+ 5. After it finishes: they should **`npm run dev`** from **that same folder** (no extra `cd` if they scaffolded into cwd). Then they edit **`src/lib/launchframe-config.ts`** for reference URL and SaaS idea, and run **`/clone-website`** with that URL.
32
+
33
+ ## If optional notes from the user after the slash command (the CLI itself needs no URL or SaaS strings) are present
34
+
35
+ The user may still paste a URL or idea in chat — **do not** require them for the CLI. Put any extra context into **`src/lib/launchframe-config.ts`** or `launchframe.context.json` for them after scaffold.
36
+
37
+ ## Fallback (local dev only)
38
+
39
+ From a checkout of this repo: `node bin/launchframe.mjs` with the same empty-folder rules (optionally `--dir` outside the package root).
package/AGENTS.md CHANGED
@@ -7,7 +7,7 @@ This version has breaking changes — APIs, conventions, and file structure may
7
7
  # Website Reverse-Engineer Template
8
8
 
9
9
  ## What This Is
10
- A reusable template for reverse-engineering any website into a clean, modern Next.js codebase using AI coding agents. The Next.js + shadcn/ui + Tailwind v4 base is pre-scaffolded — just run `/clone-website <url1> [<url2> ...]`.
10
+ A reusable template for reverse-engineering any website into a clean, modern Next.js codebase using AI coding agents. The Next.js + shadcn/ui + Tailwind v4 base is pre-scaffolded — for a **new** folder, `mkdir`, `cd` into an **empty** directory, run **`npx launchframe@latest`** (no parameters), then edit **`src/lib/launchframe-config.ts`** and run **`/clone-website`** with your URL (or invoke **`/launchframe`** so the agent runs the same command). Or work in this repo and run **`/clone-website <url1> [<url2> ...]`** to clone into the current tree.
11
11
 
12
12
  ## Tech Stack
13
13
  - **Framework:** Next.js 16 (App Router, React 19, TypeScript strict)
@@ -35,6 +35,7 @@ A reusable template for reverse-engineering any website into a clean, modern Nex
35
35
  - **No personal aesthetic changes during emulation phase** — match 1:1 first, customize later
36
36
  - **Real content** — use actual text and assets from the target site, not placeholders
37
37
  - **Beauty-first** — every pixel matters
38
+ - **DOM crawl priority** — when walking the target page, emphasize **images** (raster, responsive sources, CSS backgrounds), **SVGs** (inline icons, sprites, masks), then **motion** (keyframes, transitions, scroll/time-driven animation, libraries). Scrape and save real assets from the DOM/network first; **create** a stand-in image or vector only when fetch/blocking prevents extraction, and label substitutes clearly in research notes so the clone stays auditable
38
39
 
39
40
  ## Project Structure
40
41
  ```
@@ -60,6 +61,6 @@ scripts/ # Asset download scripts
60
61
  ## MOST IMPORTANT NOTES
61
62
  - When launching Claude Code agent teams, ALWAYS have each teammate work in their own worktree branch and merge everyone's work at the end, resolving any merge conflicts smartly since you are basically serving the orchestrator role and have full context to our goals, work given, work achieved, and desired outcomes.
62
63
  - After editing `AGENTS.md`, run `bash scripts/sync-agent-rules.sh` to regenerate platform-specific instruction files.
63
- - After editing `.claude/skills/clone-website/SKILL.md`, run `node scripts/sync-skills.mjs` to regenerate the skill for all platforms.
64
+ - After editing `.claude/skills/*/SKILL.md` (for example `clone-website` or `launchframe`), run `node scripts/sync-skills.mjs` to regenerate skill and command files for all platforms.
64
65
 
65
66
  @docs/research/INSPECTION_GUIDE.md
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <a href="https://github.com/JCodesMore/ai-website-cloner-template/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" /></a> <a href="https://github.com/JCodesMore/ai-website-cloner-template/stargazers"><img src="https://img.shields.io/github/stars/JCodesMore/ai-website-cloner-template?style=flat" alt="Stars" /></a> <a href="https://discord.gg/hrTSX5yTpB"><img src="https://img.shields.io/discord/1400896964597383279?label=discord" alt="Discord" /></a>
4
4
 
5
- Scaffold a Next.js + shadcn/ui project from **a reference URL you want to copy** plus **your SaaS idea** that drives landing-page positioning. Then run `/clone-website` so your AI agent reverse-engineers the reference layout while preserving your messaging inputs (`launchframe.context.json`, `docs/research/LAUNCHFRAME.md`, `src/lib/launchframe-config.ts`).
5
+ Scaffold a Next.js + shadcn/ui project in **the folder where you run the command** use **`npx launchframe@latest`** (no arguments; create an empty directory, `cd` into it, then run it). Configure the reference URL and SaaS copy in **`src/lib/launchframe-config.ts`**. Then run **`/clone-website`** so your AI agent reverse-engineers the reference layout while preserving your messaging (`launchframe.context.json`, `docs/research/LAUNCHFRAME.md`, `src/lib/launchframe-config.ts`). In the agent, **`/launchframe`** means the same one-liner.
6
6
 
7
7
  **Recommended: [Claude Code](https://docs.anthropic.com/en/docs/claude-code) with Opus 4.7 for best results** — but works with a variety of AI coding agents.
8
8
 
@@ -14,32 +14,33 @@ Scaffold a Next.js + shadcn/ui project from **a reference URL you want to copy**
14
14
 
15
15
  ## Quick Start
16
16
 
17
- ### CLI (recommended)
17
+ ### 1. New project (empty folder)
18
18
 
19
- From an empty folder (or anywhere you want the project folder created):
19
+ Create an **empty** directory, go into it, run the CLI with **no parameters** — files are written to **that folder** (your project root):
20
20
 
21
21
  ```bash
22
- npx launchframe@latest https://example.com "Your SaaS idea in plain language"
22
+ mkdir my-app
23
+ cd my-app
24
+ npx launchframe@latest
23
25
  ```
24
26
 
25
- Optional flags:
27
+ Optional: set `LAUNCHFRAME_SOURCE_URL` and `LAUNCHFRAME_SAAS_IDEA` in the environment before running to pre-fill config without editing files.
26
28
 
27
- - `--dir my-app` / `-o my-app` output folder name (default: `<hostname>-launchframe`)
28
- - `--skip-install` — scaffold files only; run `npm install` yourself
29
+ Then edit `src/lib/launchframe-config.ts` if you still need to change the reference URL or SaaS pitch, run `npm run dev`, and use **`/clone-website`** with your reference URL.
29
30
 
30
- Then:
31
+ ### AI agents (slash command)
31
32
 
32
- ```bash
33
- cd <your-project-folder>
34
- npm run dev
35
- ```
33
+ In Cursor, Claude Code, Continue, etc., **`/launchframe`** tells the agent to run **`npx launchframe@latest`** in an empty folder the user chooses (same as above). No URL or SaaS strings are required on the command line.
34
+
35
+ ### Optional flags
36
36
 
37
- Open your AI agent and run `/clone-website <same-reference-url>` so it rebuilds the reference site into components while aligning hero copy with your SaaS idea files above.
37
+ - `--dir path` / `-o path` scaffold into another folder instead of the current directory (must be empty)
38
+ - `--skip-install` — skip `npm install`
38
39
 
39
40
  ### Git template (advanced)
40
41
 
41
42
  1. Clone this repository and `npm install`
42
- 2. Replace `src/lib/launchframe-config.ts` or run `npx launchframe ...` into a fresh folder
43
+ 2. Point `src/lib/launchframe-config.ts` at your site, or create sibling folder and run **`npx launchframe@latest`** there
43
44
  3. Run `/clone-website <target-url>` from your agent
44
45
 
45
46
  > Using a different agent? Open `AGENTS.md` for project instructions — most agents pick it up automatically.
@@ -1,54 +1,82 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Scaffold a Launchframe project: clone reference URL via AI workflow + SaaS landing copy.
4
- * Usage: npx launchframe@latest <url> "<saas-idea>" [--dir=name] [--skip-install]
3
+ * Scaffold a Launchframe project into the current directory (or --dir).
4
+ * Usage: npx launchframe@latest [--dir=path] [--skip-install]
5
+ * Optional: LAUNCHFRAME_SOURCE_URL, LAUNCHFRAME_SAAS_IDEA env vars, or legacy CLI args.
5
6
  */
6
7
 
7
- import { cp, mkdir, readdir, readFile, writeFile } from "fs/promises";
8
+ import { cp, mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
8
9
  import { spawn } from "node:child_process";
9
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
10
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
10
11
  import { fileURLToPath } from "node:url";
11
12
 
12
13
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
14
  const PKG_ROOT = resolve(__dirname, "..");
14
15
 
15
- const SKIP_DIR_NAMES = new Set(["bin", "node_modules", ".git", ".next", "dist", "out"]);
16
-
17
- /** Root dot-directories we ship for agent tooling */
18
- const ALLOW_DOT_DIRS = new Set([
19
- ".cursor",
20
- ".claude",
21
- ".codex",
22
- ".continue",
23
- ".gemini",
24
- ".opencode",
25
- ".windsurf",
26
- ".github",
16
+ const DEFAULT_URL = "https://example.com";
17
+ const DEFAULT_SAAS_IDEA =
18
+ "Edit your SaaS pitch in src/lib/launchframe-config.ts, then run /clone-website with your reference URL.";
19
+
20
+ /**
21
+ * Never copy these root entries into a scaffolded app (build artifacts, VCS, the CLI itself).
22
+ * All other root files and folders are copied as-is — including every dotfile and dot-directory
23
+ * so AI agents see the same agent rules and commands as this template.
24
+ */
25
+ const SKIP_DIR_NAMES = new Set([
26
+ "bin",
27
+ "node_modules",
28
+ ".git",
29
+ ".next",
30
+ "dist",
31
+ "out",
32
+ "coverage",
33
+ ".turbo",
27
34
  ]);
28
35
 
29
- const SKIP_ROOT_FILES = new Set(["package-lock.json"]);
36
+ const SKIP_ROOT_FILES = new Set([
37
+ "package-lock.json",
38
+ ".DS_Store",
39
+ "Thumbs.db",
40
+ ]);
41
+
42
+ async function pathExists(p) {
43
+ try {
44
+ await stat(p);
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
30
50
 
31
51
  function printHelp() {
32
52
  console.log(`
33
- launchframe — scaffold a Next.js app for cloning a reference site + your SaaS idea
53
+ launchframe — scaffold a Next.js app into the current directory (project root)
34
54
 
35
55
  Usage:
36
- npx launchframe@latest <url> "<saas-idea>" [options]
56
+ npx launchframe@latest
57
+
58
+ This unpacks the template into the folder you are in (where you ran the command).
59
+ No URL or SaaS arguments are required — edit src/lib/launchframe-config.ts after scaffold.
37
60
 
38
- Arguments:
39
- <url> HTTPS URL of the site to reverse-engineer (visual reference)
40
- "<saas-idea>" Short pitch / positioning that should appear on the landing page
61
+ Optional environment variables (same session):
62
+ LAUNCHFRAME_SOURCE_URL Reference site to clone later (https://...)
63
+ LAUNCHFRAME_SAAS_IDEA Short landing-page pitch text
64
+
65
+ Legacy (optional positional args, for scripts only):
66
+ npx launchframe@latest <url> "<saas-idea>"
41
67
 
42
68
  Options:
43
- --dir, -o Output folder (default: first label of hostname + "-launchframe")
69
+ --dir, -o Scaffold into this folder instead of the current directory (must be empty)
44
70
  --skip-install Do not run npm install after scaffolding
45
71
  -h, --help Show this message
46
72
 
47
73
  Note:
48
- The output folder must not live inside the Launchframe package directory (the folder that contains this CLI).
74
+ Run inside an empty project folder (no existing package.json / src / next.config).
75
+ The output folder must not be inside the Launchframe npm package directory.
49
76
 
50
77
  Example:
51
- npx launchframe@latest https://stripe.com "AI invoicing for freelancers"
78
+ mkdir my-app && cd my-app
79
+ npx launchframe@latest
52
80
  `);
53
81
  }
54
82
 
@@ -106,20 +134,8 @@ function validateUrl(raw) {
106
134
  return u.href;
107
135
  }
108
136
 
109
- function defaultDirName(urlStr) {
110
- try {
111
- const host = new URL(urlStr).hostname.replace(/^www\./i, "");
112
- const label = host.split(".")[0] || "site";
113
- const safe = label.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
114
- return `${safe || "site"}-launchframe`;
115
- } catch {
116
- return "launchframe-app";
117
- }
118
-
119
- }
120
-
121
- function slugFromDir(dir) {
122
- const base = dir.replace(/\\/g, "/").split("/").filter(Boolean).pop() ?? "launchframe-app";
137
+ function slugFromDir(destRootAbs) {
138
+ const base = basename(resolve(destRootAbs));
123
139
  return base
124
140
  .toLowerCase()
125
141
  .replace(/[^a-z0-9-_]/g, "-")
@@ -133,9 +149,6 @@ function tsStringLiteral(value) {
133
149
 
134
150
  function shouldCopyRootEntry(baseName, isDirectory) {
135
151
  if (SKIP_DIR_NAMES.has(baseName)) return false;
136
- if (isDirectory && baseName.startsWith(".")) {
137
- if (!ALLOW_DOT_DIRS.has(baseName)) return false;
138
- }
139
152
  if (!isDirectory && SKIP_ROOT_FILES.has(baseName)) return false;
140
153
  return true;
141
154
  }
@@ -188,7 +201,8 @@ async function writeGeneratedPackageJson(destRoot, npmPackageName) {
188
201
 
189
202
  async function writeLaunchframeArtifacts(destRoot, url, idea) {
190
203
  const configTs = `/**
191
- * Written by Launchframe CLI edit freely after scaffolding.
204
+ * Set your reference site and positioning, then use /clone-website with the same URL.
205
+ * Written by Launchframe CLI — edit freely.
192
206
  */
193
207
  export const LAUNCHFRAME_SOURCE_URL = ${tsStringLiteral(url)} as const;
194
208
 
@@ -201,7 +215,7 @@ export const LAUNCHFRAME_SAAS_IDEA = ${tsStringLiteral(idea)} as const;
201
215
  sourceUrl: url,
202
216
  saasIdea: idea,
203
217
  notes:
204
- "Use /clone-website with sourceUrl for pixel-perfect extraction. Align landing copy with saasIdea.",
218
+ "Edit this file or src/lib/launchframe-config.ts. Use /clone-website with sourceUrl for pixel-perfect extraction.",
205
219
  };
206
220
  await writeFile(
207
221
  join(destRoot, "launchframe.context.json"),
@@ -219,7 +233,7 @@ ${url}
219
233
 
220
234
  ${idea}
221
235
 
222
- When running \`/clone-website\`, pass the reference URL above. After structural cloning, rewrite headings and hero copy so they clearly communicate the SaaS idea while respecting attribution and copyright for third-party brands.
236
+ When running \`/clone-website\`, pass the reference URL above (update src/lib/launchframe-config.ts first if you still use the default). After structural cloning, align hero copy with your SaaS idea while respecting attribution and copyright for third-party brands.
223
237
  `;
224
238
 
225
239
  await mkdir(join(destRoot, "docs", "research"), { recursive: true });
@@ -231,7 +245,14 @@ async function writeReadme(destRoot, npmPackageName, url, idea) {
231
245
 
232
246
  Created with [\`launchframe\`](https://www.npmjs.com/package/launchframe).
233
247
 
234
- ## Inputs
248
+ ## Configure
249
+
250
+ Edit \`src/lib/launchframe-config.ts\`:
251
+
252
+ - \`LAUNCHFRAME_SOURCE_URL\` — site to reverse-engineer
253
+ - \`LAUNCHFRAME_SAAS_IDEA\` — landing copy / positioning
254
+
255
+ Current values (from scaffold):
235
256
 
236
257
  - **Reference site:** ${url}
237
258
  - **SaaS idea:** ${idea}
@@ -243,13 +264,7 @@ npm install
243
264
  npm run dev
244
265
  \`\`\`
245
266
 
246
- Open your AI agent (Cursor, Claude Code, etc.) and run:
247
-
248
- \`\`\`
249
- /clone-website ${url}
250
- \`\`\`
251
-
252
- Keep the SaaS positioning from \`launchframe.context.json\` / \`src/lib/launchframe-config.ts\` when adapting cloned sections.
267
+ Open your AI agent and run \`/clone-website <your-reference-url>\` (same URL as in the config).
253
268
 
254
269
  See \`AGENTS.md\` for full agent instructions.
255
270
  `;
@@ -257,6 +272,21 @@ See \`AGENTS.md\` for full agent instructions.
257
272
  await writeFile(join(destRoot, "README.md"), body, "utf8");
258
273
  }
259
274
 
275
+ /** Refuse to stomp an existing Next-style project in the target directory. */
276
+ async function assertScaffoldTargetVacant(destRoot) {
277
+ const conflicts = ["package.json", "next.config.ts", "src"];
278
+ for (const c of conflicts) {
279
+ if (await pathExists(join(destRoot, c))) {
280
+ console.error(
281
+ `Refusing to scaffold: "${c}" already exists in this folder.\n` +
282
+ `Create a new empty directory, cd into it, then run:\n` +
283
+ ` npx launchframe@latest\n`,
284
+ );
285
+ process.exit(1);
286
+ }
287
+ }
288
+ }
289
+
260
290
  function runNpmInstall(cwd) {
261
291
  return new Promise((resolvePromise, reject) => {
262
292
  const child = spawn("npm", ["install"], {
@@ -272,6 +302,17 @@ function runNpmInstall(cwd) {
272
302
  });
273
303
  }
274
304
 
305
+ function resolveUrlAndIdea(args) {
306
+ const envUrl =
307
+ process.env.LAUNCHFRAME_SOURCE_URL?.trim() || process.env.LAUNCHFRAME_URL?.trim();
308
+ const envIdea = process.env.LAUNCHFRAME_SAAS_IDEA?.trim();
309
+
310
+ let urlRaw = args.url?.trim() || envUrl || DEFAULT_URL;
311
+ let ideaRaw = args.idea?.trim() || envIdea || DEFAULT_SAAS_IDEA;
312
+
313
+ return { urlRaw, ideaRaw };
314
+ }
315
+
275
316
  async function main() {
276
317
  const args = parseArgs(process.argv.slice(2));
277
318
  if (args.help) {
@@ -279,36 +320,31 @@ async function main() {
279
320
  process.exit(0);
280
321
  }
281
322
 
282
- if (!args.url || !args.idea) {
283
- console.error("Error: missing URL or SaaS idea.\n");
284
- printHelp();
323
+ const destRoot = args.dir?.trim()
324
+ ? resolve(process.cwd(), args.dir.trim())
325
+ : resolve(process.cwd());
326
+
327
+ if (isForbiddenOutput(PKG_ROOT, destRoot)) {
328
+ console.error(
329
+ "Output folder cannot be inside the Launchframe package directory. Create a new folder outside this package and cd into it, then run npx launchframe@latest again.",
330
+ );
285
331
  process.exit(1);
286
332
  }
287
333
 
334
+ await assertScaffoldTargetVacant(destRoot);
335
+
336
+ const { urlRaw, ideaRaw } = resolveUrlAndIdea(args);
337
+
288
338
  let url;
289
339
  try {
290
- url = validateUrl(args.url);
340
+ url = validateUrl(urlRaw);
291
341
  } catch (e) {
292
342
  console.error(String(e.message));
293
343
  process.exit(1);
294
344
  }
295
345
 
296
- const idea = args.idea.trim();
297
- if (!idea) {
298
- console.error("Error: SaaS idea cannot be empty.");
299
- process.exit(1);
300
- }
301
-
302
- const dirName = args.dir?.trim() || defaultDirName(url);
303
- const destRoot = resolve(process.cwd(), dirName);
304
- const npmPackageName = slugFromDir(dirName);
305
-
306
- if (isForbiddenOutput(PKG_ROOT, destRoot)) {
307
- console.error(
308
- "Output folder cannot be inside the Launchframe package directory. Run from a parent folder or choose another path.",
309
- );
310
- process.exit(1);
311
- }
346
+ const idea = ideaRaw.trim() || DEFAULT_SAAS_IDEA;
347
+ const npmPackageName = slugFromDir(destRoot);
312
348
 
313
349
  await mkdir(destRoot, { recursive: true });
314
350
 
@@ -318,22 +354,23 @@ async function main() {
318
354
  await writeLaunchframeArtifacts(destRoot, url, idea);
319
355
  await writeReadme(destRoot, npmPackageName, url, idea);
320
356
 
321
- console.log(`\nCreated Launchframe project at ${destRoot}`);
357
+ console.log(`\nScaffolded Launchframe in:\n ${destRoot}`);
322
358
  console.log(` Reference URL: ${url}`);
323
359
  console.log(` SaaS idea: ${idea}\n`);
360
+ console.log("Edit src/lib/launchframe-config.ts if you need different values.\n");
324
361
 
325
362
  if (!args.skipInstall) {
326
363
  console.log("Running npm install...\n");
327
364
  try {
328
365
  await runNpmInstall(destRoot);
329
- console.log("\nDone. Next: cd " + JSON.stringify(dirName) + " && npm run dev\n");
366
+ console.log("\nDone. From this folder: npm run dev\n");
330
367
  } catch (e) {
331
368
  console.error(String(e.message));
332
- console.error("\nDependencies were not installed. Run npm install inside the folder manually.\n");
369
+ console.error("\nRun npm install in this folder manually.\n");
333
370
  process.exit(1);
334
371
  }
335
372
  } else {
336
- console.log("Skipped npm install (--skip-install). Run npm install inside the folder.\n");
373
+ console.log("Skipped npm install (--skip-install). Run npm install in this folder.\n");
337
374
  }
338
375
  }
339
376
 
@@ -4,6 +4,16 @@
4
4
 
5
5
  This guide outlines what to capture when inspecting a target website via Chrome MCP or browser DevTools.
6
6
 
7
+ ## Priority: media, SVGs, and motion (do this early)
8
+
9
+ When crawling the DOM and network, **tackle these before fine-tuning copy or spacing**:
10
+
11
+ 1. **Raster imagery** — Every `<img>`, `<picture>` / `source`, `srcset` / `sizes`, CDN URLs, lazy-loaded `data-src`, `loading="lazy"` nodes, **CSS `background-image`** on the element and ancestors (including `::before` / `::after`), masks that use `url()`, `<video>` still / poster frames. Prefer **downloading** originals via scripts or MCP; if a URL is blocked or session-gated, **export a screenshot** of the element’s bounding box at a crisp DPR and store it under `public/images/`, and note the substitute in the spec.
12
+ 2. **SVGs** — Inline `<svg>`, `<use>` / sprite sheets, **SVG in CSS** (`mask-image`, `background-image`), favicons as SVG, logo marks. Prefer extracting path/viewBox into React components or static files under `public/` — **recreate** from a screenshot/trace only when the markup is obfuscated or blocked.
13
+ 3. **Motion & animation** — Inspect Styles for `animation`, `animation-name`, `animation-timeline`, `transition`, `transform`, `@keyframes`; check for libraries (Framer Motion, GSAP, Lottie, Lenis). Capture **durations, easings, delays, fill-modes**, scroll/view triggers, and `prefers-reduced-motion` handling. Motion often defines perceived quality — do not leave it as an afterthought.
14
+
15
+ Then continue with typography, spacing, and component structure as usual.
16
+
7
17
  ## Phase 1: Visual Audit
8
18
 
9
19
  ### Screenshots to Capture
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "launchframe",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "private": false,
5
5
  "description": "Scaffold a Next.js app from a reference URL plus your SaaS idea — AI-ready website cloning",
6
6
  "author": "JCodesMore",
@@ -62,7 +62,9 @@
62
62
  ".gemini",
63
63
  ".opencode",
64
64
  ".windsurf",
65
- ".github"
65
+ ".github",
66
+ ".amazonq",
67
+ ".augment"
66
68
  ],
67
69
  "scripts": {
68
70
  "dev": "next dev",