Dot Product Dial

Two vectors share an origin: a is fixed along the positive x-axis and b rotates by θ from a. The dot product a · b = |a| · |b| · cos(θ) is rendered live as a numeric readout, color-coded by sign. An optional perpendicular drop from b onto a visualizes the geometric reading of the dot product as "magnitude × projection."

Dot product 0.50; angle 60 degrees; vector a magnitude 1.00, vector b magnitude 1.00.
ab
a · b = |a| · |b| · cos θ = 1.00 · 1.00 · 0.50 = 0.50
Customize
Angle
60°
Magnitudes
1.00
1.00
Overlays

Installation

npx shadcn@latest add https://craftbits.dev/r/dot-product-dial.json

Usage

import { DotProductDial } from "@craft-bits/core";
 
<DotProductDial defaultTheta={Math.PI / 3} />

Control θ from outside (e.g. to drive it from a parent animation):

const [theta, setTheta] = useState(Math.PI / 4);
 
<DotProductDial
  theta={theta}
  onThetaChange={setTheta}
  aMagnitude={2}
  bMagnitude={1.5}
/>

Hide the projection or the formula readout for a minimal embed:

<DotProductDial
  defaultTheta={Math.PI / 2}
  showProjection={false}
  showFormula={false}
/>

Understanding the component

  1. Vector a is fixed; vector b rotates. a sits along the positive x-axis with magnitude aMagnitude. b shares the origin and rotates by theta radians (CCW positive). Math coordinates feed an internal SVG transform — y is flipped automatically.
  2. Native slider as the primary controller. A <input type="range"> covers [0, 2π] in 1° steps. Browsers ship full a11y for free — Tab to focus, / to nudge, screen readers announce aria-valuetext.
  3. Projection geometry. When showProjection is on (default), a dotted segment drops perpendicular from b's tip onto the x-axis. The opaque segment from origin to the drop foot is the projection of b onto a — its signed length equals |b|·cos(θ), exactly the dot product divided by |a|.
  4. Perpendicular detection. When |a · b| < 0.05 the component renders a small right-angle glyph at the origin, and the formula readout switches tone — a no-cost visual cue that the vectors are orthogonal.
  5. Semantic tone follows the dot product sign. Positive → cb-success, negative → cb-error, perpendicular → cb-fg-muted. The same color drives the formula readout and the projection-on-a highlight.
  6. Spring transitions. The b-vector tip follows theta with SPRINGS.snap; the projection segments use SPRINGS.smooth. prefers-reduced-motion: reduce collapses both to duration: 0.
  7. Controlled and uncontrolled. Pass theta + onThetaChange for controlled, or defaultTheta for uncontrolled. Default initial angle is π/3 (60°), which lands on a clean positive dot product.

Props

PropTypeDefaultDescription
aMagnitudenumber1Length of vector a along the x-axis.
bMagnitudenumber1Length of vector b before rotation.
thetanumberControlled angle in radians. Pair with onThetaChange.
defaultThetanumberMath.PI / 3Uncontrolled initial angle.
onThetaChange(theta: number) => voidFires on every slider change.
showProjectionbooleantrueRender the dotted projection of b onto a.
showFormulabooleantrueRender the |a||b|cos(θ) readout below the dial.
transitionTransitionSPRINGS.snapSpring for the b-vector tip.
classNamestringMerged onto the root <div> via cn().

Accessibility

  • The SVG is role="figure" with an aria-labelledby heading that's also rendered as a visually hidden aria-live="polite" summary — screen readers hear the dot product, angle, and magnitudes whenever θ changes.
  • The slider is a native <input type="range"> carrying aria-valuemin / aria-valuemax / aria-valuenow / aria-valuetext. Keyboard parity is automatic.
  • Motion respects prefers-reduced-motion: reduce — every spring collapses to an instant swap.
  • The right-angle glyph at θ = 90° / 270° doubles as a sighted-user cue that pairs with the semantic tone change on the formula readout.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/DotProductDial.tsx). The source paired the visualization with an Explore / Challenge mode strip, narration heuristics, a 5-round target-matching game, an auto-rotate sweep timer, a "predict the value" gate, and a synchronized cosine-wave panel. The library extract is the pure visualization primitive — two vectors, one angle, optional projection + formula.