Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Machine learning

Small, deterministic models whose displayed values are computed rather than staged. The ML examples use progressive focus so forward values, supervised loss, reverse gradients, and parameter updates stay readable on one persistent network.

Each block is the whole file — copy it into x.manic and run manic x.manic (live) or --record out (video).

manic-ml-scalar-to-tensor

Start with one value, extend it into a vector, arrange values into a matrix, then stack channels into a rank-3 tensor. The only ML noun is tensor; ordinary Manic steps, arrows, reveals, and captions tell the complete dimensional story.

// manic-ml-scalar-to-tensor.manic — ML foundation story
// One value gains an axis, then rows, then stacked channels. The ML-specific
// surface is only tensor(...); ordinary Manic verbs own the explanation.

title("Manic ML — From Scalar to Tensor");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Build_the_dimensions safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;
let cell = 38*u;

if h > 1.45*w {
  watermark(manicMark, (w*0.15, h*0.06), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · DATA FOUNDATIONS");
  text(headline, (cx, h*0.105), "One value gains dimensions");
  text(caption, (cx, h*0.84), "Begin with one measured value.");

  tensor(scalar, (cx, h*0.20), "7", cell, gold);
  tensor(vector, (cx, h*0.35), "7 2 -1 4", cell, cyan);
  tensor(matrix, (cx, h*0.53), "7 2 -1; 4 0 3; 1 5 6", cell, magenta);
  tensor(volume, (cx, h*0.72), "7 2 -1; 4 0 3; 1 5 6 | 2 4 8; 1 3 9; 0 5 6", cell, lime);

  text(scalarTitle, (cx, h*0.155), "SCALAR · RANK 0");
  text(vectorTitle, (cx, h*0.295), "VECTOR · RANK 1");
  text(matrixTitle, (cx, h*0.445), "MATRIX · RANK 2");
  text(volumeTitle, (cx, h*0.625), "TENSOR · RANK 3");

  arrow(grow1, (cx, h*0.245), (cx, h*0.285));
  arrow(grow2, (cx, h*0.395), (cx, h*0.435));
  arrow(grow3, (cx, h*0.585), (cx, h*0.615));
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.17, h*0.09), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · DATA FOUNDATIONS");
  text(headline, (cx, h*0.14), "One value gains dimensions");
  text(caption, (cx, h*0.82), "Begin with one measured value.");

  tensor(scalar, (w*0.11, h*0.46), "7", cell, gold);
  tensor(vector, (w*0.34, h*0.46), "7 2 -1 4", cell, cyan);
  tensor(matrix, (w*0.61, h*0.46), "7 2 -1; 4 0 3; 1 5 6", cell, magenta);
  tensor(volume, (w*0.86, h*0.46), "7 2 -1; 4 0 3; 1 5 6 | 2 4 8; 1 3 9; 0 5 6", cell, lime);

  text(scalarTitle, (w*0.11, h*0.34), "SCALAR · RANK 0");
  text(vectorTitle, (w*0.34, h*0.34), "VECTOR · RANK 1");
  text(matrixTitle, (w*0.61, h*0.34), "MATRIX · RANK 2");
  text(volumeTitle, (w*0.86, h*0.34), "TENSOR · RANK 3");

  arrow(grow1, (w*0.17, h*0.46), (w*0.23, h*0.46));
  arrow(grow2, (w*0.44, h*0.46), (w*0.51, h*0.46));
  arrow(grow3, (w*0.70, h*0.46), (w*0.76, h*0.46));
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.06), "MANIC ML · DATA FOUNDATIONS");
  text(headline, (cx, h*0.17), "One value gains dimensions");
  text(caption, (cx, h*0.84), "Begin with one measured value.");

  tensor(scalar, (w*0.24, h*0.34), "7", cell, gold);
  tensor(vector, (w*0.73, h*0.34), "7 2 -1 4", cell, cyan);
  tensor(matrix, (w*0.24, h*0.65), "7 2 -1; 4 0 3; 1 5 6", cell, magenta);
  tensor(volume, (w*0.73, h*0.65), "7 2 -1; 4 0 3; 1 5 6 | 2 4 8; 1 3 9; 0 5 6", cell, lime);

  text(scalarTitle, (w*0.24, h*0.235), "SCALAR · RANK 0");
  text(vectorTitle, (w*0.73, h*0.235), "VECTOR · RANK 1");
  text(matrixTitle, (w*0.24, h*0.505), "MATRIX · RANK 2");
  text(volumeTitle, (w*0.73, h*0.505), "TENSOR · RANK 3");

  arrow(grow1, (w*0.34, h*0.34), (w*0.50, h*0.34));
  arrow(grow2, (w*0.73, h*0.40), (w*0.36, h*0.56));
  arrow(grow3, (w*0.35, h*0.65), (w*0.50, h*0.65));
}

size(kicker, 19*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 34*u); bold(headline); wrap(headline, w*0.82); hidden(headline);
size(caption, 21*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);

size(scalarTitle, 17*u); bold(scalarTitle); color(scalarTitle, dim); hidden(scalarTitle);
size(vectorTitle, 17*u); bold(vectorTitle); color(vectorTitle, dim); hidden(vectorTitle);
size(matrixTitle, 17*u); bold(matrixTitle); color(matrixTitle, dim); hidden(matrixTitle);
size(volumeTitle, 17*u); bold(volumeTitle); color(volumeTitle, dim); hidden(volumeTitle);

color(grow1, dim); stroke(grow1, 2.5*u); hidden(grow1);
color(grow2, dim); stroke(grow2, 2.5*u); hidden(grow2);
color(grow3, dim); stroke(grow3, 2.5*u); hidden(grow3);

hidden(scalar.cells); hidden(scalar.values); hidden(scalar.labels);
hidden(vector.cells); hidden(vector.values); hidden(vector.labels);
hidden(matrix.cells); hidden(matrix.values); hidden(matrix.labels);
hidden(volume.cells); hidden(volume.values); hidden(volume.labels);

step("scalar") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  show(scalarTitle, 0.30);
  par {
    show(scalar.cells, 0.55);
    show(scalar.values, 0.55);
  }
}
wait(0.55);

step("vector") {
  par {
    show(grow1, 0.35);
    show(vectorTitle, 0.30);
    show(vector.cells, 0.60);
    show(vector.values, 0.60);
    say(caption, "Repeat the value along one ordered axis: position now matters.", 0.40);
  }
}
wait(0.60);

step("matrix") {
  par {
    show(grow2, 0.35);
    show(matrixTitle, 0.30);
    show(matrix.cells, 0.65);
    show(matrix.values, 0.65);
    say(caption, "Add rows to the columns: one axis becomes a two-dimensional matrix.", 0.40);
  }
}
wait(0.65);

step("tensor") {
  par {
    show(grow3, 0.35);
    show(volumeTitle, 0.30);
    show(volume.cells, 0.70);
    show(volume.values, 0.70);
    say(caption, "Stack matrices as channels: the same values now carry depth and context.", 0.40);
  }
}
wait(0.75);

step("one-family") {
  pulse(volume.channel1, 0.75);
  say(caption, "Scalar, vector, and matrix are all tensors—distinguished by their axes.", 0.45);
}
wait(1.50);

manic-ml-activation-focus

A focused ReLU lesson: draw the truthful activation curve, test one negative and one positive input, then connect the bend to nonlinearity. activation supplies the mathematics while core Manic owns the probes, guides, equation, and pacing.

// manic-ml-activation-focus.manic — one ML noun, one complete lesson
// `activation` supplies the truthful ReLU curve. Core Manic supplies the
// question, equation, input probes, local emphasis, timing, and takeaway.

title("Manic ML — Why ReLU Changes a Neuron");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=See_the_rule safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.15, h*0.06), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · ACTIVATION");
  text(headline, (cx, h*0.11), "Why does a neuron need ReLU?");
  text(caption, (cx, h*0.79), "A neuron first receives an unrestricted number.");
  equation(rule, (cx, h*0.60), `\operatorname{ReLU}(x)=\max(0,x)`, 35*u);

  activation(reluView, (cx, h*0.38), relu, w*0.74, h*0.22);
  line(negativePath, (w*0.13, h*0.466), (cx, h*0.466));
  line(positivePath, (cx, h*0.466), (w*0.87, h*0.27));
  line(positiveGuide, (w*0.685, h*0.466), (w*0.685, h*0.368));
  circle(negativeProbe, (w*0.315, h*0.466), 8*u);
  circle(positiveProbe, (w*0.685, h*0.368), 8*u);
  text(negativeNote, (w*0.27, h*0.525), "x = −2  →  0");
  text(positiveNote, (w*0.73, h*0.525), "x = 2  →  2");
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.17, h*0.09), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · ACTIVATION");
  text(headline, (cx, h*0.14), "Why does a neuron need ReLU?");
  text(caption, (cx, h*0.82), "A neuron first receives an unrestricted number.");
  equation(rule, (w*0.79, h*0.36), `\operatorname{ReLU}(x)=\max(0,x)`, 34*u);

  activation(reluView, (w*0.38, h*0.49), relu, w*0.52, h*0.48);
  line(negativePath, (w*0.12, h*0.677), (w*0.38, h*0.677));
  line(positivePath, (w*0.38, h*0.677), (w*0.64, h*0.25));
  line(positiveGuide, (w*0.51, h*0.677), (w*0.51, h*0.463));
  circle(negativeProbe, (w*0.25, h*0.677), 8*u);
  circle(positiveProbe, (w*0.51, h*0.463), 8*u);
  text(negativeNote, (w*0.79, h*0.50), "x = −2  →  0");
  text(positiveNote, (w*0.79, h*0.59), "x = 2  →  2");
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.06), "MANIC ML · ACTIVATION");
  text(headline, (cx, h*0.145), "Why does a neuron need ReLU?");
  text(caption, (cx, h*0.82), "A neuron first receives an unrestricted number.");
  equation(rule, (cx, h*0.67), `\operatorname{ReLU}(x)=\max(0,x)`, 34*u);

  activation(reluView, (cx, h*0.40), relu, w*0.72, h*0.28);
  line(negativePath, (w*0.14, h*0.509), (cx, h*0.509));
  line(positivePath, (cx, h*0.509), (w*0.86, h*0.26));
  line(positiveGuide, (w*0.68, h*0.509), (w*0.68, h*0.384));
  circle(negativeProbe, (w*0.32, h*0.509), 8*u);
  circle(positiveProbe, (w*0.68, h*0.384), 8*u);
  text(negativeNote, (w*0.27, h*0.58), "x = −2  →  0");
  text(positiveNote, (w*0.73, h*0.58), "x = 2  →  2");
}

size(kicker, 19*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 34*u); bold(headline); wrap(headline, w*0.82); hidden(headline);
size(caption, 21*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);
hidden(rule);

color(negativePath, magenta); stroke(negativePath, 5*u); glow(negativePath, 0.35); untraced(negativePath);
color(positivePath, cyan); stroke(positivePath, 5*u); glow(positivePath, 0.35); untraced(positivePath);
color(positiveGuide, dim); stroke(positiveGuide, 2*u); dashed(positiveGuide, 9*u, 7*u); untraced(positiveGuide);

color(negativeProbe, magenta); filled(negativeProbe); glow(negativeProbe, 0.55); hidden(negativeProbe);
color(positiveProbe, cyan); filled(positiveProbe); glow(positiveProbe, 0.55); hidden(positiveProbe);
size(negativeNote, 18*u); color(negativeNote, magenta); bold(negativeNote); hidden(negativeNote);
size(positiveNote, 18*u); color(positiveNote, cyan); bold(positiveNote); hidden(positiveNote);

untraced(reluView.axes);
untraced(reluView.curve);
hidden(reluView.label);

step("question") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  draw(reluView.axes, 0.75);
}
wait(0.55);

step("rule") {
  show(rule, 0.55);
  say(caption, "ReLU makes one transparent promise: return the larger of zero and x.", 0.40);
}
wait(0.55);

step("negative-input") {
  par {
    draw(negativePath, 0.75);
    show(negativeProbe, 0.35);
    show(negativeNote, 0.35);
    say(caption, "Negative input is muted at zero; it cannot send negative evidence onward.", 0.40);
  }
}
wait(0.65);

step("positive-input") {
  par {
    draw(positivePath, 0.85);
    draw(positiveGuide, 0.55);
    show(positiveProbe, 0.35);
    show(positiveNote, 0.35);
    say(caption, "Positive input passes through unchanged, preserving its strength.", 0.40);
  }
}
wait(0.70);

step("activation") {
  par {
    draw(reluView.curve, 1.10);
    show(reluView.label, 0.35);
    say(caption, "That small bend gives a network a nonlinear decision boundary.", 0.40);
    par { cam((cx, h*0.47), 0.70, smooth); zoom(1.10, 0.70, smooth); }
  }
}
wait(0.75);

step("takeaway") {
  par {
    pulse(reluView.curve, 0.75);
    say(caption, "ReLU does not invent a signal: it gates what the neuron already computed.", 0.45);
    par { cam((cx, cy), 0.70, smooth); zoom(1.0, 0.70, smooth); }
  }
}
wait(1.50);

manic-ml-forward-pass

A creator-first neural-network story: introduce the ReLU activation, reveal a seeded 3→6→4→3 model, then follow one real forward pass into softmax probabilities. network, activation, and forward provide the truthful structure while ordinary named steps, captions, and Creator branding tell the lesson.

// manic-ml-forward-pass.manic — ML1 creator proof
// A real deterministic network computes one prediction. The story keeps the
// model persistent and reveals only the active computation instead of flashing
// every connection at once.

title("Manic ML — A Forward Pass You Can Follow");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=See_the_computation safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

// One story reflows to portrait, feed, square, and landscape. The portrait
// network narrows to reserve a clean probability lane at the right.
if h > 1.45*w {
  watermark(manicMark, (w*0.18, h*0.075), "Made With Manic");
  text(kicker, (cx, h*0.08), "MANIC ML · FORWARD PASS");
  text(headline, (cx, h*0.13), "How does a network choose?");
  text(caption, (cx, h*0.72), "First, a neuron keeps positive evidence and removes negative evidence.");
  activation(reluView, (cx, h*0.40), relu, w*0.72, h*0.24);
  network(model, (cx, h*0.42), "3 6 4 3", "relu tanh softmax", w*0.55, h*0.32, 21);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.18, h*0.10), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · FORWARD PASS");
  text(headline, (cx, h*0.14), "How does a network choose?");
  text(caption, (cx, h*0.83), "First, a neuron keeps positive evidence and removes negative evidence.");
  activation(reluView, (cx, h*0.49), relu, w*0.42, h*0.36);
  network(model, (cx, h*0.47), "3 6 4 3", "relu tanh softmax", w*0.64, h*0.39, 21);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.07), "MANIC ML · FORWARD PASS");
  text(headline, (cx, h*0.13), "How does a network choose?");
  text(caption, (cx, h*0.82), "First, a neuron keeps positive evidence and removes negative evidence.");
  activation(reluView, (cx, h*0.43), relu, w*0.68, h*0.30);
  network(model, (cx, h*0.45), "3 6 4 3", "relu tanh softmax", w*0.64, h*0.40, 21);
}

size(kicker, 20*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 36*u); bold(headline); hidden(headline);
size(caption, 22*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);

// A truthful ReLU curve introduces the operation used by the hidden layer.
hidden(reluView);
untraced(reluView.axes);
untraced(reluView.curve);

// 3 inputs → 6 ReLU units → 4 tanh units → 3 softmax probabilities.
// Seed 21 makes the educational model reproducible across every render.
hidden(model);

step("activation") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  show(reluView, 0.55);
  draw(reluView.axes, 0.70);
  draw(reluView.curve, 1.20);
}
wait(0.75);

step("meet-the-network") {
  fade(reluView, 0.45);
  show(model, 0.65);
  say(caption, "The same operation now lives inside a small, deterministic network.", 0.45);
}
wait(0.65);

step("forward-pass") {
  par {
    forward(model, "0.15 0.92 0.38", 4.20, smooth);
    say(caption, "Follow the bright path: inputs become evidence, then probabilities.", 0.45);
    seq {
      par { cam((w*0.24, h*0.47), 0.55, smooth); zoom(1.06, 0.55, smooth); }
      wait(0.55);
      cam((cx, h*0.47), 0.80, smooth);
      wait(0.55);
      cam((w*0.76, h*0.47), 0.80, smooth);
      wait(0.40);
      par { cam((cx, cy), 0.55, smooth); zoom(1.0, 0.55, smooth); }
    }
  }
}
wait(0.90);

step("takeaway") {
  pulse(model.output, 0.75);
  say(caption, "The picture is driven by the computed values—not a decorative animation.", 0.45);
}
wait(1.60);

manic-ml-learning-step

One complete supervised learning beat on a persistent network: predict, compare with a target using cross-entropy, send exact reverse-mode gradients backward, update every weight and bias, then restore the exact pre-update checkpoint. loss, backward, checkpoint, update, and restore expose both learning and truthful rollback without pretending that rollback is general machine unlearning.

// manic-ml-learning-step.manic — ML2 creator proof
// One persistent network predicts, measures its mistake, sends exact gradients
// backward, changes its parameters, then rolls that one saved change back.
// No layer is cleared and redrawn; rollback is not claimed as full unlearning.

title("Manic ML — How One Mistake Becomes Learning");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=See_the_learning safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.13, h*0.075), "Made With Manic");
  text(kicker, (cx, h*0.08), "MANIC ML · ONE LEARNING STEP");
  text(headline, (cx, h*0.13), "How does a model learn?");
  text(caption, (cx, h*0.72), "First the network predicts from the current weights.");
  network(model, (cx, h*0.42), "3 6 4 3", "relu tanh softmax", w*0.55, h*0.32, 21);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.18, h*0.10), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · ONE LEARNING STEP");
  text(headline, (cx, h*0.14), "How does a model learn?");
  text(caption, (cx, h*0.83), "First the network predicts from the current weights.");
  network(model, (cx, h*0.47), "3 6 4 3", "relu tanh softmax", w*0.64, h*0.39, 21);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.07), "MANIC ML · ONE LEARNING STEP");
  text(headline, (cx, h*0.13), "How does a model learn?");
  text(caption, (cx, h*0.82), "First the network predicts from the current weights.");
  network(model, (cx, h*0.45), "3 6 4 3", "relu tanh softmax", w*0.64, h*0.40, 21);
}

size(kicker, 20*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 35*u); bold(headline); wrap(headline, w*0.82); hidden(headline);
size(caption, 22*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);
hidden(model);

step("question") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  show(model, 0.65);
}
wait(0.55);

step("predict") {
  par {
    forward(model, "0.15 0.92 0.38", 3.20, smooth);
    say(caption, "A forward pass turns the input into three probabilities.", 0.40);
  }
}
wait(0.55);

step("measure-the-mistake") {
  par {
    loss(model, "1 0 0", crossentropy, 1.50, smooth);
    say(caption, "The correct answer is class 1. Cross-entropy measures the mismatch.", 0.40);
  }
}
wait(0.55);

step("send-credit-backward") {
  par {
    backward(model, 3.20, smooth);
    say(caption, "The gradient carries responsibility backward through the same connections.", 0.40);
    seq {
      par { cam((w*0.76, h*0.47), 0.40, smooth); zoom(1.08, 0.40, smooth); }
      wait(0.30);
      cam((cx, h*0.47), 0.55, smooth);
      wait(0.25);
      cam((w*0.24, h*0.47), 0.55, smooth);
      wait(0.25);
      par { cam((cx, cy), 0.45, smooth); zoom(1.0, 0.45, smooth); }
    }
  }
}
wait(0.55);

// A zero-duration authored checkpoint captures the exact pre-update weights,
// prediction, target, and loss. It does not add a hidden runtime state.
checkpoint(beforeUpdate, model);

step("learn") {
  par {
    update(model, 0.18, 2.30, smooth);
    say(caption, "Each parameter moves opposite its gradient; the same input is computed again.", 0.40);
  }
}
wait(0.70);

step("unlearn") {
  par {
    restore(model, beforeUpdate, 2.30, smooth);
    say(caption, "Exact rollback restores the saved parameters and their earlier prediction.", 0.40);
    seq {
      par { cam((w*0.24, h*0.47), 0.40, smooth); zoom(1.08, 0.40, smooth); }
      wait(0.30);
      cam((cx, h*0.47), 0.55, smooth);
      wait(0.25);
      cam((w*0.76, h*0.47), 0.55, smooth);
      wait(0.25);
      par { cam((cx, cy), 0.45, smooth); zoom(1.0, 0.45, smooth); }
    }
  }
}
wait(0.70);

step("takeaway") {
  pulse(model.output, 0.75);
  say(caption, "This undoes one saved update. Dataset-level unlearning is a different process.", 0.45);
}
wait(1.50);

manic-ml-cnn-edge-story

A tiny image becomes an edge-response feature map and then a pooled summary. The shared scan choreography keeps each receptive field, kernel/operator, arithmetic line, and destination cell synchronized while tensor, kernel, convolve, and pool supply the exact values.

// manic-ml-cnn-edge-story.manic — ML3 creator proof
// A tiny image becomes a feature map and then a pooled summary. Every number is
// computed by Manic; scan coordinates the receptive field and destination.

title("Manic ML — How a CNN Finds an Edge");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=See_the_feature safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;
let cell = 48*u;

if h > 1.45*w {
  watermark(manicMark, (w*0.13, h*0.075), "Made With Manic");
  text(kicker, (cx, h*0.08), "MANIC ML · CONVOLUTION");
  text(headline, (cx, h*0.13), "How does a CNN see edges?");
  text(caption, (cx, h*0.72), "Start with a tiny image: bright cells form a simple shape.");
  tensor(image, (w*0.28, h*0.35), "0 0 0 0 0; 0 0 1 1 0; 0 1 1 1 0; 0 0 1 1 0; 0 0 0 0 0", cell, cyan);
  kernel(edge, (w*0.72, h*0.35), "-1 0 1; -2 0 2; -1 0 1", cell, magenta);
  convolve(feature, image, edge, (w*0.34, h*0.54), 1, 0, 0, relu, cell);
  pool(pooled, feature, (w*0.72, h*0.54), max, 2, 1, 0, cell);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.18, h*0.10), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · CONVOLUTION");
  text(headline, (cx, h*0.14), "How does a CNN see edges?");
  text(caption, (cx, h*0.82), "Start with a tiny image: bright cells form a simple shape.");
  tensor(image, (w*0.17, h*0.47), "0 0 0 0 0; 0 0 1 1 0; 0 1 1 1 0; 0 0 1 1 0; 0 0 0 0 0", cell, cyan);
  kernel(edge, (w*0.42, h*0.47), "-1 0 1; -2 0 2; -1 0 1", cell, magenta);
  convolve(feature, image, edge, (w*0.68, h*0.47), 1, 0, 0, relu, cell);
  pool(pooled, feature, (w*0.89, h*0.47), max, 2, 1, 0, cell);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.07), "MANIC ML · CONVOLUTION");
  text(headline, (cx, h*0.13), "How does a CNN see edges?");
  text(caption, (cx, h*0.82), "Start with a tiny image: bright cells form a simple shape.");
  tensor(image, (w*0.18, h*0.44), "0 0 0 0 0; 0 0 1 1 0; 0 1 1 1 0; 0 0 1 1 0; 0 0 0 0 0", cell, cyan);
  kernel(edge, (w*0.45, h*0.44), "-1 0 1; -2 0 2; -1 0 1", cell, magenta);
  convolve(feature, image, edge, (w*0.70, h*0.44), 1, 0, 0, relu, cell);
  pool(pooled, feature, (w*0.89, h*0.44), max, 2, 1, 0, cell);
}

size(kicker, 20*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 35*u); bold(headline); wrap(headline, w*0.82); hidden(headline);
size(caption, 22*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);
hidden(image); hidden(edge); hidden(feature); hidden(pooled);

step("pixels") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  show(image, 0.65);
}
wait(0.55);

step("edge-detector") {
  show(edge, 0.55);
  say(caption, "This 3×3 kernel compares the left side of each patch with the right.", 0.40);
}
wait(0.55);

step("feature-map") {
  show(feature, 0.50);
  say(caption, "The feature map begins quiet; each destination waits for one receptive field.", 0.40);
}
wait(0.35);

step("convolution-scan") {
  par {
    scan(feature, 4.80, smooth);
    say(caption, "The same kernel slides, multiplies, sums, applies ReLU, and writes one cell.", 0.40);
    seq {
      par { cam((w*0.38, h*0.45), 0.75, smooth); zoom(1.10, 0.75, smooth); }
      wait(2.95);
      par { cam((cx, cy), 0.85, smooth); zoom(1.0, 0.85, smooth); }
    }
  }
}
wait(0.60);

step("pooling-map") {
  show(pooled, 0.50);
  say(caption, "Max pooling asks a simpler question: where is the strongest local evidence?", 0.40);
}
wait(0.40);

step("pooling-scan") {
  par {
    scan(pooled, 3.40, smooth);
    say(caption, "Each 2×2 window keeps its first maximum; ties are deterministic.", 0.40);
  }
}
wait(0.70);

step("takeaway") {
  pulse(pooled.cells, 0.75);
  say(caption, "A CNN builds meaning locally: pixels → feature responses → compact evidence.", 0.45);
}
wait(1.50);

manic-ml-token-embedding

A sentence becomes honest word tokens, stable seeded educational lookup vectors, exact sinusoidal positions, and model-input vectors. Repeated words prove that token identity keeps one base embedding while position distinguishes each occurrence.

// manic-ml-token-embedding.manic — ML5 acceptance story
// A repeated word keeps one seeded educational token embedding, while exact
// sinusoidal position makes each occurrence a different model input.

title("Manic ML — From Words to Positioned Embeddings");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Follow_the_representation safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.16, h*0.055), "Made With Manic");
  text(kicker, (cx, h*0.055), "MANIC ML · EMBEDDINGS");
  text(headline, (cx, h*0.095), "A word needs meaning—and a place");
  text(caption, (cx, h*0.84), "Start with text. Keep every boundary and every number inspectable.");

  tokenize(words, (cx, h*0.19), "the cat chased the cat", word, w*0.80);
  embedding(context, words, (cx, h*0.50), "seeded 6 37", sinusoidal, w*0.90, h*0.48);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.16, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.07), "MANIC ML · EMBEDDINGS");
  text(headline, (cx, h*0.125), "A word needs meaning—and a place");
  text(caption, (cx, h*0.84), "Start with text. Keep every boundary and every number inspectable.");

  tokenize(words, (cx, h*0.23), "the cat chased the cat", word, w*0.68);
  embedding(context, words, (cx, h*0.54), "seeded 6 37", sinusoidal, w*0.90, h*0.48);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.06), "MANIC ML · EMBEDDINGS");
  text(headline, (cx, h*0.17), "A word needs meaning—and a place");
  text(caption, (cx, h*0.83), "Start with text. Keep every boundary and every number inspectable.");

  tokenize(words, (cx, h*0.30), "the cat chased the cat", word, w*0.76);
  embedding(context, words, (cx, h*0.60), "seeded 6 37", sinusoidal, w*0.90, h*0.38);
}

size(kicker, 18*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 32*u); bold(headline); wrap(headline, w*0.84); hidden(headline);
size(caption, 20*u); color(caption, dim); wrap(caption, w*0.82); hidden(caption);
hidden(words);
hidden(context);

step("sentence") {
  show(kicker, 0.30);
  show(headline, 0.42);
  show(words.labels, 0.35);
  show(words.source, 0.40);
  show(caption, 0.35);
}
wait(0.55);

step("tokens") {
  par {
    show(words.tokens, 0.75);
    show(words.indices, 0.75);
    say(caption, "Word tokenization turns the sentence into five ordered identities.", 0.38);
  }
}
wait(0.60);

step("lookup") {
  fade(words, 0.35);
  par {
    show(context.labels, 0.40);
    show(context.tokens, 0.55);
    show(context.vectors, 0.95);
    say(caption, "A seeded educational lookup gives each token identity one six-number vector.", 0.40);
  }
}
wait(0.60);

step("same-word") {
  par {
    pulse(context.row1, 0.70);
    pulse(context.row4, 0.70);
    say(caption, "Both copies of cat reuse the same base embedding. The lookup depends on the token—not its location.", 0.42);
  }
}
wait(0.65);

step("position") {
  par {
    show(context.positions, 1.00);
    show(context.operators, 0.45);
    say(caption, "Sinusoidal position adds a deterministic coordinate for places 0 through 4.", 0.42);
  }
}
wait(0.65);

step("model-input") {
  par {
    show(context.combined, 1.00);
    say(caption, "Token vector plus position becomes the model input. The repeated word now carries two different locations.", 0.42);
  }
}
wait(0.70);

step("takeaway") {
  par {
    pulse(context.row1, 0.72);
    pulse(context.row4, 0.72);
    say(caption, "Meaning says what the token is. Position says where this occurrence belongs.", 0.42);
  }
}
wait(1.40);

manic-ml-transformer-attention

One token finds context through a real scaled dot-product self-attention head. Explicit embeddings become Q/K/V, one selected softmax row drives the weighted value mix and residual, and a deterministic educational output projection produces exact top-k probabilities without pretending to be a pretrained language model.

// manic-ml-transformer-attention.manic — ML4 acceptance story
// Explicit token embeddings become Q/K/V, one query row becomes normalized
// attention weights, values mix, a residual is added, and a real output
// projection produces top-k probabilities.

title("Manic ML — One Transformer Attention Head");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Follow_the_attention safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.15, h*0.06), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · SELF-ATTENTION");
  text(headline, (cx, h*0.105), "One token finds context");
  text(caption, (cx, h*0.84), "Start with explicit token embeddings—not decorative wires.");

  attention(head, (cx, h*0.38), "Art | ificial | intelligence | transforms | business",
    "1 0.2 -0.4 0.7; 0.8 0.1 -0.3 0.6; -0.2 1 0.5 0.3; 0.1 0.6 0.9 -0.2; 0.7 -0.1 0.4 1",
    w*0.82, h*0.40, 23);
  topk(next, head, 3, (cx, h*0.71), "business | work | world | industry | future | people", 4, w*0.72, h*0.18, 29);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.17, h*0.09), "Made With Manic");
  text(kicker, (cx, h*0.075), "MANIC ML · SELF-ATTENTION");
  text(headline, (cx, h*0.14), "One token finds context");
  text(caption, (cx, h*0.83), "Start with explicit token embeddings—not decorative wires.");

  attention(head, (w*0.40, h*0.48), "Art | ificial | intelligence | transforms | business",
    "1 0.2 -0.4 0.7; 0.8 0.1 -0.3 0.6; -0.2 1 0.5 0.3; 0.1 0.6 0.9 -0.2; 0.7 -0.1 0.4 1",
    w*0.68, h*0.58, 23);
  topk(next, head, 3, (w*0.84, h*0.52), "business | work | world | industry | future | people", 4, w*0.26, h*0.34, 29);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.06), "MANIC ML · SELF-ATTENTION");
  text(headline, (cx, h*0.13), "One token finds context");
  text(caption, (cx, h*0.84), "Start with explicit token embeddings—not decorative wires.");

  attention(head, (cx, h*0.39), "Art | ificial | intelligence | transforms | business",
    "1 0.2 -0.4 0.7; 0.8 0.1 -0.3 0.6; -0.2 1 0.5 0.3; 0.1 0.6 0.9 -0.2; 0.7 -0.1 0.4 1",
    w*0.84, h*0.42, 23);
  topk(next, head, 3, (cx, h*0.72), "business | work | world | industry | future | people", 4, w*0.72, h*0.18, 29);
}

size(kicker, 19*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 34*u); bold(headline); wrap(headline, w*0.82); hidden(headline);
size(caption, 21*u); color(caption, dim); wrap(caption, w*0.78); hidden(caption);
hidden(head); hidden(next);

step("tokens") {
  show(kicker, 0.35);
  show(headline, 0.45);
  show(caption, 0.40);
  show(head.labels, 0.40);
  show(head.tokens, 0.60);
}
wait(0.55);

step("projections") {
  par {
    show(head.q, 0.55);
    show(head.k, 0.55);
    show(head.v, 0.55);
    say(caption, "Each embedding is projected into a Query, Key, and Value vector.", 0.40);
  }
}
wait(0.60);

step("scores") {
  show(head.matrix, 0.70);
  say(caption, "Scaled dot products become one softmax row: every weight is positive and the row sums to 100%.", 0.45);
}
wait(0.65);

step("attend") {
  par {
    attend(head, 3, 5.20, smooth);
    say(caption, "Focus intelligence: Q asks, K measures relevance, and weighted V carries the context.", 0.45);
    seq {
      par { cam((cx, h*0.46), 0.75, smooth); zoom(1.07, 0.75, smooth); }
      wait(3.45);
      par { cam((cx, cy), 0.85, smooth); zoom(1.0, 0.85, smooth); }
    }
  }
}
wait(0.75);

step("prediction") {
  show(next, 0.70);
  say(caption, "The residual plus attention mix enters an output projection and a truthful softmax ranking.", 0.45);
}
wait(0.80);

step("takeaway") {
  pulse(next.rank0, 0.75);
  say(caption, "Attention is selective information flow—not every connection shouting at once.", 0.45);
}
wait(1.50);

manic-ml-transformer-block

One persistent token lane crosses a complete deterministic transformer block: two causal attention heads, concatenation and output projection, both residual/norm stages, a GELU MLP, and exact settled outputs. transformer owns the computation while encode provides a smooth directly seekable explanation.

// manic-ml-transformer-block.manic — ML6 acceptance story
// One persistent token lane passes through multi-head causal attention,
// concatenation, two residual paths, pre-normalization, and a GELU MLP.

title("Manic ML — Inside One Transformer Block");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Follow_the_computation safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.15, h*0.06), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · TRANSFORMER BLOCK");
  text(headline, (cx, h*0.105), "Inside one transformer block");
  text(caption, (cx, h*0.84), "Follow one token lane through every computed stage.");

  tokenize(words, (cx, h*0.15), "the cat slept because it dreamed", word, w*0.82);
  embedding(context, words, (cx, h*0.41), "seeded 6 37", sinusoidal, w*0.90, h*0.38);
  transformer(block, context, (cx, h*0.49), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.90, h*0.56);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.17, h*0.09), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · TRANSFORMER BLOCK");
  text(headline, (cx, h*0.14), "Inside one transformer block");
  text(caption, (cx, h*0.82), "Follow one token lane through every computed stage.");

  tokenize(words, (cx, h*0.22), "the cat slept because it dreamed", word, w*0.72);
  embedding(context, words, (cx, h*0.54), "seeded 6 37", sinusoidal, w*0.90, h*0.48);
  transformer(block, context, (cx, h*0.52), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.92, h*0.62);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.06), "MANIC ML · TRANSFORMER BLOCK");
  text(headline, (cx, h*0.13), "Inside one transformer block");
  text(caption, (cx, h*0.83), "Follow one token lane through every computed stage.");

  tokenize(words, (cx, h*0.23), "the cat slept because it dreamed", word, w*0.78);
  embedding(context, words, (cx, h*0.52), "seeded 6 37", sinusoidal, w*0.90, h*0.44);
  transformer(block, context, (cx, h*0.52), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.90, h*0.57);
}

size(kicker, 18*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 30*u); bold(headline); wrap(headline, w*0.86); hidden(headline);
size(caption, 19*u); color(caption, dim); wrap(caption, w*0.84); hidden(caption);
hidden(words);
hidden(context);
hidden(block);

step("tokens") {
  par {
    show(kicker, 0.28);
    show(headline, 0.42);
    show(words.labels, 0.30);
    show(words.source, 0.36);
    show(words.tokens, 0.70);
    show(words.indices, 0.70);
    show(caption, 0.32);
    say(caption, "Six ordered tokens begin as one persistent lane.", 0.36);
  }
}
wait(0.55);

step("model-input") {
  seq {
    fade(words, 0.32);
    par {
      show(context.labels, 0.32);
      show(context.tokens, 0.42);
      show(context.vectors, 0.82);
      say(caption, "Each identity receives a stable lookup vector.", 0.36);
    }
    par {
      show(context.positions, 0.72);
      show(context.operators, 0.34);
      show(context.combined, 0.78);
      say(caption, "Position is added exactly. These six vectors are the block input.", 0.38);
    }
  }
}
wait(0.60);

step("encode") {
  seq {
    par {
      fade(context, 0.34);
      fade(caption, 0.24);
    }
    par {
      encode(block, 6.2, smooth);
      seq {
        par { cam((cx - w*0.25, h*0.52), 0.75, smooth); zoom(1.08, 0.75, smooth); }
        wait(1.35);
        cam((cx + w*0.17, h*0.52), 1.15, smooth);
        wait(1.50);
        par { cam((cx, cy), 0.85, smooth); zoom(1.0, 0.85, smooth); }
      }
    }
  }
}
wait(0.70);

step("takeaway") {
  seq {
    show(caption, 0.20);
    par {
      pulse(block.residual1, 0.72);
      pulse(block.residual2, 0.72);
      pulse(block.output, 0.72);
      say(caption, "Attention shares context. The MLP reshapes each token. Residuals keep its identity continuous.", 0.42);
    }
  }
}
wait(1.35);

manic-ml-logits-sampling

The same educational LM projection is viewed at low and high temperature before greedy and top-p decoding make their support explicit. logits computes every candidate from the final hidden row; sample filters, renormalizes, and selects one reproducible next token without pretending to run a pretrained model.

// manic-ml-logits-sampling.manic — ML7 acceptance story
// The same LM projection is viewed at two temperatures, then top-p sampling
// filters, renormalizes, and makes one reproducible next-token choice.

title("Manic ML — How a Transformer Chooses the Next Token");
canvas("16:9");
template("mono");

creator(me, "@anish2good name=Manic_ML tagline=Models_made_visible yt=zarigatongy x=@anish2good web=8gwifi.org/manic accent=cyan secondary=magenta footer=compact cta=Follow_the_computation safe=clean");
socials(me);

let u = (w+h-abs(w-h))/1440;

if h > 1.45*w {
  watermark(manicMark, (w*0.15, h*0.06), "Made With Manic");
  text(kicker, (cx, h*0.07), "MANIC ML · LOGITS → PROBABILITIES → TOKEN");
  text(headline, (cx, h*0.115), "How does a transformer choose its next word?");
  text(caption, (cx, h*0.83), "One hidden vector. One full distribution. One reproducible choice.");

  tokenize(words, (cx, h*0.17), "the model learned to", word, w*0.78);
  embedding(context, words, (cx, h*0.42), "seeded 6 37", sinusoidal, w*0.88, h*0.34);
  transformer(block, context, (cx, h*0.47), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.90, h*0.50);
  logits(cool, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 0.55, w*0.86, h*0.54, 73);
  logits(warm, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 1.45, w*0.86, h*0.54, 73);
}
else if w > 1.25*h {
  watermark(manicMark, (w*0.17, h*0.09), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · LOGITS → PROBABILITIES → TOKEN");
  text(headline, (cx, h*0.13), "How does a transformer choose its next word?");
  text(caption, (cx, h*0.82), "One hidden vector. One full distribution. One reproducible choice.");

  tokenize(words, (cx, h*0.21), "the model learned to", word, w*0.64);
  embedding(context, words, (cx, h*0.50), "seeded 6 37", sinusoidal, w*0.88, h*0.42);
  transformer(block, context, (cx, h*0.50), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.90, h*0.58);
  logits(cool, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 0.55, w*0.78, h*0.54, 73);
  logits(warm, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 1.45, w*0.78, h*0.54, 73);
}
else {
  watermark(manicMark, (w*0.18, h*0.08), "Made With Manic");
  text(kicker, (cx, h*0.065), "MANIC ML · LOGITS → PROBABILITIES → TOKEN");
  text(headline, (cx, h*0.155), "How does a transformer choose its next word?");
  text(caption, (cx, h*0.82), "One hidden vector. One full distribution. One reproducible choice.");

  tokenize(words, (cx, h*0.21), "the model learned to", word, w*0.70);
  embedding(context, words, (cx, h*0.50), "seeded 6 37", sinusoidal, w*0.88, h*0.40);
  transformer(block, context, (cx, h*0.50), "heads=2 mask=causal mlp=12 activation=gelu norm=pre dropout=0 mode=inference seed=41", w*0.90, h*0.55);
  logits(cool, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 0.55, w*0.82, h*0.54, 73);
  logits(warm, block, 4, (cx, h*0.51), "reason | predict | learn | adapt | explain | .", 1.45, w*0.82, h*0.54, 73);
}

size(kicker, 17*u); color(kicker, dim); bold(kicker); hidden(kicker);
size(headline, 29*u); bold(headline); wrap(headline, w*0.88); hidden(headline);
size(caption, 18*u); color(caption, dim); wrap(caption, w*0.86); hidden(caption);
hidden(words);
hidden(context);
hidden(block);
hidden(cool);
hidden(warm);

step("prompt") {
  par {
    show(kicker, 0.28);
    show(headline, 0.42);
    show(words.labels, 0.28);
    show(words.source, 0.34);
    show(words.tokens, 0.62);
    show(words.indices, 0.62);
    show(caption, 0.28);
    say(caption, "The prompt becomes an ordered token lane.", 0.34);
  }
}
wait(0.45);

step("hidden-state") {
  seq {
    fade(words, 0.28);
    par {
      show(block.output, 0.70);
      show(block.labels, 0.26);
      say(caption, "The transformer MLP ends at a hidden representation—not probabilities.", 0.40);
    }
    pulse(block.output, 0.72);
  }
}
wait(0.45);

step("cool-temperature") {
  seq {
    fade(block, 0.30);
    sample(cool, "greedy", 3.4, smooth);
    say(caption, "Low temperature sharpens every candidate. Greedy keeps only the maximum.", 0.42);
  }
}
wait(0.65);

step("warm-temperature") {
  seq {
    fade(cool, 0.30);
    sample(warm, "top-p 0.90 seed=17", 3.8, smooth);
    say(caption, "Higher temperature spreads the full softmax. Top-p keeps the smallest 90% nucleus, renormalizes it, then samples.", 0.46);
  }
}
wait(0.75);

step("takeaway") {
  par {
    pulse(warm.temperature, 0.70);
    pulse(warm.probabilities, 0.70);
    say(caption, "Temperature reshapes probability. Sampling turns that distribution into one reproducible next token.", 0.44);
  }
}
wait(1.30);