diff --git a/.agents/product-marketing.md b/.agents/product-marketing.md index 1beee80..6202a57 100644 --- a/.agents/product-marketing.md +++ b/.agents/product-marketing.md @@ -1,12 +1,12 @@ # Product Marketing Context -*Last updated: 2026-05-15* +*Last updated: 2026-06-03* ## Product Overview **One-liner:** QuickFork turns a GitHub repository into a launch-ready story and shareable marketing asset package. -**What it does:** QuickFork accepts a GitHub repository URL, extracts repository and README evidence, builds a curated project brief, generates aligned launch copy, and produces prompt/image/quality artifacts for README pages, slide decks, and social distribution. The product emphasizes traceability: generated claims, metrics, identity assets, and visual prompts should come from repository evidence or explicit user input. +**What it does:** QuickFork accepts a GitHub repository URL, extracts repository and README evidence, builds a curated project brief, maps launch materials across README/social/deck/visual/outreach channels, generates aligned launch copy, and produces prompt/image/quality artifacts for README pages, slide decks, and social distribution. The product emphasizes traceability: generated claims, metrics, identity assets, channel mappings, and visual prompts should come from repository evidence or explicit user input. **Product category:** GitHub-to-launch asset generator; developer marketing automation; open-source launch storytelling tool. @@ -25,12 +25,14 @@ **Jobs to be done:** - Turn a repository into a clear public-facing project story. - Produce launch visuals and copy for README, PPT, X/LinkedIn, and social posts. +- Map each launch material to the target user, source evidence, review question, and success signal before publishing. - Preserve evidence, identity assets, metrics, and locale alignment so generated marketing can be reviewed before publishing. **Use cases:** - Launch a GitHub project with README cover imagery and concise positioning. - Prepare multilingual launch copy in English, Chinese, and Japanese. - Generate a marketing-card prompt and visual output with source-backed identity rules. +- Create a launch materials map for README, social, deck, visual, and outreach channels from one repository brief. - Create project showcase pages from successful generations. - Build reusable proof and case-study content from generated launch packages. @@ -117,7 +119,7 @@ - "Repo URL in, shareable project assets out." - "A traceable marketing-card workflow for open-source projects." -**Words to use:** GitHub repository, launch-ready story, source-backed, traceable, curated brief, README cover, launch package, marketing card, localized copy, artifact manifest, quality report, official logo, GitHub avatar. +**Words to use:** GitHub repository, launch-ready story, source-backed, traceable, curated brief, launch materials map, README cover, launch package, marketing card, localized copy, artifact manifest, quality report, official logo, GitHub avatar. **Words to avoid:** Magic, fake proof, random logo, one-click publish, guaranteed rankings, autonomous launch, invented metrics. @@ -126,6 +128,7 @@ | Term | Meaning | | --- | --- | | Launch package | The combined brief, copy, prompt, image, QA, and manifest artifacts created from a repo | +| Launch materials map | A channel plan that assigns README, social, deck, visual, and outreach materials to target users, source evidence, review questions, and success signals | | Curated brief | A compact source-backed summary used as the factual base for generated assets | | Marketing card | A visual project explainer suitable for README, PPT, and social distribution | | Identity asset | Official project logo, README asset, homepage asset, or GitHub avatar used to represent the project | @@ -155,6 +158,7 @@ | Theme | Proof | | --- | --- | | Repo-to-story speed | Current app accepts GitHub URL and runs `/api/generations` to produce launch artifacts | +| Channel planning | The generated launch brief includes a source-backed launch materials map for README, social, deck, visual, and outreach outputs | | Traceability | Workflow stores brief, prompt, image, quality report, and manifest paths | | Brand safety | Identity rules prefer official assets or GitHub avatar and forbid random generated logos | | Multilingual readiness | Current workflow supports English, Chinese, and Japanese output slots | diff --git a/docs/marketing/data/semantic-link-inventory.csv b/docs/marketing/data/semantic-link-inventory.csv index 6488fbd..459c73a 100644 --- a/docs/marketing/data/semantic-link-inventory.csv +++ b/docs/marketing/data/semantic-link-inventory.csv @@ -2,6 +2,7 @@ status,funnel_stage,buyer_stage,persona,intent_cluster,page_type,slug,canonical_ published,top,consideration,open_source_maintainer,github_repo_to_launch_package,product,github-repo-to-launch-package,https://seekersai.com/product/github-repo-to-launch-package,github repo to launch package,generate_launch_card,google,organic,seo_foundation,product_category,2026_q2_seo_foundation,https://seekersai.com/product/github-repo-to-launch-package?utm_source=google&utm_medium=organic&utm_campaign=seo_foundation&utm_content=product_category published,top,consideration,product_marketer,source_backed_launch_assets,product,source-backed-launch-assets,https://seekersai.com/product/source-backed-launch-assets,source backed launch assets,generate_launch_card,perplexity,ai_search,ai_visibility,source_backed_assets,2026_q2_ai_visibility,https://seekersai.com/product/source-backed-launch-assets?utm_source=perplexity&utm_medium=ai_search&utm_campaign=ai_visibility&utm_content=source_backed_assets published,top,consideration,ai_project_builder,cold_start_launch_materials,product,cold-start-launch-materials,https://seekersai.com/product/cold-start-launch-materials,cold start launch materials,generate_launch_card,google,organic,cold_start_materials,product_page,2026_q2_cold_start_materials,https://seekersai.com/product/cold-start-launch-materials?utm_source=google&utm_medium=organic&utm_campaign=cold_start_materials&utm_content=product_page +published,top,consideration,ai_project_builder,github_repo_launch_materials_map,product,github-repo-launch-materials-map,https://seekersai.com/product/github-repo-launch-materials-map,github repo launch materials map,generate_launch_card,google,organic,launch_materials_map,product_page,2026_q2_launch_materials_map,https://seekersai.com/product/github-repo-launch-materials-map?utm_source=google&utm_medium=organic&utm_campaign=launch_materials_map&utm_content=product_page published,top,consideration,design_lead,readme_marketing_cards,product,readme-marketing-cards,https://seekersai.com/product/readme-marketing-cards,readme marketing cards,generate_launch_card,google,organic,readme_assets,product_page,2026_q2_readme_assets,https://seekersai.com/product/readme-marketing-cards?utm_source=google&utm_medium=organic&utm_campaign=readme_assets&utm_content=product_page published,top,consideration,ai_project_builder,github_repo_visual_explainer,product,github-repo-visual-explainer,https://seekersai.com/product/github-repo-visual-explainer,github repo visual explainer,generate_launch_card,google,organic,visual_explainer,product_page,2026_q2_visual_explainer,https://seekersai.com/product/github-repo-visual-explainer?utm_source=google&utm_medium=organic&utm_campaign=visual_explainer&utm_content=product_page published,top,consideration,founder,github_repo_to_launch_deck,product,github-repo-to-launch-deck,https://seekersai.com/product/github-repo-to-launch-deck,github repository pitch deck generator,generate_launch_card,google,organic,launch_deck,product_page,2026_q2_launch_deck,https://seekersai.com/product/github-repo-to-launch-deck?utm_source=google&utm_medium=organic&utm_campaign=launch_deck&utm_content=product_page diff --git a/docs/marketing/research/2026-06-03-launch-materials-map.md b/docs/marketing/research/2026-06-03-launch-materials-map.md new file mode 100644 index 0000000..7882102 --- /dev/null +++ b/docs/marketing/research/2026-06-03-launch-materials-map.md @@ -0,0 +1,80 @@ +# 2026-06-03 Launch Materials Map Research Note + +## Summary + +The launch materials map packages QuickFork's repo-to-launch output into a channel plan: README, social, deck, visual, and outreach. It turns the free launch brief from "generated assets" into a reviewable product workflow with target user, job, artifact, source evidence, review question, and success signal per channel. + +This is a product activation hypothesis, not validated market demand. + +## Why This Slice Matters + +- QuickFork already generates multiple launch artifacts from one repository URL. +- Builders need help deciding which artifact belongs on which channel before public publishing. +- A map makes the product easier to explain in landing pages, AI-search answers, and sales conversations. +- A map creates a paid-packaging wedge: the free product can show the plan, while a paid package can offer reviewed execution across the same channels. + +## Target User Hypotheses + +- AI project builder: needs a launch story without writing a blank marketing prompt. +- Open-source maintainer: needs README and social assets that remain tied to repository evidence. +- DevRel operator: needs channel-specific launch material for docs, social, and community posts. +- Technical founder: needs a deck and outreach narrative before requesting a fuller launch package. +- Product marketer: needs traceable claims and a reusable artifact map for cross-channel review. + +## Product Lifecycle Position + +- Discovery: public landing route explains the problem and source-backed workflow. +- Activation: generated brief now includes a launch materials map and copy event. +- Validation: compare page and artifact behavior against existing repo-to-launch routes. +- Monetization: only after evidence shows repeated full-package interest should QuickFork package reviewed channel execution as a paid product. + +## Growth Contract + +Primary activation metric: + +- `launch_materials_map_copied` after a successful free repo launch brief. + +Supporting metrics: + +- `page_view` for `/product/github-repo-launch-materials-map`. +- CTA clicks with `intent_cluster=github_repo_launch_materials_map`. +- Repo URL submissions from the route. +- Generation completions and failures. +- Artifact copy/download events by type. +- Full launch package requests after materials-map exposure. + +Guardrails: + +- Do not claim search placement, financial outcomes, adoption, Product Hunt outcomes, exact pricing, or automatic publishing. +- Do not send raw README text, artifact bodies, source notes, secrets, tokens, or email to browser analytics. +- Keep every launch material tied to repository evidence, official assets, generated reports, or explicit user input. + +## Source-Backed Inputs + +- GitHub README docs define README as the repository explanation surface: https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes +- GitHub social preview docs make repository preview visuals part of launch packaging: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/customizing-your-repositorys-social-media-preview?apiVersion=2022-11-28 +- Open Source Guides finding users connects audience discovery and feedback loops to open-source launches: https://opensource.guide/finding-users/ +- Product Hunt launch guidance frames story, media, maker context, and launch-day copy as review surfaces: https://www.producthunt.com/launch/preparing-for-launch + +## Implemented Surface + +- `RepoLaunchBrief.launchMaterialsMap` +- `RepoLaunchBrief.artifacts[]` item with type `materials_map` +- Landing result section labeled `Launch materials map` +- Copy tracking event `launch_materials_map_copied` +- Product route `/product/github-repo-launch-materials-map` +- Public discovery assets in `sitemap.xml` and `llms.txt` + +## Current Verification + +- Baseline `npm test`: 24 files passed, 158 tests passed before implementation. +- Focused generation verification passed. +- Focused hero generator verification passed. +- Focused route, semantic link, and public growth verification passed. +- Full verification passed: `npm test` returned 24 files passed and 160 tests passed. +- Build verification passed: `npm run build` completed TypeScript build and Vite production build. +- Diff hygiene passed: `git diff --check` returned no whitespace errors. + +## Next Validation Step + +Run a 14-day comparison against `/product/github-repo-to-launch-package` and `/product/cold-start-launch-materials`. Prioritize this slice only if visitors who see or copy the map show stronger generation completion, artifact export, or full-package request behavior. diff --git a/docs/plans/2026-06-01-quickfork-growth-lifecycle-prioritization.md b/docs/plans/2026-06-01-quickfork-growth-lifecycle-prioritization.md index 2d939a4..474021d 100644 --- a/docs/plans/2026-06-01-quickfork-growth-lifecycle-prioritization.md +++ b/docs/plans/2026-06-01-quickfork-growth-lifecycle-prioritization.md @@ -1518,3 +1518,67 @@ Decision: Next action: - Run the manual baseline using the four prompt rows, then fill evidence rows only after real Search Console exports and AI-answer observations exist. + +## 2026-06-03 Launch Materials Map Product Activation Slice + +Hypothesis: + +- If QuickFork adds a source-backed launch materials map to the generated brief and gives the same intent a crawlable product route, AI project builders can understand which launch material belongs on README, social, deck, visual, and outreach channels before requesting a full package. + +Lifecycle stage: + +- Activation and Validation. + +Target user: + +- AI project builders preparing a cold-start repository launch. +- Open-source maintainers who need source-backed README, social, and visual materials. +- DevRel operators and product marketers who need traceable channel assets. +- Technical founders evaluating whether a reviewed launch package is worth requesting. + +Changed surface: + +- `src/server/generation/types.ts` +- `src/server/generation/launch-brief.ts` +- `src/components/landing/HeroSection.tsx` +- `src/lib/analytics.ts` +- `src/styles/app.css` +- `src/marketing/link-catalog.ts` +- `src/marketing/page-content.ts` +- `public/sitemap.xml` +- `public/llms.txt` +- `docs/marketing/data/semantic-link-inventory.csv` +- `docs/superpowers/plans/2026-06-03-launch-materials-map.md` +- `docs/marketing/research/2026-06-03-launch-materials-map.md` + +Metric: + +- Primary: `launch_materials_map_copied`. +- Supporting: page views, CTA clicks, repo submissions, generation completions, artifact copy/download events, and full launch package requests by `intent_cluster=github_repo_launch_materials_map`. + +Guardrail: + +- Do not claim search placement, financial outcomes, adoption, Product Hunt outcomes, exact pricing, automatic publishing, or willingness to pay. +- Do not send raw README text, artifact bodies, source notes, secrets, tokens, email, or private launch notes to browser analytics. + +Evidence observed: + +- Baseline `npm test` passed before changes: 24 test files, 158 tests passed. +- RED generation test failed first because the launch brief did not include `launchMaterialsMap` or a `materials_map` artifact. +- GREEN focused generation verification passed: `npm test -- src/server/generation/generation.test.ts -t "source-backed free repo launch brief"`. +- GREEN focused UI verification passed: `npm test -- src/App.test.tsx -t "Hero generator"`. +- RED route tests failed first because `/product/github-repo-launch-materials-map` was not in the marketing catalog, sitemap, or `llms.txt`. +- GREEN route verification passed: `npm test -- src/App.test.tsx -t "launch materials map"`. +- GREEN semantic-link verification passed: `npm test -- src/seo/semantic-links.test.ts -t "launch materials map|canonical page paths"`. +- GREEN public-growth verification passed: `npm test -- src/seo/public-growth.test.ts -t "sitemap|machine-readable AI context"`. +- Full verification passed: `npm test` returned 24 files passed and 160 tests passed. +- Build verification passed: `npm run build` completed TypeScript build and Vite production build. +- Diff hygiene passed: `git diff --check` returned no whitespace errors. + +Decision: + +- Treat this as a product activation and validation slice, not validated demand. The materials map is ready for production smoke, Search Console review, AI-answer checks, and artifact-behavior comparison. + +Next action: + +- Run full verification, merge, production smoke, then compare `/product/github-repo-launch-materials-map` behavior against `/product/github-repo-to-launch-package` and `/product/cold-start-launch-materials` over a 14-day window. diff --git a/docs/superpowers/plans/2026-06-03-launch-materials-map.md b/docs/superpowers/plans/2026-06-03-launch-materials-map.md new file mode 100644 index 0000000..5643b48 --- /dev/null +++ b/docs/superpowers/plans/2026-06-03-launch-materials-map.md @@ -0,0 +1,57 @@ +# 2026-06-03 Launch Materials Map + +## Objective + +Turn QuickFork's free repo launch brief into a clearer product activation surface by adding a source-backed launch materials map. The map explains which generated material belongs on README, social, deck, visual, and outreach channels, who it is for, what source evidence supports it, what a human should review, and what activation signal QuickFork should measure next. + +## Skills And Rules + +- Use `superpowers:*` skills when the task matches their trigger rules. +- Keep the growth loop source-backed: repository evidence, official project assets, README content, public metadata, generated reports, and explicit user input. +- Keep analytics payloads behavioral and aggregate. Do not send raw README text, artifact bodies, secrets, tokens, email, or private launch notes. +- Use the Obsidian growth note to record the hypothesis, validation evidence, and next lifecycle decision after implementation. + +## Product Hypothesis + +If QuickFork makes the launch materials map first-class inside the generated brief and gives the same intent a crawlable product page, AI project builders can understand the value faster and QuickFork can measure whether artifact planning creates stronger activation than isolated copy/download events. + +## Target Users + +- AI project builders preparing a cold-start GitHub launch. +- Open-source maintainers who need a reviewable README, social, and visual package. +- DevRel operators and product marketers who need traceable channel assets. +- Technical founders evaluating whether a paid launch package is worth requesting. + +## Implementation Plan + +1. Add a typed `launchMaterialsMap` to `RepoLaunchBrief`. +2. Generate five channel mappings: README, social, deck, visual, and outreach. +3. Add a `materials_map` artifact to the export manifest. +4. Render the map in the landing generator result and support copy tracking with `launch_materials_map_copied`. +5. Add `/product/github-repo-launch-materials-map` to the semantic link catalog, page narrative, sitemap, `llms.txt`, and CSV inventory. +6. Record the growth hypothesis and lifecycle plan in repo docs and Obsidian. + +## Source Notes + +- GitHub README docs: https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes +- GitHub social preview docs: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/customizing-your-repositorys-social-media-preview?apiVersion=2022-11-28 +- Open Source Guides finding users: https://opensource.guide/finding-users/ +- Product Hunt launch guide: https://www.producthunt.com/launch/preparing-for-launch + +## Verification Notes + +- Baseline `npm test` passed before implementation: 24 test files, 158 tests. +- RED generation test failed before `launchMaterialsMap` existed. +- GREEN generation focused test passed: `npm test -- src/server/generation/generation.test.ts -t "source-backed free repo launch brief"`. +- GREEN UI focused test passed: `npm test -- src/App.test.tsx -t "Hero generator"`. +- RED route tests failed before `/product/github-repo-launch-materials-map` was added to the catalog and public assets. +- GREEN route focused test passed: `npm test -- src/App.test.tsx -t "launch materials map"`. +- GREEN semantic-link focused test passed: `npm test -- src/seo/semantic-links.test.ts -t "launch materials map|canonical page paths"`. +- GREEN public-growth focused test passed: `npm test -- src/seo/public-growth.test.ts -t "sitemap|machine-readable AI context"`. +- Full verification passed: `npm test` returned 24 files passed and 160 tests passed. +- Build verification passed: `npm run build` completed TypeScript build and Vite production build. +- Diff hygiene passed: `git diff --check` returned no whitespace errors. + +## Lifecycle Decision + +Treat this as an Activation plus Validation slice, not proof of demand. The next decision should use page views, CTA clicks, repo submissions, generation completions, materials-map copy events, artifact exports, and full-package requests before expanding or pricing the capability. diff --git a/public/llms.txt b/public/llms.txt index 2bff008..6c281ed 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -32,6 +32,7 @@ QuickFork should use repository evidence, official project assets, README conten - GitHub Repo To Launch Package | QuickFork: https://seekersai.com/product/github-repo-to-launch-package - Product, Consideration. QuickFork maps github repo to launch package demand into source-backed README, social, deck, outreach, and visual explainer assets for cold-start technical launches. - Source Backed Launch Assets | QuickFork: https://seekersai.com/product/source-backed-launch-assets - Product, Consideration. QuickFork maps source backed launch assets demand into reviewable README, social, deck, outreach, and visual materials generated from repository evidence, source maps, and human-approved claims. - Cold Start Launch Materials | QuickFork: https://seekersai.com/product/cold-start-launch-materials - Product, Consideration. QuickFork maps cold start launch materials demand into source-backed README, social, deck, visual, and outreach drafts generated from one public GitHub repository URL. +- GitHub Repo Launch Materials Map | QuickFork: https://seekersai.com/product/github-repo-launch-materials-map - Product, Consideration. QuickFork maps github repo launch materials map demand into a source-backed channel plan for README, social, deck, visual, and outreach assets from one repository URL. - README Marketing Cards | QuickFork: https://seekersai.com/product/readme-marketing-cards - Product, Consideration. QuickFork maps readme marketing cards demand into README-first hero cards, GitHub social preview direction, and launch visuals grounded in repository evidence and human review. - GitHub Repo Visual Explainer | QuickFork: https://seekersai.com/product/github-repo-visual-explainer - Product, Consideration. QuickFork maps github repo visual explainer demand into source-backed story maps, README hero cards, GitHub social previews, and deck-ready visual launch assets for technical repositories. - GitHub Repository Pitch Deck Generator | QuickFork: https://seekersai.com/product/github-repo-to-launch-deck - Product, Consideration. QuickFork maps github repository pitch deck generator demand into a deck-ready launch brief, slide outline, Product Hunt story, and outreach narrative from repository evidence. diff --git a/public/sitemap.xml b/public/sitemap.xml index 6012526..86fd21c 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -24,6 +24,12 @@ monthly 0.8 + + https://seekersai.com/product/github-repo-launch-materials-map + 2026-06-02 + monthly + 0.8 + https://seekersai.com/product/readme-marketing-cards 2026-06-02 diff --git a/src/App.test.tsx b/src/App.test.tsx index 5b148f5..20d433f 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -354,6 +354,56 @@ describe("App", () => { expect(JSON.stringify(window.dataLayer)).not.toMatch(/email|token|secret|api_key|raw|readme/i); }, 10000); + it("renders the GitHub repo launch materials map as a product activation route", () => { + window.dataLayer = []; + window.history.replaceState({}, "", "/product/github-repo-launch-materials-map?utm_source=google"); + + render(); + + expect(screen.getByRole("heading", { name: /GitHub Repo Launch Materials Map/i })).toBeInTheDocument(); + expect(screen.getAllByText(/channel plan for README, social, deck, visual, and outreach/i).length).toBeGreaterThan(0); + expect(screen.getAllByText(/target user, artifact, source evidence, review question, and success signal/i).length).toBeGreaterThan(0); + expect(screen.getByText(/Map every material to a job/i)).toBeInTheDocument(); + expect(screen.getByText(/Measure activation by artifact behavior/i)).toBeInTheDocument(); + expect(screen.getByText(/What is a GitHub repo launch materials map/i)).toBeInTheDocument(); + expect(screen.getByRole("link", { name: /GitHub Docs About READMEs/i })).toHaveAttribute( + "href", + "https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes", + ); + expect(screen.getByRole("link", { name: /Product Hunt launch guide/i })).toHaveAttribute( + "href", + "https://www.producthunt.com/launch/preparing-for-launch", + ); + expect(screen.getByText("Last updated: June 3, 2026")).toBeInTheDocument(); + const primaryCta = screen + .getAllByRole("link", { name: /generate free repo brief/i }) + .find((link) => link.classList.contains("primaryButton")); + expect(primaryCta).toHaveAttribute("href", "/#hero"); + expect(document.title).toBe("GitHub Repo Launch Materials Map | QuickFork"); + expect(document.querySelector('meta[name="description"]')).toHaveAttribute( + "content", + "QuickFork maps github repo launch materials map demand into a source-backed channel plan for README, social, deck, visual, and outreach assets from one repository URL.", + ); + expect(document.querySelector('link[rel="canonical"]')).toHaveAttribute( + "href", + "https://seekersai.com/product/github-repo-launch-materials-map", + ); + expect(window.dataLayer).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + event: "page_view", + page_path: "/product/github-repo-launch-materials-map", + page_type: "product", + buyer_stage: "consideration", + intent_cluster: "github_repo_launch_materials_map", + utm_source: "google", + }), + ]), + ); + expect(document.body.textContent).not.toMatch(/\b(guaranteed|rankings|revenue|customers|viral|autonomous)\b/i); + expect(JSON.stringify(window.dataLayer)).not.toMatch(/email|token|secret|api_key|raw|readme/i); + }, 10000); + it("renders source-backed launch assets as a high-intent product route", () => { window.dataLayer = []; window.history.replaceState({}, "", "/product/source-backed-launch-assets?utm_source=perplexity"); @@ -1178,6 +1228,34 @@ describe("App", () => { }, ], }, + launchMaterialsMap: { + title: "QwenLM/FlashQLA launch materials map", + summary: "Channel plan for README, social, deck, visual, and outreach launch materials.", + channels: [ + { + type: "readme", + label: "README launch section", + primaryUser: "Open-source adopters", + jobToBeDone: "Understand FlashQLA before reading implementation details.", + artifactLabel: "README launch brief", + channelFit: "GitHub visitors need source-backed context above the fold.", + source: "README or repo metadata includes: Optimizes attention kernels for lower latency inference.", + reviewQuestion: "Which source-backed claim belongs in the README hero?", + successSignal: "README artifact copied or downloaded.", + }, + { + type: "visual", + label: "Visual project explainer", + primaryUser: "AI project builders", + jobToBeDone: "Understand the workflow without parsing the full README.", + artifactLabel: "Visual explainer prompt", + channelFit: "README, social preview, and deck channels need one consistent visual metaphor.", + source: "Audience hypothesis from repo metadata and topics.", + reviewQuestion: "Does the visual direction preserve identity assets and avoid fake logos?", + successSignal: "Visual prompt copied or image preview opened.", + }, + ], + }, readmeChecklist: [ { item: "Lead with a one-sentence README value proposition.", @@ -1224,6 +1302,13 @@ describe("App", () => { body: "## Project story map\n\nSource-backed visual interpretation.", sourceReferences: ["README or repo metadata includes: Optimizes attention kernels."], }, + { + type: "materials_map", + label: "Launch materials map", + fileName: "qwenlm-flashqla-launch-materials-map.md", + body: "## Launch materials map\n\nREADME and visual channel plan.", + sourceReferences: ["README or repo metadata includes: Optimizes attention kernels."], + }, { type: "readme", label: "README launch brief", @@ -1293,10 +1378,17 @@ describe("App", () => { expect(within(storyMapRegion).getByText(/Project story map/i)).toBeInTheDocument(); expect(within(storyMapRegion).getByText(/Source-backed visual interpretation/i)).toBeInTheDocument(); expect(within(storyMapRegion).getByText(/Install to benchmark/i)).toBeInTheDocument(); + const materialsMapRegion = within(briefRegion).getByRole("region", { name: /launch materials map/i }); + expect(within(materialsMapRegion).getByText(/^Launch materials map$/i)).toBeInTheDocument(); + expect(within(materialsMapRegion).getByText(/Channel plan for README, social, deck, visual, and outreach/i)).toBeInTheDocument(); + expect(within(materialsMapRegion).getByText(/README launch section/i)).toBeInTheDocument(); + expect(within(materialsMapRegion).getByText(/Which source-backed claim belongs in the README hero/i)).toBeInTheDocument(); + expect(within(materialsMapRegion).getByText(/Visual project explainer/i)).toBeInTheDocument(); expect(within(briefRegion).getByText(/Lead with a one-sentence README value proposition/i)).toBeInTheDocument(); expect(within(briefRegion).getByText(/Launch angle 1/i)).toBeInTheDocument(); expect(within(briefRegion).getByText(/Create a ai_kernel_infra visual explainer/i)).toBeInTheDocument(); expect(within(briefRegion).getByText(/Export artifacts/i)).toBeInTheDocument(); + expect(within(materialsMapRegion).getByRole("button", { name: /copy launch materials map/i })).toBeInTheDocument(); expect(within(briefRegion).getByRole("button", { name: /copy README launch brief/i })).toBeInTheDocument(); expect(within(briefRegion).getByRole("link", { name: /download README launch brief/i })).toHaveAttribute( "download", @@ -1335,11 +1427,11 @@ describe("App", () => { has_image_url: true, }), expect.objectContaining({ - event: "launch_brief_viewed", - repo_full_name: "QwenLM/FlashQLA", - generation_id: "gen_qwenlm_flashqla_test", - brief_sections: 8, - }), + event: "launch_brief_viewed", + repo_full_name: "QwenLM/FlashQLA", + generation_id: "gen_qwenlm_flashqla_test", + brief_sections: 9, + }), ]), ); @@ -1353,6 +1445,8 @@ describe("App", () => { expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.stringContaining("Target user discovery")); fireEvent.click(within(briefRegion).getByRole("button", { name: /copy story map/i })); expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.stringContaining("Project story map")); + fireEvent.click(within(materialsMapRegion).getByRole("button", { name: /copy launch materials map/i })); + expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.stringContaining("Launch materials map")); fireEvent.click(within(briefRegion).getByRole("button", { name: /copy README launch brief/i })); expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expect.stringContaining("README checklist")); fireEvent.click(within(briefRegion).getByRole("link", { name: /download README launch brief/i })); @@ -1381,6 +1475,14 @@ describe("App", () => { node_count: 3, source_reference_count: 1, }), + expect.objectContaining({ + event: "launch_materials_map_copied", + repo_full_name: "QwenLM/FlashQLA", + generation_id: "gen_qwenlm_flashqla_test", + channel_count: 2, + artifact_type_count: 2, + source_reference_count: 1, + }), expect.objectContaining({ event: "launch_artifact_copied", repo_full_name: "QwenLM/FlashQLA", @@ -1404,13 +1506,14 @@ describe("App", () => { cta_id: "request_full_launch_package", cta_location: "launch_brief_panel", lifecycle_stage: "monetization", - artifact_count: 4, + artifact_count: 5, }), ]), ), ); expect(JSON.stringify(window.dataLayer)).not.toContain("README checklist"); expect(JSON.stringify(window.dataLayer)).not.toContain("Which repository evidence"); + expect(JSON.stringify(window.dataLayer)).not.toContain("Which source-backed claim belongs in the README hero"); fireEvent.click(previewImage); const previewDialog = await screen.findByRole("dialog", { name: /generated image preview/i }); diff --git a/src/components/landing/HeroSection.tsx b/src/components/landing/HeroSection.tsx index 5333804..905d33b 100644 --- a/src/components/landing/HeroSection.tsx +++ b/src/components/landing/HeroSection.tsx @@ -86,6 +86,7 @@ interface RepoLaunchBriefSummary { audienceHypothesis: string; audienceDiscovery?: RepoLaunchAudienceDiscoverySummary; storyMap?: RepoLaunchStoryMapSummary; + launchMaterialsMap?: RepoLaunchMaterialsMapSummary; readmeChecklist: Array<{ item: string; source: string; @@ -134,8 +135,26 @@ interface RepoLaunchStoryMapNodeSummary { source: string; } +interface RepoLaunchMaterialsMapSummary { + title: string; + summary: string; + channels: RepoLaunchMaterialChannelSummary[]; +} + +interface RepoLaunchMaterialChannelSummary { + type: "readme" | "social" | "deck" | "visual" | "outreach"; + label: string; + primaryUser: string; + jobToBeDone: string; + artifactLabel: string; + channelFit: string; + source: string; + reviewQuestion: string; + successSignal: string; +} + interface RepoLaunchBriefArtifactSummary { - type: "audience" | "story_map" | "readme" | "social" | "deck" | "outreach" | "visual"; + type: "audience" | "story_map" | "materials_map" | "readme" | "social" | "deck" | "outreach" | "visual"; label: string; fileName: string; body: string; @@ -472,6 +491,19 @@ function LaunchBriefPanel({ }); }; + const handleCopyMaterialsMap = async () => { + if (!brief.launchMaterialsMap) return; + await navigator.clipboard?.writeText(serializeLaunchMaterialsMap(brief.launchMaterialsMap)); + setCopyStatus("Copied launch materials map"); + trackEvent("launch_materials_map_copied", { + ...getRepoAnalyticsProperties(repoUrl), + generation_id: generationId, + channel_count: brief.launchMaterialsMap.channels.length, + artifact_type_count: getLaunchMaterialArtifactTypeCount(brief.launchMaterialsMap), + source_reference_count: brief.sourceReferences.length, + }); + }; + const handleCopyArtifact = async (artifact: RepoLaunchBriefArtifactSummary) => { await navigator.clipboard?.writeText(artifact.body); setCopyStatus(`Copied ${artifact.label}`); @@ -591,6 +623,55 @@ function LaunchBriefPanel({ ) : null} + {brief.launchMaterialsMap ? ( +
+
+
+ Launch materials map + {brief.launchMaterialsMap.summary} +
+ +
+
    + {brief.launchMaterialsMap.channels.map((channel) => ( +
  • + {channel.type} + {channel.label} +
    +
    +
    User
    +
    {channel.primaryUser}
    +
    +
    +
    Job
    +
    {channel.jobToBeDone}
    +
    +
    +
    Artifact
    +
    {channel.artifactLabel}
    +
    +
    +
    Fit
    +
    {channel.channelFit}
    +
    +
    +
    Review
    +
    {channel.reviewQuestion}
    +
    +
    +
    Signal
    +
    {channel.successSignal}
    +
    +
    + {channel.source} +
  • + ))} +
+
+ ) : null} {brief.artifacts?.length ? (
@@ -681,7 +762,7 @@ function LaunchBriefPanel({ } function getLaunchBriefSectionCount(brief: RepoLaunchBriefSummary) { - return 6 + (brief.audienceDiscovery ? 1 : 0) + (brief.storyMap ? 1 : 0); + return 6 + (brief.audienceDiscovery ? 1 : 0) + (brief.storyMap ? 1 : 0) + (brief.launchMaterialsMap ? 1 : 0); } function getArtifactDownloadHref(artifact: RepoLaunchBriefArtifactSummary) { @@ -708,6 +789,7 @@ function serializeLaunchBrief(brief: RepoLaunchBriefSummary, repoFullName: strin "", ...(brief.audienceDiscovery ? [serializeAudienceDiscovery(brief.audienceDiscovery), ""] : []), ...(brief.storyMap ? [serializeStoryMap(brief.storyMap), ""] : []), + ...(brief.launchMaterialsMap ? [serializeLaunchMaterialsMap(brief.launchMaterialsMap), ""] : []), "README checklist:", ...brief.readmeChecklist.map((item) => `- ${item.item} (${item.source})`), "", @@ -761,10 +843,36 @@ function serializeStoryMap(storyMap: RepoLaunchStoryMapSummary) { ].join("\n"); } +function serializeLaunchMaterialsMap(launchMaterialsMap: RepoLaunchMaterialsMapSummary) { + return [ + `Launch materials map: ${launchMaterialsMap.title}`, + "", + launchMaterialsMap.summary, + "", + ...launchMaterialsMap.channels.map((channel, index) => + [ + `${index + 1}. ${channel.label}`, + ` Channel: ${channel.type}`, + ` Primary user: ${channel.primaryUser}`, + ` Job to be done: ${channel.jobToBeDone}`, + ` Artifact: ${channel.artifactLabel}`, + ` Channel fit: ${channel.channelFit}`, + ` Review question: ${channel.reviewQuestion}`, + ` Success signal: ${channel.successSignal}`, + ` Source: ${channel.source}`, + ].join("\n"), + ), + ].join("\n"); +} + function getAudienceChannelCount(audienceDiscovery: RepoLaunchAudienceDiscoverySummary) { return new Set(audienceDiscovery.signals.map((signal) => signal.whereToFind)).size; } +function getLaunchMaterialArtifactTypeCount(launchMaterialsMap: RepoLaunchMaterialsMapSummary) { + return new Set(launchMaterialsMap.channels.map((channel) => channel.type)).size; +} + function ProductAnimationPanel() { const videoRef = useRef(null); diff --git a/src/lib/analytics.ts b/src/lib/analytics.ts index 2a5afb6..a475092 100644 --- a/src/lib/analytics.ts +++ b/src/lib/analytics.ts @@ -17,6 +17,7 @@ export type AnalyticsEventName = | "launch_brief_copied" | "launch_audience_map_copied" | "launch_story_map_copied" + | "launch_materials_map_copied" | "launch_artifact_copied" | "launch_artifact_downloaded" | "generated_image_preview_opened" diff --git a/src/marketing/link-catalog.ts b/src/marketing/link-catalog.ts index 5043154..f92f25a 100644 --- a/src/marketing/link-catalog.ts +++ b/src/marketing/link-catalog.ts @@ -120,6 +120,25 @@ export const marketingLinks: readonly MarketingLink[] = [ content: "product_page", }, }, + { + status: "published", + funnelStage: "top", + buyerStage: "consideration", + persona: "ai_project_builder", + intentCluster: "github_repo_launch_materials_map", + pageType: "product", + slug: "github-repo-launch-materials-map", + canonicalUrl: "https://seekersai.com/product/github-repo-launch-materials-map", + primaryKeyword: "github repo launch materials map", + primaryCta: "generate_launch_card", + crmCampaign: "2026_q2_launch_materials_map", + utm: { + source: "google", + medium: "organic", + campaign: "launch_materials_map", + content: "product_page", + }, + }, { status: "published", funnelStage: "top", diff --git a/src/marketing/page-content.ts b/src/marketing/page-content.ts index 7cf4527..3a3b8e1 100644 --- a/src/marketing/page-content.ts +++ b/src/marketing/page-content.ts @@ -330,6 +330,97 @@ const pageNarratives: Partial> = { ], lastUpdated: "June 2, 2026", }, + github_repo_launch_materials_map: { + definition: + "A GitHub repo launch materials map is a source-backed channel plan that maps one repository URL into README, social, deck, visual, and outreach assets. Each channel names the target user, artifact, source evidence, review question, and success signal so builders can review launch materials before publishing.", + targetUser: + "AI project builders, open-source maintainers, technical founders, DevRel operators, and product marketers preparing a cold-start repository launch.", + jobToBeDone: + "When a generated repo brief produces multiple launch artifacts, help the builder decide which material belongs on which channel, who it is for, what source evidence supports it, and what activation signal to watch next.", + evidenceBoundary: + "The map should use repository metadata, README evidence, linked docs, official identity assets, generated quality reports, or explicit user input. It should not promise search placement, financial outcomes, adoption, Product Hunt outcomes, exact pricing, or automated publishing.", + benefits: [ + { + title: "Map every material to a job", + body: "Tie README, social, deck, visual, and outreach outputs to a target user, job-to-be-done, artifact, source evidence, review question, and success signal.", + }, + { + title: "Keep cold-start launch work reviewable", + body: "Show which source-backed claim belongs in each channel before the builder copies, downloads, or requests a full package.", + }, + { + title: "Measure activation by artifact behavior", + body: "Track copy and download behavior by artifact type so QuickFork can learn which materials create value before adding pricing or scale.", + }, + { + title: "Make the product workflow AI-readable", + body: "Expose the materials map as a crawlable product page with definition, FAQ, source notes, and CTA back to the generator.", + }, + ], + workflow: [ + { + title: "Start from one repository URL", + body: "QuickFork reads README, metadata, topics, source references, identity assets, and explicit user notes.", + }, + { + title: "Build the free repo launch brief", + body: "The generation flow creates target-user discovery, a story map, source references, and channel artifacts.", + }, + { + title: "Map artifacts to channels", + body: "The materials map assigns README, social, deck, visual, and outreach outputs to users, jobs, review questions, and success signals.", + }, + { + title: "Copy, download, and validate", + body: "Builders export the useful artifacts, then compare page source, generation, copy, download, and full-package request behavior.", + }, + ], + faqs: [ + { + question: "What is a GitHub repo launch materials map?", + answer: + "It is a source-backed channel plan that maps one repository URL into README, social, deck, visual, and outreach assets, with target user, artifact, source evidence, review question, and success signal for each channel.", + }, + { + question: "How does the materials map help cold-start launches?", + answer: + "It keeps every launch material tied to a specific user job and source boundary before the project has mature public proof, so builders can review and ship the most useful channels first.", + }, + { + question: "What does QuickFork measure after generating the map?", + answer: + "QuickFork can measure launch brief views, materials-map copies, artifact copies and downloads, generation completions, and full launch package requests without sending raw README text or artifact bodies to browser analytics.", + }, + { + question: "Does the materials map publish assets automatically?", + answer: + "No. It is a review and planning surface. Humans still approve claims, visuals, examples, pricing language, and public publishing choices.", + }, + ], + sourceNotes: [ + { + label: "GitHub Docs About READMEs", + body: "GitHub treats the README as the primary repository explanation surface, so a channel map should start with README evidence.", + url: "https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes", + }, + { + label: "GitHub Docs social preview", + body: "GitHub social preview customization makes shared-link visuals a concrete material in repository launch planning.", + url: "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/customizing-your-repositorys-social-media-preview?apiVersion=2022-11-28", + }, + { + label: "Open Source Guides finding users", + body: "Open Source Guides connects audience discovery and feedback loops to open-source launch work.", + url: "https://opensource.guide/finding-users/", + }, + { + label: "Product Hunt launch guide", + body: "Product Hunt launch preparation makes story, media, maker context, and launch-day copy practical review surfaces.", + url: "https://www.producthunt.com/launch/preparing-for-launch", + }, + ], + lastUpdated: "June 3, 2026", + }, readme_marketing_cards: { definition: "README marketing cards are README-first hero cards, GitHub social preview direction, and launch visuals grounded in repository evidence and human review. They help visitors understand what a technical project does before reading the full README, code, benchmark notes, or launch announcement.", @@ -1195,6 +1286,9 @@ export function getMarketingPageHeadline(link: MarketingLink) { if (link.intentCluster === "cold_start_launch_materials") { return "Cold Start Launch Materials From A GitHub Repo."; } + if (link.intentCluster === "github_repo_launch_materials_map") { + return "GitHub Repo Launch Materials Map for source-backed channel planning."; + } if (link.intentCluster === "readme_marketing_cards") { return "README Marketing Cards for source-backed repository visuals."; } @@ -1258,6 +1352,9 @@ export function getMarketingPageDescription(link: MarketingLink) { if (link.intentCluster === "cold_start_launch_materials") { return "QuickFork maps cold start launch materials demand into source-backed README, social, deck, visual, and outreach drafts generated from one public GitHub repository URL."; } + if (link.intentCluster === "github_repo_launch_materials_map") { + return "QuickFork maps github repo launch materials map demand into a source-backed channel plan for README, social, deck, visual, and outreach assets from one repository URL."; + } if (link.intentCluster === "readme_marketing_cards") { return "QuickFork maps readme marketing cards demand into README-first hero cards, GitHub social preview direction, and launch visuals grounded in repository evidence and human review."; } diff --git a/src/seo/public-growth.test.ts b/src/seo/public-growth.test.ts index 1e420cf..78447fe 100644 --- a/src/seo/public-growth.test.ts +++ b/src/seo/public-growth.test.ts @@ -33,6 +33,7 @@ describe("public growth infrastructure", () => { expect(sitemap).toContain(`${link.canonicalUrl}`); } expect(sitemap).toContain("https://seekersai.com/product/cold-start-launch-materials"); + expect(sitemap).toContain("https://seekersai.com/product/github-repo-launch-materials-map"); expect(sitemap).toContain("https://seekersai.com/product/github-repo-visual-explainer"); expect(sitemap).toContain("https://seekersai.com/product/github-repo-to-launch-deck"); expect(sitemap).toContain("https://seekersai.com/product/github-repo-to-product-outreach"); @@ -61,6 +62,11 @@ describe("public growth infrastructure", () => { expect(llms).toContain( "source-backed README, social, deck, visual, and outreach drafts generated from one public GitHub repository URL", ); + expect(llms).toContain("https://seekersai.com/product/github-repo-launch-materials-map"); + expect(llms).toContain("GitHub Repo Launch Materials Map"); + expect(llms).toContain( + "source-backed channel plan for README, social, deck, visual, and outreach assets from one repository URL", + ); expect(llms).toContain("https://seekersai.com/product/readme-marketing-cards"); expect(llms).toContain("README Marketing Cards"); expect(llms).toContain( diff --git a/src/seo/semantic-links.test.ts b/src/seo/semantic-links.test.ts index 8d492f9..d75f7cb 100644 --- a/src/seo/semantic-links.test.ts +++ b/src/seo/semantic-links.test.ts @@ -225,6 +225,12 @@ describe("typed semantic marketing link catalog", () => { primaryCta: "generate_launch_card", }), ); + expect(getMarketingLinkByPath("/product/github-repo-launch-materials-map")).toEqual( + expect.objectContaining({ + intentCluster: "github_repo_launch_materials_map", + primaryKeyword: "github repo launch materials map", + }), + ); expect(getMarketingLinkByPath("/product/readme-marketing-cards")).toEqual( expect.objectContaining({ intentCluster: "readme_marketing_cards", @@ -268,6 +274,16 @@ describe("typed semantic marketing link catalog", () => { expect(getMarketingPageDescription(link!)).not.toMatch(/guaranteed|rankings|revenue|customers|viral/i); }); + it("publishes a GitHub repo launch materials map product page contract", () => { + const link = getMarketingLinkByPath("/product/github-repo-launch-materials-map"); + + expect(link).toBeDefined(); + expect(getMarketingPageTitle(link!)).toContain("GitHub Repo Launch Materials Map"); + expect(getMarketingPageHeadline(link!)).toContain("GitHub Repo Launch Materials Map"); + expect(getMarketingPageDescription(link!)).toContain("source-backed channel plan"); + expect(getMarketingPageDescription(link!)).not.toMatch(/guaranteed|rankings|revenue|customers|viral/i); + }); + it("publishes a README marketing cards product page contract", () => { const link = getMarketingLinkByPath("/product/readme-marketing-cards"); diff --git a/src/server/generation/generation.test.ts b/src/server/generation/generation.test.ts index 8479e56..29bd247 100644 --- a/src/server/generation/generation.test.ts +++ b/src/server/generation/generation.test.ts @@ -542,9 +542,36 @@ describe("project launch generation backend", () => { }), ); expect(result.launchBrief.storyMap.nodes[2]?.detail).toContain("->"); + expect(result.launchBrief.launchMaterialsMap.title).toContain("nexu-io/open-design"); + expect(result.launchBrief.launchMaterialsMap.channels.map((channel) => channel.type)).toEqual([ + "readme", + "social", + "deck", + "visual", + "outreach", + ]); + expect(result.launchBrief.launchMaterialsMap.channels[0]).toEqual( + expect.objectContaining({ + type: "readme", + label: "README launch section", + primaryUser: expect.stringContaining("Open-source"), + jobToBeDone: expect.stringContaining("understand"), + reviewQuestion: expect.stringContaining("source"), + successSignal: expect.stringContaining("README"), + source: expect.stringContaining("README or repo metadata includes"), + }), + ); + expect(result.launchBrief.launchMaterialsMap.channels[3]).toEqual( + expect.objectContaining({ + type: "visual", + artifactLabel: "Visual explainer prompt", + reviewQuestion: expect.stringContaining("identity"), + }), + ); expect(result.launchBrief.artifacts.map((artifact) => artifact.type)).toEqual([ "audience", "story_map", + "materials_map", "readme", "social", "deck", @@ -567,6 +594,13 @@ describe("project launch generation backend", () => { body: expect.stringContaining("## Project story map"), sourceReferences: expect.arrayContaining([expect.stringContaining("README or repo metadata includes")]), }), + expect.objectContaining({ + type: "materials_map", + label: "Launch materials map", + fileName: "nexu-io-open-design-launch-materials-map.md", + body: expect.stringContaining("## Launch materials map"), + sourceReferences: expect.arrayContaining([expect.stringContaining("README or repo metadata includes")]), + }), expect.objectContaining({ type: "readme", label: "README launch brief", diff --git a/src/server/generation/launch-brief.ts b/src/server/generation/launch-brief.ts index d098420..220b9e7 100644 --- a/src/server/generation/launch-brief.ts +++ b/src/server/generation/launch-brief.ts @@ -8,6 +8,7 @@ import type { RepoLaunchBriefAngle, RepoLaunchBriefArtifact, RepoLaunchBriefChecklistItem, + RepoLaunchMaterialsMap, RepoLaunchStoryMap, VisualDirection, } from "./types.js"; @@ -65,12 +66,26 @@ export function buildRepoLaunchBrief(input: { sourceReferences, visualCategory: input.visualDirection.category, }); + const launchMaterialsMap = buildLaunchMaterialsMap({ + repoFullName: input.metadata.fullName, + summary: input.brief.subtitle, + audience, + audienceDiscovery, + storyMap, + readmeChecklist, + launchAngles, + socialPost, + deckOutline, + sourceReferences, + visualCategory: input.visualDirection.category, + }); return { summary: input.brief.subtitle, audienceHypothesis: audience, audienceDiscovery, storyMap, + launchMaterialsMap, readmeChecklist, launchAngles, socialPost, @@ -84,6 +99,7 @@ export function buildRepoLaunchBrief(input: { audienceHypothesis: audience, audienceDiscovery, storyMap, + launchMaterialsMap, readmeChecklist, launchAngles, socialPost, @@ -101,6 +117,7 @@ function buildLaunchBriefArtifacts(input: { audienceHypothesis: string; audienceDiscovery: RepoLaunchAudienceDiscovery; storyMap: RepoLaunchStoryMap; + launchMaterialsMap: RepoLaunchMaterialsMap; readmeChecklist: RepoLaunchBriefChecklistItem[]; launchAngles: RepoLaunchBriefAngle[]; socialPost: string; @@ -127,6 +144,13 @@ function buildLaunchBriefArtifacts(input: { body: formatStoryMap(input.storyMap, sourceBlock), sourceReferences: input.sourceReferences, }, + { + type: "materials_map", + label: "Launch materials map", + fileName: `${slug}-launch-materials-map.md`, + body: formatLaunchMaterialsMap(input.launchMaterialsMap, sourceBlock), + sourceReferences: input.sourceReferences, + }, { type: "readme", label: "README launch brief", @@ -236,6 +260,91 @@ function buildAudienceDiscovery(input: { }; } +function buildLaunchMaterialsMap(input: { + repoFullName: string; + summary: string; + audience: string; + audienceDiscovery: RepoLaunchAudienceDiscovery; + storyMap: RepoLaunchStoryMap; + readmeChecklist: RepoLaunchBriefChecklistItem[]; + launchAngles: RepoLaunchBriefAngle[]; + socialPost: string; + deckOutline: string[]; + sourceReferences: string[]; + visualCategory: VisualDirection["category"]; +}): RepoLaunchMaterialsMap { + const primarySource = input.sourceReferences[0] ?? "Repository evidence is limited; review generated claims before publishing."; + const secondarySource = input.sourceReferences[1] ?? primarySource; + const adopterSignal = input.audienceDiscovery.signals.find((signal) => signal.id === "open_source_adopters"); + const reviewerSignal = input.audienceDiscovery.signals.find((signal) => signal.id === "launch_reviewers"); + const technicalSignal = input.audienceDiscovery.signals.find((signal) => signal.id === "technical_builders"); + const topAngle = input.launchAngles[0]?.body ?? input.summary; + const firstChecklistItem = input.readmeChecklist[0]?.item ?? "Lead with a source-backed README value proposition."; + const workflowNode = input.storyMap.nodes.find((node) => node.id === "workflow"); + + return { + title: `${input.repoFullName} launch materials map`, + summary: `Channel plan for README, social, deck, visual, and outreach launch materials from ${input.summary}`, + channels: [ + { + type: "readme", + label: "README launch section", + primaryUser: adopterSignal?.segment ?? "Open-source adopters and README visitors", + jobToBeDone: `Help visitors understand ${input.repoFullName} before reading implementation details.`, + artifactLabel: "README launch brief", + channelFit: `Use the README section to surface "${firstChecklistItem}" before lower-level repository detail.`, + source: primarySource, + reviewQuestion: "Which source-backed claim belongs in the README hero without overstating proof?", + successSignal: "README artifact copied or downloaded; visitor continues into generation or full package request.", + }, + { + type: "social", + label: "Social launch post", + primaryUser: reviewerSignal?.segment ?? "Launch reviewers and technical social followers", + jobToBeDone: "Decide whether the project is worth clicking before opening GitHub.", + artifactLabel: "Social launch post", + channelFit: `Lead with "${input.socialPost.split("\n")[0]}" and keep the repo URL visible.`, + source: secondarySource, + reviewQuestion: "Does the post explain the project without invented traction, adoption, or pricing?", + successSignal: "Social artifact copied or downloaded; campaign UTM drives generation_started.", + }, + { + type: "deck", + label: "Launch deck outline", + primaryUser: "Technical founders, demo reviewers, and DevRel operators", + jobToBeDone: "Turn the repository story into a short launch narrative for demos, internal review, or Product Hunt prep.", + artifactLabel: "Pitch deck outline", + channelFit: `Anchor the deck around ${input.deckOutline.length} source-backed slides and the workflow ${workflowNode?.detail ?? "from repo evidence"}.`, + source: secondarySource, + reviewQuestion: "Which deck slide needs the strongest source citation before sharing outside the team?", + successSignal: "Deck artifact copied or downloaded; full launch package CTA clicked after artifact review.", + }, + { + type: "visual", + label: "Visual project explainer", + primaryUser: technicalSignal?.segment ?? input.audience, + jobToBeDone: "Understand the project workflow and proof boundary without parsing the full README.", + artifactLabel: "Visual explainer prompt", + channelFit: `Use the ${input.visualCategory} direction to keep README, social preview, and deck visuals aligned.`, + source: primarySource, + reviewQuestion: "Does the visual direction preserve identity assets and avoid fake logos or unsupported diagrams?", + successSignal: "Visual prompt copied, generated image preview opened, or image downloaded.", + }, + { + type: "outreach", + label: "Product outreach draft", + primaryUser: "DevRel operators, partner editors, and launch communities", + jobToBeDone: "Ask for feedback or distribution using a human-reviewed source-backed note.", + artifactLabel: "Product outreach draft", + channelFit: `Use a short outreach note centered on "${topAngle}" and keep it reviewable before sending.`, + source: primarySource, + reviewQuestion: "Which recipient segment should review this outreach draft before public distribution?", + successSignal: "Outreach artifact copied or downloaded; qualified contact request references launch review.", + }, + ], + }; +} + function buildStoryMap(input: { repoFullName: string; summary: string; @@ -330,6 +439,32 @@ function formatStoryMap(storyMap: RepoLaunchStoryMap, sourceBlock: string) { ].join("\n"); } +function formatLaunchMaterialsMap(launchMaterialsMap: RepoLaunchMaterialsMap, sourceBlock: string) { + return [ + `# ${launchMaterialsMap.title}`, + "", + "## Launch materials map", + "", + launchMaterialsMap.summary, + "", + ...launchMaterialsMap.channels.map((channel, index) => + [ + `${index + 1}. ${channel.label}`, + ` Channel: ${channel.type}`, + ` Primary user: ${channel.primaryUser}`, + ` Job to be done: ${channel.jobToBeDone}`, + ` Artifact: ${channel.artifactLabel}`, + ` Channel fit: ${channel.channelFit}`, + ` Review question: ${channel.reviewQuestion}`, + ` Success signal: ${channel.successSignal}`, + ` Source: ${channel.source}`, + ].join("\n"), + ), + "", + sourceBlock, + ].join("\n"); +} + function formatSourceReferences(sourceReferences: string[]) { return ["## Source references", ...sourceReferences.map((source) => `- ${source}`)].join("\n"); } diff --git a/src/server/generation/types.ts b/src/server/generation/types.ts index 5bb5847..1c6eefb 100644 --- a/src/server/generation/types.ts +++ b/src/server/generation/types.ts @@ -228,7 +228,27 @@ export interface RepoLaunchStoryMap { nodes: RepoLaunchStoryMapNode[]; } -export type RepoLaunchBriefArtifactType = "audience" | "story_map" | "readme" | "social" | "deck" | "outreach" | "visual"; +export type RepoLaunchMaterialChannelType = "readme" | "social" | "deck" | "visual" | "outreach"; + +export interface RepoLaunchMaterialChannel { + type: RepoLaunchMaterialChannelType; + label: string; + primaryUser: string; + jobToBeDone: string; + artifactLabel: string; + channelFit: string; + source: string; + reviewQuestion: string; + successSignal: string; +} + +export interface RepoLaunchMaterialsMap { + title: string; + summary: string; + channels: RepoLaunchMaterialChannel[]; +} + +export type RepoLaunchBriefArtifactType = "audience" | "story_map" | "materials_map" | "readme" | "social" | "deck" | "outreach" | "visual"; export interface RepoLaunchBriefArtifact { type: RepoLaunchBriefArtifactType; @@ -243,6 +263,7 @@ export interface RepoLaunchBrief { audienceHypothesis: string; audienceDiscovery: RepoLaunchAudienceDiscovery; storyMap: RepoLaunchStoryMap; + launchMaterialsMap: RepoLaunchMaterialsMap; readmeChecklist: RepoLaunchBriefChecklistItem[]; launchAngles: RepoLaunchBriefAngle[]; socialPost: string; diff --git a/src/styles/app.css b/src/styles/app.css index 148935a..9edfa3c 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -1127,6 +1127,98 @@ blockquote { line-height: 1.4; } +.launchMaterialsMap { + border: 1px solid var(--border); + display: grid; + background: #f7fbf8; +} + +.launchMaterialsMapHead { + padding: 14px; + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 12px; + align-items: center; + border-bottom: 1px solid var(--border); +} + +.launchMaterialsMapHead strong { + display: block; + font-size: 15px; + line-height: 1.25; +} + +.launchMaterialsMapHead small { + display: block; + margin-top: 4px; + color: var(--muted); + font-size: 13px; + line-height: 1.4; +} + +.launchMaterialsMapChannels { + margin: 0; + padding: 0; + display: grid; + list-style: none; +} + +.launchMaterialsMapChannels li { + padding: 14px; + border-bottom: 1px solid var(--border); + display: grid; + gap: 8px; +} + +.launchMaterialsMapChannels li:last-child { + border-bottom: 0; +} + +.launchMaterialsMapChannels span { + width: fit-content; + padding: 3px 7px; + border: 1px solid var(--border); + background: #ffffff; + color: var(--muted); + font: 700 11px/1.2 var(--font-mono); + text-transform: uppercase; +} + +.launchMaterialsMapChannels strong { + font-size: 15px; + line-height: 1.25; +} + +.launchMaterialsMapChannels dl { + margin: 0; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px 12px; +} + +.launchMaterialsMapChannels div { + min-width: 0; +} + +.launchMaterialsMapChannels dt { + color: var(--muted); + font: 700 10px/1.2 var(--font-mono); + text-transform: uppercase; +} + +.launchMaterialsMapChannels dd { + margin: 3px 0 0; + color: var(--fg); + font-size: 13px; + line-height: 1.45; +} + +.launchMaterialsMapChannels small { + color: var(--muted); + font-size: 12px; + line-height: 1.4; +} + .launchArtifactList { border: 1px solid var(--border); display: grid; @@ -3289,6 +3381,8 @@ blockquote { .launchAudienceDiscoveryHead, .launchAudienceDiscoverySignals dl, .launchStoryMapHead, + .launchMaterialsMapHead, + .launchMaterialsMapChannels dl, .launchArtifactIntro, .launchArtifactRow, .launchPackageCta,