launchframe 0.4.0 → 0.4.1

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,42 @@
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
+ You are helping the user scaffold a **new** project from **the reference URL and SaaS idea from the user (see slash command arguments)**:
8
+
9
+ - A **reference URL** (the website to copy later with `/clone-website`)
10
+ - A **SaaS idea** string (headline / positioning for the generated landing page)
11
+
12
+ ## Parse inputs
13
+
14
+ 1. Split **the reference URL and SaaS idea from the user (see slash command arguments)** into:
15
+ - **URL** — First `http://` or `https://` URL. Normalize (trim, validate). If invalid or missing, ask once for a correct URL.
16
+ - **SaaS idea** — Everything after the URL, typically in quotes. Strip surrounding quotes. If empty, ask for a short product pitch.
17
+
18
+ 2. Optional flags the user might pass (same as the CLI): `--dir` / `-o` for output folder, `--skip-install` to skip `npm install`.
19
+
20
+ ## Run the published CLI
21
+
22
+ Execute the scaffold using the **latest** package from npm (exact intent: **`launchframe@latest`**):
23
+
24
+ ```bash
25
+ npx launchframe@latest "<url>" "<saas-idea>" [--dir <folder>] [--skip-install]
26
+ ```
27
+
28
+ - Use shell-appropriate quoting (PowerShell vs bash). Escape embedded quotes in the SaaS idea.
29
+ - **Output path:** The Launchframe CLI must not write **inside** the npm package / template directory itself (that would recurse). If the open workspace is this repository, run `npx` with `--dir` pointing to a **sibling** path (e.g. `..\\my-app` on Windows, `../my-app` on macOS/Linux) or ask the user for a folder **outside** the repo.
30
+ - Prefer letting the CLI run `npm install` unless the user passed `--skip-install`.
31
+
32
+ ## After scaffold
33
+
34
+ Tell the user:
35
+
36
+ 1. `cd` into the new project directory.
37
+ 2. `npm run dev` to preview the SaaS landing shell.
38
+ 3. Run **`/clone-website <same-reference-url>`** in that project so the agent can reverse-engineer the reference site into components, while keeping the SaaS idea from `launchframe.context.json` / `src/lib/launchframe-config.ts`.
39
+
40
+ ## Fallback (local dev only)
41
+
42
+ If `npx launchframe@latest` is unavailable (offline), from a **checkout of this repo** you may run `node bin/launchframe.mjs "<url>" "<saas-idea>" ...` with the same rules for `--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 — start a **new** project with **`/launchframe <url> "your saas idea"`** (runs **`npx launchframe@latest`**), or work in the current repo and run **`/clone-website <url1> [<url2> ...]`** to clone into this 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 from **a reference URL you want to copy** plus **your SaaS idea** that drives landing-page positioning. Use **`npx launchframe@latest`** or the slash command **`/launchframe <url> "your idea"`** to scaffold, 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`).
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,7 +14,17 @@ 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
+ ### AI agents (slash command)
18
+
19
+ In Cursor, Claude Code, Continue, and other synced tools:
20
+
21
+ ```text
22
+ /launchframe https://example.com "Your SaaS idea in plain language"
23
+ ```
24
+
25
+ The agent runs **`npx launchframe@latest`** with those arguments (see `.cursor/commands/launchframe.md`). Output must be **outside** the template package directory when developing from a clone of this repo — use `--dir ../my-app` or an absolute path.
26
+
27
+ ### CLI (same as slash command)
18
28
 
19
29
  From an empty folder (or anywhere you want the project folder created):
20
30
 
@@ -22,6 +32,8 @@ From an empty folder (or anywhere you want the project folder created):
22
32
  npx launchframe@latest https://example.com "Your SaaS idea in plain language"
23
33
  ```
24
34
 
35
+ Scaffolding copies the full template at the repository root — including **hidden agent config** (for example `.cursor/`, `.claude/`, `.github/`, `.amazonq/`, `.augment/`, and other dotfiles) so tools see the same rules and commands as this template.
36
+
25
37
  Optional flags:
26
38
 
27
39
  - `--dir my-app` / `-o my-app` — output folder name (default: `<hostname>-launchframe`)
@@ -39,7 +51,7 @@ Open your AI agent and run `/clone-website <same-reference-url>` so it rebuilds
39
51
  ### Git template (advanced)
40
52
 
41
53
  1. Clone this repository and `npm install`
42
- 2. Replace `src/lib/launchframe-config.ts` or run `npx launchframe ...` into a fresh folder
54
+ 2. Replace `src/lib/launchframe-config.ts` or run `npx launchframe@latest ...` into a fresh folder
43
55
  3. Run `/clone-website <target-url>` from your agent
44
56
 
45
57
  > Using a different agent? Open `AGENTS.md` for project instructions — most agents pick it up automatically.
@@ -12,21 +12,27 @@ import { fileURLToPath } from "node:url";
12
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
13
13
  const PKG_ROOT = resolve(__dirname, "..");
14
14
 
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",
15
+ /**
16
+ * Never copy these root entries into a scaffolded app (build artifacts, VCS, the CLI itself).
17
+ * All other root files and folders are copied as-is including every dotfile and dot-directory
18
+ * so AI agents see the same agent rules, skills, and IDE metadata as this template.
19
+ */
20
+ const SKIP_DIR_NAMES = new Set([
21
+ "bin",
22
+ "node_modules",
23
+ ".git",
24
+ ".next",
25
+ "dist",
26
+ "out",
27
+ "coverage",
28
+ ".turbo",
27
29
  ]);
28
30
 
29
- const SKIP_ROOT_FILES = new Set(["package-lock.json"]);
31
+ const SKIP_ROOT_FILES = new Set([
32
+ "package-lock.json",
33
+ ".DS_Store",
34
+ "Thumbs.db",
35
+ ]);
30
36
 
31
37
  function printHelp() {
32
38
  console.log(`
@@ -46,6 +52,8 @@ Options:
46
52
 
47
53
  Note:
48
54
  The output folder must not live inside the Launchframe package directory (the folder that contains this CLI).
55
+ Scaffolding copies every root file and folder from the template (including dotfiles such as .cursor, .claude,
56
+ .github, etc.) except build/cache directories, so your AI tools see the same rules and commands as upstream.
49
57
 
50
58
  Example:
51
59
  npx launchframe@latest https://stripe.com "AI invoicing for freelancers"
@@ -133,9 +141,6 @@ function tsStringLiteral(value) {
133
141
 
134
142
  function shouldCopyRootEntry(baseName, isDirectory) {
135
143
  if (SKIP_DIR_NAMES.has(baseName)) return false;
136
- if (isDirectory && baseName.startsWith(".")) {
137
- if (!ALLOW_DOT_DIRS.has(baseName)) return false;
138
- }
139
144
  if (!isDirectory && SKIP_ROOT_FILES.has(baseName)) return false;
140
145
  return true;
141
146
  }
@@ -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.1",
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",
@@ -1,111 +1,124 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Generates clone-website command/skill files for all supported AI coding platforms.
5
- * Source of truth: .claude/skills/clone-website/SKILL.md
4
+ * Generates invokable skill/command files for all supported AI coding platforms.
5
+ * Source of truth: `.claude/skills/<skill-id>/SKILL.md` (YAML frontmatter + markdown body).
6
6
  *
7
7
  * Usage: node scripts/sync-skills.mjs
8
8
  */
9
9
 
10
- import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
11
- import { dirname, join } from 'node:path';
12
- import { fileURLToPath } from 'node:url';
10
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
15
+
16
+ const SKILLS = [
17
+ {
18
+ id: "clone-website",
19
+ sourceRel: ".claude/skills/clone-website/SKILL.md",
20
+ shortDesc: "Reverse-engineer and clone any website as a pixel-perfect replica",
21
+ plainSubstitution: "the target URL provided by the user",
22
+ augmentArgumentHint: "<url>",
23
+ },
24
+ {
25
+ id: "launchframe",
26
+ sourceRel: ".claude/skills/launchframe/SKILL.md",
27
+ shortDesc:
28
+ "Scaffold a Next.js app with npx launchframe@latest from a reference URL and SaaS idea",
29
+ plainSubstitution:
30
+ "the reference URL and SaaS idea from the user (see slash command arguments)",
31
+ augmentArgumentHint: "<url> \"<saas-idea>\"",
32
+ },
33
+ ];
13
34
 
14
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
15
- const SOURCE = join(ROOT, '.claude', 'skills', 'clone-website', 'SKILL.md');
16
-
17
- // --- Parse source skill ---
18
-
19
- let raw;
20
- try {
21
- raw = readFileSync(SOURCE, 'utf8').replace(/\r\n/g, '\n');
22
- } catch {
23
- console.error(`Error: Source skill not found at .claude/skills/clone-website/SKILL.md`);
24
- process.exit(1);
35
+ function write(relPath, content) {
36
+ const full = join(ROOT, relPath);
37
+ mkdirSync(dirname(full), { recursive: true });
38
+ writeFileSync(full, content, "utf8");
39
+ console.log(` \u2713 ${relPath}`);
25
40
  }
26
41
 
27
- const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
28
- if (!match) {
29
- console.error('Error: Could not parse SKILL.md frontmatter');
30
- process.exit(1);
42
+ function parseSkill(sourceRel) {
43
+ const full = join(ROOT, sourceRel);
44
+ const raw = readFileSync(full, "utf8").replace(/\r\n/g, "\n");
45
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
46
+ if (!match) {
47
+ throw new Error(`Could not parse frontmatter: ${sourceRel}`);
48
+ }
49
+ return { raw, body: match[2] };
31
50
  }
32
51
 
33
- const body = match[2];
34
- const shortDesc = 'Reverse-engineer and clone any website as a pixel-perfect replica';
52
+ function syncSkill(skill) {
53
+ const { id, sourceRel, shortDesc, plainSubstitution, augmentArgumentHint } = skill;
54
+
55
+ let parsed;
56
+ try {
57
+ parsed = parseSkill(sourceRel);
58
+ } catch (e) {
59
+ console.error(e.message || e);
60
+ process.exit(1);
61
+ }
62
+
63
+ const { raw, body } = parsed;
64
+ const noArgs = (text) => text.replace(/\$ARGUMENTS/g, plainSubstitution);
65
+ const header =
66
+ `<!-- AUTO-GENERATED from ${sourceRel} \u2014 do not edit directly.\n` +
67
+ ` Run \`node scripts/sync-skills.mjs\` to regenerate. -->\n\n`;
68
+
69
+ console.log(`\nSyncing ${id}...\n Source: ${sourceRel}\n`);
70
+
71
+ write(`.codex/skills/${id}/SKILL.md`, raw);
72
+ write(`.github/skills/${id}/SKILL.md`, raw);
73
+
74
+ write(`.cursor/commands/${id}.md`, header + noArgs(body));
75
+
76
+ write(`.windsurf/workflows/${id}.md`, header + noArgs(body));
77
+
78
+ const geminiBody = body.replace(/\$ARGUMENTS/g, "{{args}}");
79
+ write(
80
+ `.gemini/commands/${id}.toml`,
81
+ `# AUTO-GENERATED from ${sourceRel}\n` +
82
+ `# Run \`node scripts/sync-skills.mjs\` to regenerate.\n\n` +
83
+ `description = ${JSON.stringify(shortDesc)}\n\n` +
84
+ `[prompt]\ntext = '''\n${geminiBody}\n'''\n`,
85
+ );
86
+
87
+ write(
88
+ `.opencode/commands/${id}.md`,
89
+ `---\ndescription: ${JSON.stringify(shortDesc)}\n---\n${header}${body}`,
90
+ );
91
+
92
+ write(
93
+ `.augment/commands/${id}.md`,
94
+ `---\ndescription: ${JSON.stringify(shortDesc)}\nargument-hint: ${JSON.stringify(augmentArgumentHint)}\n---\n${header}${body}`,
95
+ );
96
+
97
+ write(
98
+ `.continue/commands/${id}.md`,
99
+ `---\nname: ${id}\ndescription: ${JSON.stringify(shortDesc)}\ninvokable: true\n---\n${header}${body}`,
100
+ );
101
+
102
+ write(
103
+ `.amazonq/cli-agents/${id}.json`,
104
+ JSON.stringify(
105
+ {
106
+ name: id,
107
+ description: shortDesc,
108
+ prompt: noArgs(body),
109
+ fileContext: ["AGENTS.md", "docs/research/**"],
110
+ },
111
+ null,
112
+ 2,
113
+ ) + "\n",
114
+ );
115
+ }
35
116
 
36
- // --- Helpers ---
117
+ console.log("Syncing skills to all platforms...");
37
118
 
38
- function write(relPath, content) {
39
- const full = join(ROOT, relPath);
40
- mkdirSync(dirname(full), { recursive: true });
41
- writeFileSync(full, content, 'utf8');
42
- console.log(` \u2713 ${relPath}`);
119
+ for (const skill of SKILLS) {
120
+ syncSkill(skill);
43
121
  }
44
122
 
45
- const HEADER =
46
- '<!-- AUTO-GENERATED from .claude/skills/clone-website/SKILL.md \u2014 do not edit directly.\n' +
47
- ' Run `node scripts/sync-skills.mjs` to regenerate. -->\n\n';
48
-
49
- const noArgs = (text) => text.replace(/\$ARGUMENTS/g, 'the target URL provided by the user');
50
-
51
- // --- Generate ---
52
-
53
- console.log('Syncing clone-website skill to all platforms...');
54
- console.log(` Source: .claude/skills/clone-website/SKILL.md\n`);
55
-
56
- // 1. Codex CLI — same SKILL.md format, same $ARGUMENTS syntax
57
- write('.codex/skills/clone-website/SKILL.md', raw);
58
-
59
- // 2. GitHub Copilot — same SKILL.md format
60
- write('.github/skills/clone-website/SKILL.md', raw);
61
-
62
- // 3. Cursor — plain markdown, no argument substitution support
63
- write('.cursor/commands/clone-website.md', HEADER + noArgs(body));
64
-
65
- // 4. Windsurf — markdown workflow
66
- write('.windsurf/workflows/clone-website.md', HEADER + noArgs(body));
67
-
68
- // 5. Gemini CLI — TOML format, {{args}} for arguments
69
- const geminiBody = body.replace(/\$ARGUMENTS/g, '{{args}}');
70
- write(
71
- '.gemini/commands/clone-website.toml',
72
- `# AUTO-GENERATED from .claude/skills/clone-website/SKILL.md\n` +
73
- `# Run \`node scripts/sync-skills.mjs\` to regenerate.\n\n` +
74
- `description = "${shortDesc}"\n\n` +
75
- `[prompt]\ntext = '''\n${geminiBody}\n'''\n`
76
- );
77
-
78
- // 6. OpenCode — markdown + YAML frontmatter, $ARGUMENTS works natively
79
- write(
80
- '.opencode/commands/clone-website.md',
81
- `---\ndescription: "${shortDesc}"\n---\n${HEADER}${body}`
82
- );
83
-
84
- // 7. Augment Code — markdown + YAML frontmatter
85
- write(
86
- '.augment/commands/clone-website.md',
87
- `---\ndescription: "${shortDesc}"\nargument-hint: "<url>"\n---\n${HEADER}${body}`
88
- );
89
-
90
- // 8. Continue — prompt file with invokable: true
91
- write(
92
- '.continue/commands/clone-website.md',
93
- `---\nname: clone-website\ndescription: "${shortDesc}"\ninvokable: true\n---\n${HEADER}${body}`
94
- );
95
-
96
- // 9. Amazon Q — JSON agent definition
97
- write(
98
- '.amazonq/cli-agents/clone-website.json',
99
- JSON.stringify(
100
- {
101
- name: 'clone-website',
102
- description: shortDesc,
103
- prompt: noArgs(body),
104
- fileContext: ['AGENTS.md', 'docs/research/**'],
105
- },
106
- null,
107
- 2
108
- ) + '\n'
109
- );
110
-
111
- console.log('\nDone! 9 platform command files generated from source skill.');
123
+ const totalFiles = SKILLS.length * 9;
124
+ console.log(`\nDone! ${totalFiles} platform files generated (${SKILLS.length} skills \u00d7 9 targets).`);