Generated from the vocabulary (npm run forth -- --words > forth/WORDS.md). In the REPL: ? lists words, help <word> shows one. Numbers are float32; true is -1, false is 0; a 4-D vector is four floats on the stack (x y z w).
| Word | Stack | Does |
|---|---|---|
+ | ( a b -- a+b ) | add |
- | ( a b -- a-b ) | subtract |
* | ( a b -- a*b ) | multiply |
/ | ( a b -- a/b ) | divide (float) |
mod | ( a b -- a%b ) | remainder |
min | ( a b -- m ) | smaller of two |
max | ( a b -- m ) | larger of two |
atan2 | ( y x -- rad ) | angle of the point (x, y) |
negate | ( a -- -a ) | change sign |
abs | ( a -- |a| ) | absolute value |
sqrt | ( a -- r ) | square root |
sin | ( rad -- s ) | sine |
cos | ( rad -- c ) | cosine |
floor | ( a -- n ) | round down |
1+ | ( a -- a+1 ) | increment |
1- | ( a -- a-1 ) | decrement |
2* | ( a -- 2a ) | double |
2/ | ( a -- a/2 ) | halve |
pi | ( -- 3.14159 ) | the constant pi |
dup | ( a -- a a ) | duplicate the top |
drop | ( a -- ) | discard the top |
swap | ( a b -- b a ) | exchange the top two |
over | ( a b -- a b a ) | copy the second item |
rot | ( a b c -- b c a ) | rotate the third item to the top |
-rot | ( a b c -- c a b ) | rotate the top item to third |
nip | ( a b -- b ) | drop the second item |
2dup | ( a b -- a b a b ) | duplicate the top pair |
2drop | ( a b -- ) | discard the top pair |
2swap | ( a b c d -- c d a b ) | exchange the top two pairs |
depth | ( -- n ) | number of items on the stack |
= | ( a b -- f ) | equal (true = -1, false = 0) |
<> | ( a b -- f ) | not equal |
< | ( a b -- f ) | less than |
> | ( a b -- f ) | greater than |
<= | ( a b -- f ) | less or equal |
>= | ( a b -- f ) | greater or equal |
0= | ( a -- f ) | is zero |
0< | ( a -- f ) | is negative |
and | ( a b -- a&b ) | bitwise and (int32) |
or | ( a b -- a|b ) | bitwise or (int32) |
xor | ( a b -- a^b ) | bitwise xor (int32) |
invert | ( a -- ~a ) | bitwise not (int32) |
true | ( -- -1 ) | the true flag |
false | ( -- 0 ) | the false flag |
assert | ( f -- ) | error "assertion failed" when f is 0 (used by ci/smoke.fs) |
near | ( a b eps -- f ) | true when |a-b| <= eps |
if | ( f -- ) | run the next part when f is not 0 (inside : definitions) |
else | ( -- ) | alternative branch of if |
then | ( -- ) | end of if |
begin | ( -- ) | start of a begin..until/again/while loop |
until | ( f -- ) | loop back to begin until f is not 0 |
again | ( -- ) | loop back to begin forever (the watchdog ends it) |
while | ( f -- ) | leave the begin..repeat loop when f is 0 |
repeat | ( -- ) | end of begin..while..repeat |
do | ( limit start -- ) | counted loop (runs at least once) |
loop | ( -- ) | end of do, step 1 |
+loop | ( n -- ) | end of do, step n |
i | ( -- n ) | index of the innermost do loop |
j | ( -- n ) | index of the next outer do loop |
; | ( -- ) | end a : definition; redefining an existing word replaces its body in place, so callers see the change |
: | ( -- ) name | start a definition: : square dup * ; |
[ | ( -- ) | switch to interpreting inside a definition |
] | ( -- ) | back to compiling |
literal | ( x -- ) | compile x as a literal: [ 2 3 + ] literal |
immediate | ( -- ) | make the last definition run at compile time |
' | ( -- xt ) name | push the execution token of a word |
['] | ( -- ) name | compile the execution token of a word as a literal |
execute | ( xt -- ) | run the word with this token |
see | ( -- ) name | decompile a word from its threaded code: see sq |
variable | ( -- ) name | define a variable; the name pushes its address |
create | ( -- ) name | define a name that pushes the next free cell address; fill with , |
, | ( x -- ) | store x in the next free cell |
constant | ( x -- ) name | define a constant |
v4 | ( x y z w -- ) name | define a named 4-D vector; the name pushes its 4 floats |
@ | ( addr -- x ) | fetch a variable |
! | ( x addr -- ) | store into a variable |
+! | ( x addr -- ) | add into a variable |
. | ( a -- ) | print and drop |
.s | ( -- ) | print the stack, bottom first |
cr | ( -- ) | newline |
space | ( -- ) | print a space |
." | ( -- ) text" | print text up to the closing quote: ." hello" |
words ? | ( -- ) | list every word |
help | ( -- ) name | one-line help: help rotxw |
time | ( -- s ) | seconds since the scene started (frozen in reduced-motion) |
time! | ( s -- ) | set the clock (CLI, tests, brand marks) |
mouse | ( -- mx my ) | pointer relative to the hero, -0.5 .. 0.5 (0 0 when absent) |
view | ( -- left top right bottom ) | the visible area in scene units, origin at the hero centre |
reduced | ( -- f ) | true under prefers-reduced-motion |
nodes | ( -- n ) | topology: number of nodes (boards, head, mini, switch) from scene/topology.json |
links | ( -- n ) | topology: number of links |
link@ | ( j -- a b ) | topology: node indices joined by link j |
role@ | ( i -- r ) | topology: role of node i: 0 board, 1 head, 2 mini, 3 switch |
boards | ( -- n ) | topology: number of boards (nodes whose role is board) |
zoom | ( eye -- ) | move the camera to this distance over 0.4 s, easing out (1500 at rest; 380 flies into the inner cell) |
eye | ( -- d ) | current camera distance |
zoomed | ( -- f ) | true when the camera is flying to, or sits at, a close distance (eye target below 1000) |
pointer | ( -- x y ) | the pointer (mouse, or the last tap) in scene units around the hero centre; 100000 100000 when there is none |
label | ( x y i -- ) | write the 2-letter role glyph of topology node i at (x, y): B1 .. B7, HD head, MN mini, SW switch |
gpu@ | ( i -- gb ) | topology: memory class in GB of node i (0 for non-boards) |
rgb | ( r g b -- ) | set the stroke colour, 0..255 |
alpha | ( a -- ) | set the stroke opacity, 0..1 |
width | ( w -- ) | set the line width |
offset | ( dx dy -- ) | translate everything drawn next (the chromatic split uses it) |
line | ( x1 y1 x2 y2 -- ) | draw a segment |
moveto | ( x y -- ) | set the pen |
lineto | ( x y -- ) | draw from the pen to (x, y) and move the pen there |
disc | ( x y r -- ) | draw a filled dot of radius r |
tag | ( x y -- ) text | write a small label at (x, y): 12 40 tag U_VEC |
cls | ( -- ) | clear what the REPL drew |
gfx-reset | ( -- ) | reset colour, alpha, width, offset and the draw statistics |
nlines | ( -- n ) | segments drawn since gfx-reset |
ndots | ( -- n ) | dots drawn since gfx-reset |
gbounds | ( -- x0 y0 x1 y1 ) | bounding box of everything drawn since gfx-reset |
gsum | ( -- s ) | sum of all drawn coordinates (a checksum for ci/smoke.fs) |
rotxy | ( angle -- ) | set the xy-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rotxz | ( angle -- ) | set the xz-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rotxw | ( angle -- ) | set the xw-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rotyz | ( angle -- ) | set the yz-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rotyw | ( angle -- ) | set the yw-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rotzw | ( angle -- ) | set the zw-plane angle of the 4-D rotor, radians (absolute, not cumulative) |
rot0 | ( -- ) | reset the rotor to identity |
rotate | ( x y z w -- x y z w ) | apply the rotor to a 4-D vector |
mat | ( -- m00 .. m33 ) | push the 16 entries of the rotor, row-major |
v* | ( x y z w k -- x y z w ) | scale a 4-D vector |
proj | ( x y z w -- x y z ) | perspective 4-D to 3-D along w, distance 1500 |
proj3 | ( x y z -- sx sy ) | 3-D to 2-D with the scene rotateX(-25) rotateY(45), perspective 1500 |
tess | ( -- v0 .. v15 ) | the 16 vertices (x y z w) of a unit tesseract, +-1/2, turned by the rotor |
tessn | ( n -- v0 .. v15 ) | the same, with edge length n |
edges | ( -- a0 b0 .. a31 b31 ) | the 32 edges as vertex index pairs |
draw | ( v0 .. v15 n -- ) | scale 16 vertices by n, project 4-D to 3-D to 2-D and draw the 32 edges |
cube | ( -- v0 .. v7 ) | the 8 vertices (x y z) of a unit cube (the tesseract's w = 0 section), turned by the rotor |
draw3 | ( v0 .. v7 n -- ) | scale 8 cube vertices by n, project 3-D to 2-D and draw the 12 edges (the brand mark) |
dot | ( a0 a1 a2 a3 b0 b1 b2 b3 -- d ) | 4-D dot product |
norm | ( x y z w -- n ) | length of a 4-D vector |
inference ƒ | ( a b -- y ) | a tiny fixed 2-16-1 ReLU perceptron, weights baked in: y ~ hypot(a, b) within 1 % |
Rotor (rotxy rotxz rotxw rotyz rotyw rotzw, rot0, rotate, mat). R^4 has six rotation planes. A rotation by theta in the (a, b) plane is the identity except on those two axes, where it is the Givens matrix [[cos t, -sin t], [sin t, cos t]]. The rotor is the product G_zw G_yw G_yz G_xw G_xz G_xy (xy applied first); each word sets one plane's angle absolutely, so time rotxw is a clean animation. The 4x4 product is rebuilt on every set.
Perspective (proj). The eye sits at w = D, D = 1500 (the page's CSS perspective). A 4-D point maps to 3-D by f = D / (D - w), (x, y, z) <- f (x, y, z). Points with w = 0 are unchanged.
Scene projection (proj3). The 3-D point is turned by the scene rotation M = Rx(-25 deg) Ry(45 deg) (the order and signs of RetroHypercube's rotateX(-25deg) rotateY(45deg); y points down) and projected by f = D / (D - z'), giving screen (x' f, y' f). brand/src/mkmark.py used exactly this; the tests hold the new code to its numbers within 1e-3.
Tesseract (tess tessn edges draw). Schlaefli {4,3,3}: the 16 vertices are all sign choices (+-1/2)^4, vertex i taking its x, y, z, w sign from bits 0..3 of i. Two vertices share an edge when they differ in exactly one bit (Hamming distance 1): 16 * 4 / 2 = 32 edges, listed in the order i < j. It has 8 cubic cells: fixing one coordinate to +-1/2 gives a cube. Its dual is the 16-cell (8 vertices +-e_i, 24 edges). cube / draw3 use the w = 0 section (a cube of the same size, the brand mark's nested cells); draw runs 4-D, then proj, then proj3.
Nested cells (scene/cells.fs). Sizes 160, 110, 70, 35 and turn periods 10, 15, 20, 25 s; cell i turns by 2 pi t / period_i.
inference. A 2-16-1 ReLU perceptron: hidden unit k computes max(0, a cos t_k + b sin t_k), t_k = k * 22.5 deg, and the output is 0.197 times their sum. The sum equals r * S(phi) with S within +-1 % of a constant, so the net approximates hypot(a, b). The weights were set analytically, not trained.
Topology (scene/hero.fs). node i of n sits on a Fibonacci sphere: z = 1 - (2i+1)/n, r = sqrt(1 - z^2), phi = i * 2.39996 (the golden angle); the vertex (r cos phi, r sin phi, z, 0) is scaled, rotated by the inner cell's rotor and projected like any other 4-vector. Memory class sets the dot radius.
: starts a definition; every word compiles to a cell of a threaded code array (an execution token, or a literal / branch with its operand cell). ; appends exit. see name decompiles it.if else then begin until again while repeat do loop +loop ; [ literal and user words marked immediate) run at compile time. [ ... ] interprets inside a definition; literal compiles the result.+ - * / mod min max atan2 negate abs sqrt sin cos floor 1+ 1- 2* 2/) applied to adjacent literals are evaluated while compiling, so : k 2 3 + ; compiles to 5. Folding never crosses a branch target.