Area Collapse
A 2x2 determinant visualizer you can grab with your hands. Two draggable column-vector tips form a parallelogram on a Cartesian grid; the parallelogram's area equals the determinant of the matrix whose columns are those vectors. As the columns rotate toward each other the area shrinks. When they become parallel the determinant hits zero, the parallelogram collapses onto a dashed line, and the SINGULAR badge lands. Drag past that line and the determinant flips sign — the matrix mirrors the plane.
The viz is uncontrolled — initialCol0 and initialCol1 seed the starting state, and onColumnsChange lets the caller mirror the live values into a surrounding UI.
Installation
npx shadcn@latest add https://craftbits.dev/r/area-collapse.jsonUsage
import { AreaCollapse } from "@craft-bits/viz/area-collapse";
<AreaCollapse
initialCol0={{ x: 2, y: 0 }}
initialCol1={{ x: 1, y: 2 }}
size={320}
/>Read the live columns out as the learner drags:
<AreaCollapse
initialCol0={{ x: 2, y: 0 }}
initialCol1={{ x: 1, y: 2 }}
onColumnsChange={(col0, col1) => {
console.log("det =", col0.x * col1.y - col1.x * col0.y);
}}
/>Drop the singularity dramatics for a calmer parallelogram explorer:
<AreaCollapse showSingularBadge={false} />Understanding the component
- Two draggable column tips.
col0(accent / purple) andcol1(warning / orange) each render as a thick line from the origin to an invisible 14px hit-target circle on the tip. Drag either tip in any direction; the parallelogram updates every frame. - One parallelogram, two layers. A filled polygon and a stroked outline cover the same four corners — the origin,
col0,col0 + col1, andcol1. The fill's opacity scales with the magnitude of the determinant so a small parallelogram fades naturally, with a0.04opacity floor so it never disappears completely. - Five narration states.
wide(success tone),shrinking(accent),thin(warning),singular(error tone, locks once entered),negative(error tone, mirror language). Each state drives both the parallelogram fill colour and the narration paragraph under the canvas. - The singular climax. When the determinant hits the singular threshold, a dashed line replaces the parallelogram, the SINGULAR badge animates in on
SPRINGS.bouncy, and the narration locks to the singular copy until reset. - Det formula scrubber. Below the canvas a colour-coded
det A = ad − bcformula updates in real time. Column 0 entries inherit the accent colour; column 1 entries inherit the warning colour; the final value flips betweencb-success,cb-warning, andcb-errordepending on sign and magnitude. - Disk-clamped drag. Tips are clamped to a disk of radius
0.9 * range, so the parallelogram cannot escape the canvas. Pointer capture is set on pointer-down so the drag survives leaving the SVG. - Reduced motion. When
prefers-reduced-motion: reduceis set, the SINGULAR badge enter and exit collapse to instant — the badge still appears and disappears, just without the spring overshoot.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
initialCol0 | { x, y } | { x: 2, y: 0 } | Starting position of the accent (purple) column vector tip. |
initialCol1 | { x, y } | { x: 1, y: 2 } | Starting position of the warning (orange) column vector tip. |
range | number | 4 | Half-range of both axes. The canvas covers [-range, range]. |
size | number | 320 | Pixel size of the square SVG canvas. |
showSingularBadge | boolean | true | Show the SINGULAR badge plus dashed collapse line when the determinant is near zero. |
transition | Transition | SPRINGS.bouncy | Transition for the SINGULAR badge enter and exit. |
onColumnsChange | (col0, col1) => void | — | Notified whenever the user moves a column. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- Each drag handle is a
role="slider"SVG circle witharia-label("Drag column 0"/"Drag column 1") andaria-valuetextreporting the live(x, y)of the tip. - The SVG element exposes
role="img"with anaria-labelsummary that names both columns and the current determinant. - The narration block is
aria-live="polite"— state-change copy is announced without stealing focus. - The root element exposes
data-narr-state(wide/shrinking/thin/singular/negative) for downstream styling or assistive hooks. - Colour is never the only signal — every state is reinforced by the narration copy, the formula colour, and (in the singular case) the SINGULAR badge plus the dashed collapsed line.
- Drag handles have a 14px hit radius (28px diameter) — meets the Fitts' Law guideline when the surrounding viz padding is included.
- Motion respects
prefers-reduced-motion: reduce— the SINGULAR badge transition collapses to instant.
Credits
- Extracted from:
craftingattention(src/lessons/primitives/math/AreaCollapse.tsx). The source was a determinants and singularity lesson primitive, hardcoded to a 320px canvas, the lesson's--color-ink/--color-success/--color-accent/--color-warn/--color-failpalette, and the project'sca-narrationstyled paragraph. The viz extract repaints onto--cb-accent/--cb-warning/--cb-success/--cb-error/--cb-fg-*so it themes alongside every other craft-bits component, exposessize/range/initialCol0/initialCol1/onColumnsChange/showSingularBadgefor reuse outside the lesson, and swapsframer-motion'smnamespace for the canonicalmotionimport.