Neuron Inline

The "hello world" of neural networks rendered as a hands-on toy: one neuron, two inputs x₁ and x₂, three knobs (W₁, W₂, bias). The learner turns the knobs and watches the decision boundary line sweep across a scatter plot of pre-labeled points; the line is the locus where W₁·x₁ + W₂·x₂ + bias = 0. Anything on one side is "class 1," anything on the other is "class 0." Misclassified points keep a soft pulsing error ring around them, so the goal — "find the angle and offset that separates the colors" — is unambiguous.

Single-neuron decision boundary classifier. 5 of 8 points classified correctly.
0.50
1.00
-1.50

0.50x₁ + 1.00x₂ 1.50 = 0

Customize
Initial bias
-1.50
Layers

Installation

npx shadcn@latest add https://craftbits.dev/r/neuron-inline.json

Usage

import { NeuronInline } from "@craft-bits/viz/neuron-inline";
 
<NeuronInline />

Show every signal — accuracy meter, activation toggle, shaded background:

<NeuronInline showAccuracy showActivationToggle showShading />

Constrain the controls (e.g. fix the weights, expose only the bias):

<NeuronInline controls={["bias"]} initial={{ w1: 1, w2: 1 }} />

Provide your own dataset:

<NeuronInline
  data={[
    { x1: 0.3, x2: 2.4, label: 1 },
    { x1: 2.6, x2: 0.4, label: 0 },
  ]}
/>

Understanding the component

  1. The plot. A 340×340 SVG with origin at the bottom-left of the plot region. x₁ runs along the horizontal axis, x₂ along the vertical, both spanning [-0.5, 3.5]. Eight labeled points are scattered at fixed positions; "class 1" uses the accent token, "class 0" uses the warning token.
  2. The boundary line. We solve W₁·x₁ + W₂·x₂ + bias = 0 for the two points where the line enters and exits the visible region. Those four numbers are pushed through useMotionValue + useSpring(SPRINGS.smooth), so when the user nudges a slider the endpoints interpolate rather than snap.
  3. The weight-vector arrow. A small green arrow rooted at (1.5, 1.5) points in the direction (W₁, W₂) — the normal to the boundary line. Like the line, its tip is spring-interpolated.
  4. Half-plane wash. When activation shading is off, a subtle accent-to-warning gradient is rotated behind the plot to line up with the boundary, telling the eye which side is "positive" at a glance.
  5. Activation shading (opt-in). showShading swaps the wash for a 16×16 grid of tiles colored by sigmoid(z) or relu(z)/3, making the smoothness of sigmoid vs. the hinge of ReLU visually obvious.
  6. Wrong-pulsing rings. Points the current weights misclassify get a pulsing error ring (driven by SVG <animate>). Toggling on showAccuracy adds an explicit N / N readout.

Props

PropTypeDefaultDescription
controlsreadonly ("w1" | "w2" | "bias")[]["w1", "w2", "bias"]Which parameter sliders to expose, in order.
initialPartial<NeuronInlineState>{ w1: 0.5, w2: 1, bias: -1.5, activation: "sigmoid" }Initial state. Doubles as the reset target.
datareadonly NeuronInlineDataPoint[]8 canonical pointsLabeled training points (x1/x2 in plot domain [-0.5, 3.5]).
showActivationTogglebooleanfalseRender the sigmoid/relu toggle below the sliders.
showShadingbooleanfalseRender the activation-shaded grid behind the points.
showEquationbooleantrueRender the live W₁·x₁ + W₂·x₂ ± |b| = 0 equation.
showAccuracybooleanfalseRender per-point accuracy dots and N / N readout.
showWeightArrowbooleantrueRender the green weight-vector arrow.
transitionTransitionSPRINGS.smoothOverride the boundary-line / arrow spring.
onChange(state) => voidFires whenever any state knob changes.
classNamestringMerged onto the root via cn().

Accessibility

  • The plot SVG is role="img" with an aria-label summarising the current accuracy (Neuron boundary — N of M classified correctly); the count updates live as the user drags.
  • Each slider has a visible label, a numeric live readout, and an aria-label repeating the current value. Sliders are reachable in tab order; the native range input handles keyboard adjustment.
  • The activation toggle uses aria-pressed to convey the selected mode for screen readers.
  • All decorative SVG layers — half-plane wash, glow filters, axis ticks, legend, weight arrow, data points — are aria-hidden, so the canonical reading is the title summary plus slider values.
  • Colour is never the only signal: misclassified points are marked by a pulsing error ring in addition to the warning hue, and the accuracy readout flips to a success colour only when every point is correctly classified.
  • Motion: the boundary line and arrow use a spring (SPRINGS.smooth) that respects Transition overrides; consumers needing fully reduced motion can pass transition={{ duration: 0 }}.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/math/NeuronInline.tsx). The source was wired into the curriculum — it imported SvgLabel from the lesson SVG primitives, hardcoded the eight training points, and tracked progress against the host lesson. The viz extract drops SvgLabel for raw <text> styled via the --cb-* token palette, exposes data so any binary 2D classification task can be plugged in, re-keys every colour from CA's per-track palette to the semantic --cb-accent / --cb-warning / --cb-success / --cb-error / --cb-fg-* family, generalises the spring tuning to SPRINGS.smooth, and removes every lesson-specific prop in favour of a plain onChange callback and a built-in reset that only surfaces once the state diverges from initial.