Embedding Space Viz

A 2D embedding-space sandbox. Documents are dots clustered by meaning; a query is a vector pointing out from origin. Three modes — pick from preset queries (explore), drag a query freely to see live cosine + angle (investigate), or take a challenge to find a boundary spot where the top-K result set spans at least two different clusters (challenge).

Italian pasta recipesHow to make spaghetti carbonaraBest pizza dough recipeMediterranean cooking guideNeural network architecturesGPU memory optimizationTransformer model trainingDeep learning fundamentalsParis travel guideBest hotels in FranceEuropean vacation planningFrench cuisine restaurantsPick a query above to search this spaceeach dot is a document embedded as a 2D vector

Select a query to see where it lands in embedding space. Each dot is a document, clustered by meaning.

Use the query buttons above to search embedding space.
Customize
Retrieval
3

Installation

npx shadcn@latest add https://craftbits.dev/r/embedding-space-viz.json

Usage

import { EmbeddingSpaceViz } from "@craft-bits/viz/embedding-space-viz";
 
<EmbeddingSpaceViz />

Drop in your own document set:

<EmbeddingSpaceViz
  documents={[
    { id: "a1", label: "Quicksort", x: 120, y: 140, cluster: "algos" },
    { id: "a2", label: "Heapsort", x: 160, y: 100, cluster: "algos" },
    { id: "p1", label: "Dynamic typing", x: 600, y: 360, cluster: "pl" },
  ]}
  clusterLabels={[
    { label: "Algorithms", x: 140, y: 60 },
    { label: "Languages", x: 600, y: 300 },
  ]}
  clusterColors={{
    algos: { fill: "var(--cb-info)", stroke: "var(--cb-info)" },
    pl:    { fill: "var(--cb-success)", stroke: "var(--cb-success)" },
  }}
/>

Drive the mode from outside (controlled mode):

const [mode, setMode] = useState("explore");
 
<EmbeddingSpaceViz mode={mode} onModeChange={setMode} />

Understanding the component

  1. 2D plotted SVG. Documents live at fixed (x, y) coordinates in SVG user space. Cluster geometry is encoded by the input — there is no layout algorithm, the caller chooses positions. A dashed crosshair marks the canvas centre (origin for the cosine math).
  2. Mode tabs. Three top-level modes — explore, investigate, challenge. Switching modes clears all interaction state.
  3. Explore mode. Renders preset query pills above the canvas. Selecting one drops a glowing query dot, then after ~800ms (or instantly under reduced motion) the top-K connection lines stagger in with cosine similarity badges at their midpoints.
  4. Negation demo. A preset query can declare a negationCompare index; when that preset is active, a dashed red line draws between the two query positions with the cosine similarity printed — showing that "NOT" barely shifts an embedding.
  5. Investigate mode. The canvas becomes a click-and-drag surface. The query dot follows the pointer, the top-K results recompute on every frame, and a dashed gauge in the centre shows the angle (degrees) and cosine between the query vector and the nearest document.
  6. Challenge mode. A goal panel asks the visitor to place a query where the top-K spans ≥ 2 clusters. Start challenge enables dragging; Check placement evaluates and surfaces a pass/fail badge.
  7. Cluster-aware highlights. Hovering a document draws a dashed vector to it from canvas centre; matched documents glow in their cluster's colour; nearby documents fade up proportional to distance.
  8. Reduced motion. Under prefers-reduced-motion: reduce, every spring collapses to instant, the connection lines snap in without staggering, and the query-dot sonar pulse does not mount.

Props

PropTypeDefaultDescription
documentsEmbeddingSpaceVizDocument[]built-in 12-doc setDocuments plotted in embedding space.
presetQueriesEmbeddingSpaceVizPresetQuery[]built-in 4-query setPills surfaced in explore mode.
clusterLabelsEmbeddingSpaceVizClusterLabel[]built-in 3-cluster setDecorative cluster labels rendered behind dots.
clusterColorsRecord<string, { fill, stroke }>cooking / tech / travelPer-cluster colour overrides.
topKnumber3Number of nearest documents to highlight.
mode"explore" | "investigate" | "challenge"Controlled mode. Pair with onModeChange.
defaultMode"explore" | "investigate" | "challenge""explore"Uncontrolled initial mode.
onModeChange(next: Mode) => voidFires on mode switch.
viewBoxWidthnumber800SVG viewBox width (user units).
viewBoxHeightnumber500SVG viewBox height (user units).
transitionTransitionSPRINGS.snapOverride the spring used for dot / line state transitions.
classNamestringMerged onto the root via cn().

Accessibility

  • The SVG is role="img" with an aria-label summarising the layout; per-document labels are decorative.
  • Mode switching uses role="tablist" / role="tab" with aria-selected and data-state hooks for styling.
  • A polite live region announces the top results whenever they change.
  • Preset queries are real <button> elements with visible labels, focus rings, and ≥ 32px hit area.
  • Investigate / challenge modes require pointer input; the live region tells screen-reader users to switch to explore mode for keyboard-accessible queries.
  • Colour is never the only signal — matched docs scale up and labels bold, the negation comparison adds a dashed stroke + cosine label, and the cluster labels are text.
  • Motion respects prefers-reduced-motion: reduce.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/systems/EmbeddingSpaceViz.tsx). The source was a lesson component wrapped in the project's Widget chrome (with built-in undo/redo history, eyebrow / premise / caption header, and reset button), with hard dependencies on SvgLabel, ModeStrip, ChallengeBtn, and FeedbackBadge from the lesson chrome layer, plus per-track palette tokens. The viz extract replaces every palette reference with var(--cb-*) semantic tokens, re-keys motion to canonical SPRINGS.snap / SPRINGS.smooth / SPRINGS.bouncy and scalar STAGGER from @craft-bits/core/motion, drops the Widget chrome, replaces SvgLabel with plain <text>, inlines a local ChallengeButton, surfaces the document set / preset queries / cluster labels / colours / topK as props, and exposes the interaction mode as a controlled-or-uncontrolled Radix-style prop.