Skip to content

Add Product Galaxy — 3D map of how PostHog products fit together#17019

Draft
rafaeelaudibert wants to merge 1 commit into
masterfrom
product-galaxy
Draft

Add Product Galaxy — 3D map of how PostHog products fit together#17019
rafaeelaudibert wants to merge 1 commit into
masterfrom
product-galaxy

Conversation

@rafaeelaudibert
Copy link
Copy Markdown
Member

Changes

Adds a new windowed app at /products/galaxy — a force-directed 3D graph of how PostHog's 16 main products relate to one another, styled like a 1998-vintage sci-fi terminal. It turns the implicit pairsWith relationships scattered across the product data files into something visitors can actually see and play with.

How it works

  • Each main product is a wireframe node, colored by its brand token. Edges are the existing pairsWith declarations.
  • Visitors click nodes to add products to their fleet ("what I already use"). The right rail then scores the remaining products by edge weight and surfaces recommended companions with the original pairsWith marketing copy as bullets.
  • A custom d3-force pulls fleet nodes one way and pushes everything else outward by BFS distance, so a selection visually stratifies the universe into direct neighbors, two-hop products, and the far-away things. The camera slowly flies to fit the new layout (fleet ends up on the left third of the screen).
  • Particles flow outward along edges from the fleet — direction is flipped per-link based on BFS depth, so the recommended next steps are obvious from across the room.
  • Marketing can deep-link via /products/galaxy?using=product_analytics,session_replay to prefill the fleet and land directly in the angled view.

Data layer changes

  • New src/hooks/productData/relationships.ts is now the single source of truth for pairsWith / billedWith / sharesFreeTier / worksWith (the last is @deprecated).
  • The 16 per-product files no longer carry their own pairsWith / worksWith arrays. useProducts derives those legacy shapes from relationships.ts so ProductSidebar and the "Pairs with..." slide keep working unchanged — no other consumers needed to be touched.
  • Galaxy-specific assembly (buildGraph, recommend, result types) lives in src/components/ProductGalaxy/graph.ts next to its only consumer, not in the shared data module.

Frontend bits worth flagging for review

  • src/components/ProductGalaxy/colors.ts resolves Tailwind tokens against the live DOM (probe span + getComputedStyle, cached) and feeds the resulting hex values to three.js materials. The canvas tracks tailwind.config.js / data-scheme automatically — no hardcoded hex map drifting out of sync.
  • HUD and panels use the project's warm gray palette with orange as a rare highlight. No neon teal anywhere.
  • SSRFallback.tsx lists every product and its pairings as crawlable text so the page has indexable content before the canvas hydrates.
  • The dev-mode UI freeze gotcha is documented in GalaxyCanvas.tsx next to the graphReady gate (three-forcegraph defers its first _updateScene by a frame; calling d3ReheatSimulation during that window crashes the next animation tick — the gate avoids it).

Files touched outside the new directories

  • src/context/App.tsx — registers /products/galaxy in appSettings (size limits, center position).
  • src/hooks/useProducts.tsx — three lines to inject worksWith / pairsWith from relationships.ts.
  • src/hooks/productData/*.tsx — removed the now-duplicated pairsWith / worksWith arrays from each of the 16 product files (billedWith / sharesFreeTier stay — pricing, not relationship, concerns).
  • package.json / pnpm-lock.yaml — adds react-force-graph-3d and three. The chunk is lazy-loaded and only hits this route.

Checklist

  • I've read the docs and/or content style guides.
  • Words are spelled using American English
  • Use relative URLs for internal links
  • I've checked the pages added or changed in the Vercel preview build
  • If I moved a page, I added a redirect in vercel.json

🤖 Generated with Claude Code

Adds a new /products/galaxy app: a force-directed 3D graph rendered with
react-force-graph-3d, styled like a 1998-vintage sci-fi terminal. It
turns the implicit "which products go well together" relationships in
the productData files into something visitors can actually see and play
with.

How it works:

- Each of the 16 main billed products is a wireframe node, coloured by
  its brand token. Edges are the existing `pairsWith` declarations.
- Visitors click nodes to add products to their "fleet" (i.e. "what I
  already use"). The right rail then scores the remaining products by
  edge weight, surfacing recommended companions with the original
  pairsWith marketing copy as supporting bullets.
- A custom d3-force pulls fleet nodes one way and pushes other products
  outward by BFS distance, so a selection visually stratifies the
  universe into immediate neighbours, two-hop products, and the
  far-away things. The camera slowly flies to fit the new layout.
- Particles flow outward along edges from the fleet (direction is
  flipped per-link based on BFS depth) so the recommended next steps
  are obvious from across the room.
- Marketing can deep-link via `?using=product_analytics,session_replay`,
  which prefills the fleet and lands directly in the angled view.

Data layer:

- All product relationships move into a new
  `src/hooks/productData/relationships.ts` file — single source of truth
  for `pairsWith`, `billedWith`, `sharesFreeTier`, and the deprecated
  `worksWith`. The 16 per-product files no longer carry their own
  `pairsWith` / `worksWith` arrays; `useProducts` derives the legacy
  shapes from this file, so `ProductSidebar` and the "Pairs with..."
  slide keep working unchanged.
- Galaxy-specific graph construction (`buildGraph`) and recommendation
  scoring (`recommend`) live next to their only consumer, in
  `src/components/ProductGalaxy/graph.ts`.

Frontend bits worth noting:

- `colors.ts` resolves Tailwind colour tokens against the live DOM
  (probe span + `getComputedStyle`), caches the result, and feeds the
  three.js materials. The canvas tracks `tailwind.config.js` /
  `data-scheme` automatically without a hardcoded hex map.
- The HUD/panels use the project's warm grey palette with `orange` as
  the rare highlight — no neon teal, on theme with the rest of the site.
- Crawlable `SSRFallback` lists every product and its pairings so the
  page has indexable content before the canvas hydrates.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview May 26, 2026 01:42AM

@github-actions
Copy link
Copy Markdown
Contributor

Vale prose linter → found 4 errors, 6 warnings, 0 suggestions in your markdown

Full report → Copy the linter results into an LLM to batch-fix issues.

Linter being weird? Update the rules!

src/components/ProductGalaxy/README.md — 4 errors, 6 warnings, 0 suggestions
Line Severity Message Rule
1:3 warning 'ProductGalaxy' heading should be in sentence case, and product names should be capitalized. PostHogBase.SentenceCase
12:131 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
16:51 warning 'starfield' is a possible misspelling. PostHogBase.Spelling
18:128 warning 'pairsWith' is a possible misspelling. PostHogBase.Spelling
19:52 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
20:32 warning 'Crawlable' is a possible misspelling. PostHogBase.Spelling
44:3 warning 'Scanline' is a possible misspelling. PostHogBase.Spelling
47:149 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
59:4 warning 'SSR considerations' heading should be in sentence case, and product names should be capitalized. PostHogBase.SentenceCase
63:130 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash

@rafaeelaudibert rafaeelaudibert marked this pull request as draft May 27, 2026 23:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant