Skip to content

feature: ambient writing graph behind homepage hero (animated, blurred) #24

Description

@viniciusdc

What it is

An animated, blurred force-directed graph of the notebook's posts, rendered as a backdrop behind the homepage hero. Nodes are posts, edges are computed relationships (shared tags, word overlap, date proximity). The graph quietly conveys the breadth + topology of the notebook even before the visitor scrolls — the hero block sits in front of it, sharp and legible; the graph blurs slightly behind it, with subtle motion to signal that it's alive.

Visual spec

  • Position: `position: fixed` or `absolute` inside the homepage layout, behind the hero (`z-index` below ``)
  • Blur: a few px (CSS `filter: blur(2–4px)`) — visible as shapes and relationships, not as individual labels
  • Opacity: low overall (`opacity: 0.25–0.4`), warmer caramel/amber on amber background; foreground hero pulls focus
  • Nodes: small filled circles or Q.E.D.-style squares, sized by — TBD — recency, edge-count, or tag-cluster size
  • Edges: thin lines, faintly oscillating rays along their length. Implementation candidates:
    • Animated `stroke-dasharray` + `stroke-dashoffset` shifting over 4–8s, gives a soft electrical-pulse feel
    • Multiple thin lines per edge with phase-shifted opacity animations, creating a subtle wavering glow
    • Particles traveling node→node along the edge path (more demanding)
  • Motion budget: respect `prefers-reduced-motion`. Default state should be calm — slow, low-amplitude pulses, never strobing
  • Camera: graph is static positionally (force layout run once at build time); only the visual decoration animates

Data pipeline

  1. Build-time script (e.g. `scripts/gen-graph.mjs`): walks `src/pages/writing//index.{astro,mdx}` and `src/pages/projects//index.{astro,mdx}`, extracts each `metadata` block (title, tag/label, date, description)
  2. Edge scoring between every pair of posts:
    • Shared `tag` (or shared category) → base weight
    • Word overlap in title + description after stopword removal → additional weight
    • Date proximity → minor weight
  3. Force-directed layout computed in Node (e.g. via `d3-force`) to produce stable `(x, y)` per node
  4. Emit `src/data/writing-graph.json` with `{ nodes: [...], edges: [...] }`
  5. Homepage imports the JSON and renders an inline SVG; CSS handles the blur + animations

Behavior at low post counts

The graph needs a graceful degradation:

  • 0–2 posts: graph is meaningless. Fall back to a static, abstract version — a small constellation of decorative nodes drawn from a fixed seed so it still feels notebook-ish
  • 3–6 posts: render the real graph; it'll look sparse but honest
  • 7+ posts: starts to feel like a real topology, with clusters visible through the blur

Performance

  • SVG only, no canvas/WebGL needed for the density we'll have
  • All animations CSS-driven (no JS animation loop)
  • Force layout is build-time, not runtime — JSON is small (<10KB for ~50 posts)
  • Page weight increase should be <20KB total

Also useful: local writing aid

The same JSON can power a separate `make graph` target that opens a non-blurred, interactive version locally for writing — "where are the clusters? what's missing?" That was the original spec from this issue. The local view and the homepage backdrop share the same data pipeline.

Out of scope (initial cut)

  • Semantic embeddings — keyword/tag overlap is enough to start
  • Click-through nodes on the backdrop (it's decoration; the actual posts are linked in the recent list)
  • Real-time animation of force simulation
  • Graph view as its own `/graph` page (could be a follow-up; not blocking)

Blocked on

Post volume. Below ~5 published posts the graph carries no information. With #22 and #18 plus a few more, it starts to be worth rendering. Not blocking building the pipeline — the script + the homepage component can land now and the visual gets richer organically as posts ship.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions