Ellipse Axis Explorer
A square SVG plane that teaches the focal definition of an ellipse. The user drags two sliders — semi-major axis a and semi-minor axis b — and the ellipse, its axes, the two foci, and the eccentricity readout all update live.
Ellipse with semi-major axis 1.50 and semi-minor axis 1.00. Eccentricity 0.75.
1.50
1.00
e = c / a = 1.12 / 1.50 = 0.75
Customize
Axes
1.50
1.00
Overlays
Installation
npx shadcn@latest add https://craftbits.dev/r/ellipse-axis-explorer.jsonUsage
import { EllipseAxisExplorer } from "@craft-bits/core";
<EllipseAxisExplorer defaultA={1.5} defaultB={1.0} />Drive both axes as controlled values:
const [a, setA] = useState(1.5);
const [b, setB] = useState(1.0);
<EllipseAxisExplorer a={a} onAChange={setA} b={b} onBChange={setB} />Hide the foci to focus on the axes alone:
<EllipseAxisExplorer defaultA={1.5} defaultB={1.0} showFoci={false} />Hide the eccentricity readout when you only want the visualization:
<EllipseAxisExplorer
defaultA={2}
defaultB={1}
showEccentricity={false}
/>Understanding the component
- Parametric ellipse polyline. The curve is sampled at 96 points along
(a cos t, b sin t)fortin zero to two pi and rendered as amotion.polylineso thepointsattribute can spring between snapshots without React re-rendering on every frame. - Foci on the major axis. The focal distance is
sqrt(a squared minus b squared). Whenais the larger axis the foci sit on the x axis; when the user pushesbpastathe construction flips and the foci move to the y axis. - Eccentricity as a ratio. Eccentricity equals
cdivided by the larger semi-axis — zero for a circle, approaching one as the ellipse stretches thin. The readout surfaces the full expression so the relationship betweenc, the major axis, andestays visible. - Auto-fit viewport. The math-space half-extent is
12 percentlarger than the bigger of the two slider maxes, so the ellipse and foci stay comfortably inside the frame across the entire slider range without popping. - Two strokes, two roles. A faint accent fill at 8 percent opacity sits behind a solid accent outline so the ellipse reads as both a shape and a curve — the fill establishes the body, the outline carries the precision.
- Built on
LabeledSlider. Both sliders are instances of the library'sLabeledSlider— installing this component via shadcn pullslabeled-sliderin as a transitive dependency, free a11y included. - Reduced motion. When
prefers-reduced-motion: reduceis set the ellipse, axes, and foci snap to their new positions with no spring.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
a | number | — | Controlled semi-major axis. Pair with onAChange. |
defaultA | number | 1.5 | Uncontrolled initial semi-major axis. |
onAChange | (value: number) => void | — | Fires when a changes. |
b | number | — | Controlled semi-minor axis. Pair with onBChange. |
defaultB | number | 1.0 | Uncontrolled initial semi-minor axis. |
onBChange | (value: number) => void | — | Fires when b changes. |
aRange | readonly [number, number] | [0.5, 2.5] | Slider range for a. |
bRange | readonly [number, number] | [0.3, 2.5] | Slider range for b. |
showAxes | boolean | true | Draw the dashed semi-axis lines. |
showFoci | boolean | true | Render the two focal points. |
showEccentricity | boolean | true | Render the eccentricity readout. |
size | number | 320 | SVG side length in pixels (the plane is square). |
transition | Transition | SPRINGS.smooth | Spring for ellipse / axis transitions. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root renders with
role="figure"andaria-labelledbypointing at a visually hiddenaria-live="polite"summary — assistive tech announces the new axes and eccentricity as the user drags the sliders. - The SVG itself is
aria-hidden; the visible sliders carry their own labels viaLabeledSlider, so keyboard users can adjust each axis with arrow keys and the focus ring lands on a native input. - The eccentricity readout uses tabular numerals so the columns stay aligned as values change.
- Animation respects
prefers-reduced-motion: reduce— every spring collapses to an instant swap.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/math/EllipseAxisExplorer.tsx). The source was a linear-algebra widget that morphed a unit circle into an ellipse and overlaid a narration state machine for "scalar multiple of identity" / "ill-conditioned" / "singular." The library extract drops the eigenvalue framing and rebuilds the component around the focal definition — semi-major and semi-minor axes, foci at distancecfrom the center, and eccentricitye = c / a— so it teaches conic sections instead of linear maps.