Matrix Transform
A square SVG plane that visualizes a 2x2 matrix as the linear transformation it performs on the plane. The matrix's two columns are exactly where the basis vectors î = (1, 0) and ĵ = (0, 1) land — drag either column's arrowhead to reshape the whole grid in real time. The signed-area determinant is surfaced below, so collapsing-to-a-line (det = 0) and orientation-flipping (det < 0) are immediately observable.
2 by 2 matrix transformation. i hat lands at (1.00, 0.00). j hat lands at (0.00, 1.00). Determinant 1.00.
det · signed area1.00
Customize
Column 1 (where i hat lands)
1
0
Column 2 (where j hat lands)
0
1
Display
Installation
npx shadcn@latest add https://craftbits.dev/r/matrix-transform.jsonUsage
import { MatrixTransform } from "@craft-bits/core";
<MatrixTransform
defaultMatrix={[
[1, 0],
[0, 1],
]}
/>Make the basis-vector tips draggable and observe matrix changes:
const [matrix, setMatrix] = useState<Matrix2D>([
[1, 0],
[0, 1],
]);
<MatrixTransform
matrix={matrix}
onMatrixChange={setMatrix}
interactive
/>Apply a 90° rotation as a controlled value:
<MatrixTransform
matrix={[
[0, -1],
[1, 0],
]}
/>A singular matrix (det = 0) — the plane collapses to a line:
<MatrixTransform
matrix={[
[1, 2],
[0.5, 1],
]}
/>Understanding the component
- Math-space coordinates, y points up. The matrix is row-major:
[[a, b], [c, d]]. The first column[a, c]is where î lands; the second column[b, d]is where ĵ lands. Every point(x, y)maps to(a·x + b·y, c·x + d·y). - Deformed grid as the transformation. With
showGrid, the integer grid is rendered twice: a very faint original cartesian grid, plus the image of that grid under the matrix in accent color. Watching the lines warp is the linear-algebra "what does this matrix do?" intuition. - Two columns, two tones. Column 1 (where î lands) draws in
var(--cb-accent); column 2 (where ĵ lands) draws invar(--cb-warning). The original î / ĵ basis vectors are shown as dashed dim arrows so the user can see the before / after. - Unit-square parallelogram. The image of the unit square is filled at low opacity. Its color switches to
var(--cb-warning)when the matrix is singular (det ≈ 0) andvar(--cb-error)when orientation flips (det < 0) — visual feedback aligned with the determinant readout. - Drag handles on the column tips. When
interactive, each transformed basis-vector arrowhead becomes a 32px-diameterrole="slider"invisible hit target. Dragging projects the pointer throughgetScreenCTM().inverse()so it tracks under any transform; the tip clamps torange. - Numeric entry parity. Below the plot, four numeric
<input type="number">cells let the user type matrix entries directly. Color-coded to match each column. - Determinant readout. The signed area scaling factor is shown beneath the inputs. Green when positive, warning-tinted when zero (singular), error-tinted when negative (orientation flipped).
- Spring transitions. The deformed grid + parallelogram animate with
SPRINGS.smoothbetween matrix prop changes. Drag handles follow the pointer withSPRINGS.snap.prefers-reduced-motion: reducecollapses both toduration: 0.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
matrix | Matrix2D | — | Controlled 2x2 matrix. Pair with onMatrixChange. |
defaultMatrix | Matrix2D | identity | Uncontrolled initial matrix. |
onMatrixChange | (next: Matrix2D) => void | — | Fires on drag, keyboard nudge, or numeric edit. |
range | readonly [number, number] | [-3, 3] | Visible math-space domain on both axes. |
showGrid | boolean | true | Paint the original + deformed integer grid. |
showAxes | boolean | true | Paint the x / y axes through the origin. |
showBasisVectors | boolean | true | Highlight the original î / ĵ (dashed) + their transformed images. |
interactive | boolean | false | Make each column tip a drag + focus handle. |
size | number | 320 | SVG side length in pixels (the plane is square). |
transition | Transition | SPRINGS.snap | Spring for drag-follow transitions. |
className | string | — | Merged onto the root <div> via cn(). |
The Matrix2D shape is a row-major tuple — [[a, b], [c, d]] represents
| a b |
| c d |
Accessibility
- The SVG is
role="img"with a visually hidden summary listing where î and ĵ land and the current determinant. - When
interactive, each column tip exposes arole="slider"invisible 32px hit target meeting WCAG 2.5.8 (Target Size, Enhanced). - Keyboard: focus a handle, then
←/→/↑/↓nudge in 0.25-unit steps.Shift+Arrownudges by 1 unit. The tip clamps torange. - The four numeric inputs accept arrow-key increment via
step={0.1}and full numeric entry; each input carries anaria-labelidentifying its (row, column) position. - The determinant readout is
aria-live="polite"— assistive tech announces the value as it changes. - Animation respects
prefers-reduced-motion: reduce— all springs collapse to an instant swap.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/math/MatrixTransform.tsx). The source was a determinant-intuition lesson wired up with Explore / Predict / Challenge modes, randomly generated predict rounds, challenge pools, narration heuristics, and preset bookmarks. The library extract is the pure visualization primitive — a 2x2 matrix, the deformed grid, drag-the-tips interactivity, numeric entry, and the determinant readout.