Medium Pool · every medium your app could speak
$npx skills add funclosure/medium-pool

Reading-driven graph

VisualizationText
Prose scroll reveals the graph
messageReading becomes navigation.
instance Global Workspace readerSix passages, twelve concepts

A concept graph on its own is a map without a route. Prose on its own is a route without a map. Bind them and the reader gets both: they read at their own pace, and the graph lights up the concepts the current passage is about.

This is the pattern behind mindgraph, where a digested transcript becomes a force-directed graph plus a Source pane, and scrolling the prose spotlights the graph.

The binding

  • Signal: the reader’s scroll position, resolved to one active passage
  • Contract: each passage declares the concept ids it is about
  • Effect: the graph’s emphasis set becomes those ids; everything else dims
direction
both ways
substrate
Visualization + Text · scroll position as the binding

Built from

  • Visualization: A picture computed from data
  • Text: Words people read, quote, and search

Where it bites

  • Resolve scroll to one passage with a fixed reading line (around 40% down the pane), not to whatever is intersecting. Two passages half-visible must not fight.
  • Passages declare ids; the graph never parses prose. Keep the contract in data so the two sides can evolve separately.
  • Emphasis changes should be calm: dim, do not remove. Layout must not jump when the set changes.
  • Auto-scroll is a convenience, not the default. Reading speed belongs to the reader.
  • Both parts must work alone. The graph without prose is still the Visualization lane; the prose without the graph is still readable text.

Instances of this composition

Each is one way to build it. None of them is the composition.

Global Workspace readerin the pool

Six passages, twelve concepts. reference/ReadingGraph.ts

mindgraphside project

The origin of this composition: scrolling the Source pane spotlights the graph.

scrollamaopen source

Scrollytelling with IntersectionObserver. The scroll-to-step resolver, generalized.

$npx skills add funclosure/medium-pool --skill compose-reading-graph
skills/compose-reading-graph/SKILL.md
---
name: compose-reading-graph
description: "Bind a scrolling text to a concept graph so the active passage sets the graph's emphasis. Use when building reading surfaces over transcripts, essays, or papers where a map of concepts should follow the reader. Composes medium-visualization and medium-text."
---

# Reading-driven graph

## What this composition does to the person
Bound by scroll, prose and graph turn reading into navigation: the reader moves through the text and watches where they are on the map of ideas.

## What this composition is
Prose and a concept graph, bound by scroll position. The reader scrolls; one passage is active; the graph emphasizes that passage's concepts. The pattern behind mindgraph's Source pane and graph canvas.

## Parts (install these first)
- `medium-visualization` for the graph: layout, hit testing, and `setEmphasis(ids)`
- `medium-text` for the passages and their markup

## The binding contract
- Each passage carries `data-ids`, the concept ids it is about.
- A reading line at 40% of the pane's height picks the single active passage on every scroll event.
- The active passage's ids become the graph's emphasis set. Nothing else changes; layout stays put.

## UX rules that always apply
- Dim, never hide, the concepts outside the active set.
- Mark the active passage in the prose too, so both sides agree visibly.
- Optional auto-read scrolls slowly and stops at the end; the reader can always take over.

## Reference instances
Each is one way to speak this composition, cited as evidence. None of them is the composition.

`reference/ReadingGraph.ts` — passage list with ids, reading-line resolver, and a ForceGraph from the visualization skill driven through `setEmphasis`. It imports the graph engine from the sibling `medium-visualization` skill folder, so install both or the import fails. It uses a few layout class names from the pool's stylesheet (`row`, `btn`, `status`, `frame`); without that stylesheet the logic still runs and the controls are unstyled.

## Gotchas
- Fixed reading line, not intersection ratios.
- Ids live in data, never inferred from text at runtime.
- Keep the two parts independently usable.