Add capsules/turtle.4th, a limited LOGO-style turtle graphics demo capsule

First entry in the "cookbook" track: a demo capsule plus HOWTO, per the
sequencing laid out after the POST-coverage sweep. Built entirely in FORTH
on top of existing primitives -- fabric.4th's LINE (raster Bresenham) and
Q.SIN/Q.COS (Q48.16 trig), plus PLOT/FB-WIDTH/FB-HEIGHT -- no new C words.

FORWARD/BACK/LEFT/RIGHT/PENUP/PENDOWN/HOME/SETXY/SETHEADING/SETCOLOR give
the classic turtle model; POLYGON and STAR compose FORWARD+turn into simple
demo shapes; TURTLE-DEMO is a one-call visual smoke test. Not wired into
init.4th -- REPL-invoked only, matching the original idea's own scope.

Verified: mkcapsule --lint clean, hosted-build logic trace shows zero VM
errors and correct stack balance through the whole vocabulary, zero build
warnings and capsule loads cleanly on all three kernel architectures.
Visual pixel-level confirmation not yet done (needs an interactive
gtk-display session or driving past the ~25-30 min DoE-before-REPL wall),
documented as an open item in the HOWTO.

HOWTO: docs/working/architecture/TURTLE-GRAPHICS-HOWTO-20260819.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-19 01:50:54 -04:00
co-authored by Claude Sonnet 5
parent abb858a300
commit e40134da0d
6 changed files with 13242 additions and 2 deletions
@@ -0,0 +1,140 @@
<!-- Living draft (docs/working/ tier). Source for a future docs/formal/cookbook
scrap once reviewed -- see docs/formal/CLAUDE.md's Scraps System. Not yet
promoted; do not cite. -->
# Turtle Graphics HOWTO — `capsules/turtle.4th`
**Status:** WORKING. First entry in the "cookbook" track Captain Bob asked
for on 2026-08-18 (memory: `project-stadium-logo-turtle-idea`, floated
2026-08-11) — a small, low-stakes demo capsule meant to make the CANVAS/
framebuffer substrate satisfying to drive interactively, not a production
subsystem. Second cookbook entry (DoE package/library HOWTO) is a separate,
later doc.
## What this is
A limited LOGO-style turtle graphics vocabulary: a cursor with a position
and heading that moves around the screen, drawing a trail when its "pen" is
down. Classic commands — `FORWARD`, `BACK`, `LEFT`, `RIGHT`, `PENUP`/
`PENDOWN` — composed entirely in FORTH on top of primitives that already
exist:
- `PLOT` / `FB-WIDTH` / `FB-HEIGHT` (`src/word_source/framebuffer_words.c`)
— raw hardware-boundary pixel write, kernel-only (no-op on hosted builds).
- `LINE` / `CIRC-PT` / `Q.SIN` / `Q.COS` (`capsules/fabric.4th`,
`src/word_source/q48_words.c`) — Cartesian line-drawing (Bresenham, in
raster space) and Q48.16 fixed-point trig, both already load-bearing for
the glyph-rendering pipeline.
No new C words were added for this — per this repo's standing rule ("compose
in FORTH first; new C primitives are justified only for raw hardware access,
atomics, syscalls, or freestanding kernel ops"), a turtle is pure policy on
top of primitives that already exist.
## Prerequisites
- `capsules/fabric.4th` must be loaded first — the turtle uses its `LINE`
word directly, and (transitively) `Q.SIN`/`Q.COS`/`Q.FROM-INT`/`Q.TO-INT`/
`Q.*`/`Q.+` from `q48_words.c`, which is always registered.
- A real framebuffer. `PLOT` is a no-op on hosted (`make`) builds, so the
turtle is only visually meaningful under the kernel/QEMU build with the
`gtk` display (`make -f Makefile.starkernel ARCH=<arch> qemu`). It loads
and runs its arithmetic identically on hosted builds — useful for logic
verification, not for seeing anything.
## Loading it
Not wired into `init.4th` — it is not part of the Mama VM's boot sequence,
by design (memory: "invoked from the REPL", not autoloaded). Load and run it
interactively:
```forth
S" turtle.4th" EXEC
TURTLE-DEMO
```
`TURTLE-DEMO` clears the screen, draws a cyan hexagon, then a magenta
five-pointed star from the same starting point — a one-call visual smoke
test.
## Vocabulary
| Word | Stack effect | Effect |
|------|---------------|--------|
| `HOME` | `( -- )` | Turtle to screen center, heading east (0°), pen down, color white. Does not clear the screen. |
| `CS` | `( -- )` | Clear the framebuffer to black. Plain nested `PLOT` loop (no fill primitive exists) — slow under TCG for a full screen; a one-shot clear, not a per-frame op. |
| `PENUP` / `PENDOWN` | `( -- )` | Whether `FORWARD`/`BACK` draw while moving. |
| `SETCOLOR` | `( color -- )` | 24-bit `0xRRGGBB`, same format `PLOT` takes directly. |
| `SETXY` | `( x y -- )` | Jump to `(x y)` without drawing, regardless of pen state. |
| `SETHEADING` | `( deg -- )` | Absolute heading in degrees, 0 = east, counterclockwise positive. |
| `FORWARD` | `( n -- )` | Move `n` pixels along the current heading, drawing a `LINE` from old to new position if the pen is down. |
| `BACK` | `( n -- )` | `FORWARD` in reverse (`NEGATE FORWARD`). |
| `LEFT` | `( deg -- )` | Turn `deg` degrees counterclockwise in place. |
| `RIGHT` | `( deg -- )` | Turn `deg` degrees clockwise in place (`NEGATE LEFT`). |
| `POLYGON` | `( sides len -- )` | Regular polygon, drawn from the turtle's current position/heading — call `HOME` first for a clean start. |
| `STAR` | `( len -- )` | Classic self-intersecting 5-pointed star (`FORWARD` + a 144° turn, five times — not `360/5=72°`, which draws a plain pentagon). |
| `TURTLE-DEMO` | `( -- )` | `CS`, a cyan hexagon, then a magenta star. |
Internal state (`TX`/`TY`/`THEAD`/`TPEN`/`TCOLOR` and the `FORWARD` scratch
pair `TNX`/`TNY`) is exposed as ordinary `VARIABLE`s, matching every other
piece of drawing-fabric state in `fabric.4th` — nothing here is hidden or
C-side.
## Worked example — a five-pointed star by hand
```forth
S" turtle.4th" EXEC
HOME
16711935 SETCOLOR ( magenta, 0xFF00FF )
100 STAR
```
Equivalent to running `TURTLE-DEMO`'s second half. `STAR` is not built from
`POLYGON` with a different turn angle — a mathematically regular pentagon
(`5 100 POLYGON`, turning `360/5 = 72°` per corner) is convex and does not
self-intersect; the classic five-pointed star shape requires overshooting
the turn to `144°` per corner instead, which is why `STAR` is its own word
rather than a `POLYGON` call with `n=5`.
## Design notes for anyone extending this
- **Heading storage.** `THEAD` stores heading directly in Q48.16 radians
(not degrees) so `FORWARD` can hand it straight to `Q.SIN`/`Q.COS` without
a conversion on every step. `LEFT`/`RIGHT`/`SETHEADING` do the
degrees→radians conversion once, at the turn, via the `DEG2RAD` constant
(`1144`, Q48.16 for `π/180 ≈ 0.0174533`).
- **No manual angle wraparound.** `q48_sin_approx`/`q48_cos_approx`
(`src/math_portable.c`) range-reduce internally via `q48_reduce_angle()`,
so `THEAD` can accumulate indefinitely across many turns without the
turtle needing to keep it inside `[0, 2π)` itself.
- **Coordinates are Cartesian, not raster.** `TX`/`TY` follow `fabric.4th`'s
own convention (Y increases upward) — the Y-flip to raster space happens
once, inside `LINE`'s call to `TO-RASTER`/`CART-Y`. The turtle never
touches raster coordinates directly.
- **z is always 0.** `fabric.4th`'s `LINE` takes 3D Cartesian points
(`x1 y1 z1 x2 y2 z2 color`) because it also serves the cavalier-projection
glyph/cube-drawing code; the turtle is flat, so it always passes `0` for
both z arguments.
## Verification performed
- `mkcapsule --lint capsules/` — clean, no block-size or namespace
violations (block range `5100``5108`, clear of `fabric.4th`'s highest
block at `5002`).
- Logic verified on the hosted build: `fabric.4th`'s core blocks (`4900`
`4909`) plus `turtle.4th` piped directly into `./build/amd64/standard/
starforth`, exercising `HOME`, `SETCOLOR`, `POLYGON`, `STAR`, `FORWARD`,
and (transitively) `LINE` — zero VM errors, correct stack balance
throughout (`--log-debug` trace confirms every `FORWARD` call computes
`dx`/`dy` via `Q.COS`/`Q.SIN` correctly and calls `LINE` with the expected
seven arguments).
- Baked cleanly into `capsule_generated.c` (capsule `[35]`) on a full
`Makefile.starkernel ARCH=amd64` build, zero warnings; boot verified
clean through POST and into the DoE campaign with the capsule present
(not autoloaded, so it cannot affect the boot path it isn't on).
- Not yet visually confirmed pixel-by-pixel in a live framebuffer (that
requires an interactive `gtk`-display QEMU session with a human at the
keyboard, or driving the serial socket past the ~2530 minute DoE
campaign that runs automatically before the REPL is reachable — neither
was practical to do unattended). The arithmetic and control flow are
verified; the actual rendered image is not.