Showing Values

show() puts a value beside the line that made it, or draws it as a table or a graph

show() puts a value at the end of the line that called it, in the editor. Change the code, and the value beside it changes.

import { show } from "oj"

const f = (x: number) => 3 * x ** 2 - 4 * x + 5
show(f(3.0))                        // 20
const h = 0.0001
show((f(3.0 + h) - f(3.0)) / h)     // 14.0003
show(h, f(3.0), f(3.0 + h))         // several values, one line

Numbers print to six significant figures. Each call also gets a row in the console that names its line (lesson.ts:6); click it to go there.

It is imported, never a global, so a cart that does not import it is exactly as it was, and the browser's own window.print is left alone.

Tables

A plain object, an array, a Map or a Set is drawn as a table under the line:

show({ x1: x1.grad, w1: w1.grad, x2: x2.grad, w2: w2.grad })   // one row, a column each
show([{ name: "ada", hp: 3 }, { name: "bo", hp: 7 }])          // a row per record

A class with its own toString, like Vector2, prints that instead.

Graphs

An object with an inputs array of objects is drawn as a graph, the way micrograd's draw_dot draws one: each input to the left of the value it feeds.

Property What it draws
inputs The objects this one was made from. Required, and what makes it a graph
label The name on its box, when it is a string
op What made it (+, *, tanh), in a small node before its box
Every other number Its values, in the box: for micrograd, data then grad
class Value {
    data: number
    grad = 0
    label: string
    op: string
    inputs: Value[]
    constructor(data: number, label = "", inputs: Value[] = [], op = "") {
        this.data = data; this.label = label; this.inputs = inputs; this.op = op
    }
    // add, mul, tanh, backward ...
}

const L = d.mul(f); L.label = "L"
show(L)

The field names are listed once, under the drawing, in the colour their values are drawn in.

In a loop

Only the latest value per line is kept, and the editor gets one update a frame however many times a line ran, so a show inside useFrame is cheap. It keeps what the value was when show was called: show(o) and then o.backward() shows o before the backward pass.

A line that shows one number frame after frame also draws its recent values as bars after the value, about the last two seconds, scaled from the lowest to the highest. show(Math.sin(t)) in useFrame draws its wave. A number that never changes draws no bars.

Big values are cut down to fit: 50 rows, 20 columns, 60 nodes, with "+N more" for the rest.

Dragging a number

Hold Cmd (Ctrl on Windows and Linux) and drag a number in your code sideways. It moves by its own last decimal place, so 0.01 goes to 0.02 and 20 to 21, and the cart follows as you drag: the values beside your lines change and the stage reacts. Letting go runs the file as it now reads, and one undo puts the number back.

A number the cart reads on every frame (in useFrame, a drawing, a render) takes each new value without restarting, so the cart keeps its state. A number read only when the cart starts runs the cart again at each step. One read in both places changes only its per-frame uses while you drag, and the rest catch up when you let go.

Only a number the code reads drags: one in a type, an enum or a property name stays put.

When a line throws

An error in the cart is drawn in red at the end of the line that threw it, and the values beside your other lines stay as they were when it happened, until the next Run.

When the error stopped the cart (React lost what it was drawing, the cart did not start, or the error comes every frame), the editor runs the cart once more with that line watched, so it can say what the line read when it threw:

return n * board!.score    TypeError: Cannot read properties of null (reading 'score')   board = null   n = 3

That second run starts the cart over, as a Run does, which costs nothing once the cart has stopped. The console does not say the error twice, and nothing else in the editor changes.

An error that leaves the cart running, such as one in a click handler, gets its message alone: running the cart again would throw away its state. A line that reads no names, or a file you have changed since the last Run, gets the message alone too.

Outside the editor

On the cart's own page and in Unity, show draws nothing. It logs a line to the console when what it shows changes, at most once a second for each line of code, and always ends on the latest value, so a show left in a loop does not flood the log.