# MUD64 Specification

> **Companion spec to [MUD-SPEC v0.1](MUD-SPEC.md)** · Team DC · FutureVision Labs  
> **Inspired by:** [Microtext 2.6 for Commodore 64](https://weaselsworld.com/microtext-2-6/) (NPL / Ariadne, frame-based dialogues)  
> **Canonical web player:** [mud64-player.html](mud64-player.html)

**File extension:** still `.mud` — screen modules are MarkUpDown documents with `::: screen-module` and `::: frame` fences.

**Tagline:** *Document the screens. Flip the story. Export to silicon.*

---

## 1. Why MUD64?

[Microtext](https://weaselsworld.com/microtext-2-6/) proved that **numbered frames + branch addresses** make text adventures and training modules approachable on the C64. Authors think in flowcharts; the runtime thinks in linked screens.

MUD64 brings that model into **MarkUpDown** so you can:

1. **Author** flip-screens and text adventures in plain `.mud` in Code Designer
2. **Preview** in a CRT browser player (no hardware required)
3. **Export** Microtext-compatible module text for real C64 / emulators via [homebrewz.live](https://homebrewz.live)
4. **Publish** HTML docs + playable embed on the same source file

Uses the same `:::`` / `++` split as **MUD-SPEC** (core MarkUpDown):

| Family | Syntax | Purpose |
|--------|--------|---------|
| Presentation | `:::` | Frames, module meta, docs, embeds |
| Execution | `++` | Microtext export, SID hooks, build manifest |

---

## 2. Mental model (Microtext parity)

| Microtext concept | MUD64 equivalent |
|-------------------|----------------------|
| Module (`.STA`) | `::: screen-module` + `++ screen.export` |
| Frame `*5` | `::: frame id=5` |
| Screen text | `text:` body (multiline) |
| `?` prompt (text) | `prompt: text` |
| `!` prompt (single key) | `prompt: key` |
| `FLY=10, SPARROW=15, =20` | `branches:` block or inline |
| `$END` | `end: true` on final frame |
| `$NOTE`, `$VOICE` | `sound:` / `cmd:` lines (export passthrough) |
| Graphics mode 0–3 | `mode: 0` on module or frame |

Reference tutorial: Cock Robin Q&A in the [Microtext manual](https://weaselsworld.com/microtext-2-6/) §4.

---

## 3. Module header

```mud
::: screen-module
name: WISHART.VLT
start: 5
machine: c64
mode: 0
border: #06b6d4
bg: #0f0f23
:::
```

| Key | Required | Notes |
|-----|----------|-------|
| `name` | yes | Module filename stem (e.g. `WISHART.VLT` → `WISHART.VLT` / `.STA` export) |
| `start` | yes | First frame id (integer) |
| `machine` | no | `c64` (default), `c128`, `web` |
| `mode` | no | Microtext graphics mode 0–3 |
| `border` / `bg` / `fg` | no | Web preview colours — C64 defaults: `#352879` / `#352879` / `#6c5eb5` |
| `charset` | no | `petscii` — use [Style64 PETSCII](https://style64.org/petscii/) + [C64 Pro Mono](http://style64.org/c64-truetype) in web player |
| `embed` | no | homebrewz / EmulatorJS URL for hardware run |

---

## 4. Frame block

```mud
::: frame id=5
text: |
  *** WISHART FLIGHT HQ ***
  
  Covenant Vault is LIVE on the wire.
  
  WHO COMMANDS THE DECK?
prompt: text
branches:
  CHIEF: 10
  GEMZY: 15
  CEEDEE: 20
  default: 25
:::
```

### 4.1 Frame keys

| Key | Notes |
|-----|-------|
| `id` | Frame number (required). Matches Microtext `*N` header. |
| `text` | Screen body. Pipe `\|` for multiline. Supports `**bold**` in web preview. |
| `prompt` | `text` → `?` · `key` → `!` · `none` → auto-continue on Enter |
| `branches` | Keyword → frame map. `default:` is Microtext `=N` catch-all. |
| `branch` | Shorthand single line: `CHIEF=10, GEMZY=15, default=25` |
| `end` | `true` → emit `$END` on export |
| `sound` | Passthrough e.g. `$NOTE C3` · `$VOICE 1` (C64 SID) |
| `cmd` | Raw Microtext command line(s) appended after branches |
| `mode` | Override module graphics mode for this frame |

### 4.2 Branch rules (Microtext-compatible)

- Keyword match is **case-insensitive** unless `match: exact` on module
- Unknown input → `default` branch, or **NOT UNDERSTOOD – TRY AGAIN** (Microtext behaviour)
- `= 5` unconditional jump → use `branches: default: 5` with `prompt: none`

### 4.3 End frame

```mud
::: frame id=99
end: true
text: |
  RAAAWWK FOR GLORY.
  [ MODULE END ]
prompt: none
:::
```

---

## 5. Executable blocks (`++`)

### 5.1 Microtext module export

Emits literal frame text for paste into Microtext editor or batch tooling:

```mud
++ screen.microtext export=WISHART.VLT
; Generated from MUD64 — Team DC
*5
WHO COMMANDS THE DECK?
?
CHIEF=10, GEMZY=15, CEEDEE=20, =25
............................
*99
$END
............................
```

### 5.2 Export manifest (frontmatter)

```mud
---
title: Wishart Vault Adventure
export:
  html: dist/wishart-vault.html
  screen:
    microtext: out/WISHART.VLT
    json: out/wishart-vault.json
  c64:
    embed: https://homebrewz.live/play.html
---
```

### 5.3 Hardware / SID (optional)

```mud
++ c64.hardware
machine "Commodore 64"
ram 64K
sid 6581

++ c64.export
prg "out/player.prg" load=$0801
```

See [`examples/c64-hardware-demo.mud`](examples/c64-hardware-demo.mud) for the full silicon manifest.

### 5.4 Dual compile — Code Designer **or** native C64

Every MUD64 module can reach real silicon **two ways**. Same `.mud` source, same intermediate manifest — **your choice of forge**:

| Path | Where it runs | Output | Best for |
|------|---------------|--------|----------|
| **`cd`** | [Code Designer](https://codedesigner.cloud) Flight Deck | `.prg` · `.d64` · `.sid` · `.VLT` | Fast iteration, Git, Monaco, cloud CI |
| **`native`** | Commodore 64 (or [homebrewz.live](https://homebrewz.live) browser emu) | In-RAM `.PRG` or disk file | Bedrock silicon, demo party, no network |
| **`both`** | CD export **+** native verify | Matched binaries | Team DC canon — compile twice, ship once |

**Design rule:** the exporter emits a **portable MUD64-IR** (frame graph + `++ c64.*` manifests + PETSCII plot ops). Code Designer lowers IR → 6510 assembly offline; the **native compiler** lowers the **same IR** on-machine. Bit-identical output is the goal when `target=both`.

```mud
++ c64.compile name=deck64_build
target both
machine c64pal
output prg load=$0801 name=out/DECK64.PRG
output d64 name=out/DECK64.D64 autostart
output microtext name=out/DECK64.VLT

cd:
  pipeline flight-deck
  asm acme
  link $0801
  include ++ c64.sprites, ++ c64.raster, ++ c64.draw, ++ c64.petscii, ++ c64.raycast, ++ c64.math, ++ c64.sid

native:
  compiler MUD64CMP version=0.1
  device 8
  source DECK64.MUD
  load_address $0801
  plotter $0C00          ; PETSCII vector routines
  frame_table $2000
  optional reu 512K      ; precalc 3D mesh tables
```

**Code Designer path (`target=cd` or `both`):**

1. Open `.mud` in Flight Deck (`/editor`)
2. Export manifest resolves `++ c64.*` blocks → assembly stubs
3. Toolchain (Acme/cc65) assembles + links → `out/*.PRG` / `.D64`
4. Flash to real C64, run on [homebrewz.live](https://homebrewz.live), or ship `.D64` to the vault

**Native C64 path (`target=native` or `both`):**

1. Copy `DECK64.MUD` + `MUD64CMP` (+ optional `MUD64.LIB`) to disk
2. `LOAD"MUD64CMP",8,1` → `RUN`
3. Compiler tokenizes `.mud`, builds IR, emits 6510 plot/frame/SID stubs **in situ**
4. `SYS 2049` or autostart — module runs without a PC in the loop

**PETSCII plot ops (shared IR — CD and native):**

| Opcode | Args | 6510 size (typical) |
|--------|------|---------------------|
| `PLOT_CLEAR` | — | 3 |
| `PLOT_LINE` | x0,y0,x1,y1 | 9 |
| `PLOT_CIRCLE` | cx,cy,r,flags | 8 |
| `PLOT_TUNNEL` | depth,cx,cy | 6 |
| `PLOT_MESH` | mesh_id, rot_y, rot_x | 5 + table ptr |
| `RAYCAST_INIT` | cols, rows, fov | 5 |
| `RAYCAST_MAP` | level_id, w, h, data_ptr | 7 + map bytes |
| `RAYCAST_TEXTURE` | wall_type, pattern_ptr | 4 |
| `RAYCAST_SPAWN` | level_id, px, py, pa | 8 |
| `RAYCAST_SPRITE` | id, x, y, art_ptr | 7 |
| `RAYCAST_WALK` | mode, speed, turn | 5 |
| `RAYCAST_FRAME` | frame_id, scene_name | 4 |

Web player [`petscii-draw.js`](petscii-draw.js) interprets **plot opcodes** for preview; [`petscii-raycast.js`](petscii-raycast.js) interprets **raycast IR** live. Native `MUD64CMP` compiles plotter to `$0C00`, raycast engine to `$1000` (default).

**Frontmatter export block (dual target):**

```mud
---
export:
  c64:
    compile: both
    prg: out/DECK64.PRG
    d64: out/DECK64.D64
    native:
      compiler: MUD64CMP
      disk: DECK64.D64
  screen:
    microtext: out/DECK64.VLT
---
```

Reference module: [`examples/dual-compile-manifest.mud`](examples/dual-compile-manifest.mud) · native toolchain notes: [`c64/NATIVE-COMPILE.md`](c64/NATIVE-COMPILE.md).

---

## 6. Web preview player

Code Designer ships a **40×25-style CRT player**:

- [mud64-player.html](mud64-player.html) — loads [examples/wishart-vault-adventure.mud](examples/wishart-vault-adventure.mud)
- Parses `::: screen-module` + `::: frame` fences client-side
- Keyboard input, branch routing, frame history (cursor up/down like Microtext edit stepping)

Embed in any `.mud` doc:

```mud
::: embed sandbox
src: mud64-player.html?module=examples/wishart-vault-adventure.mud
height: 520
title: Play Wishart Vault Adventure
:::
```

---

## 7. Author workflow

1. **Flowchart on paper** (Microtext §4.2) — boxes = frames, arrows = branches  
2. **Write `.mud`** — module header + one `::: frame` per box  
3. **Preview** — [mud64-player.html](mud64-player.html) or Flight Deck live preview (roadmap)  
4. **Choose compile path** — [§5.4](MUD64-SPEC.md#54-dual-compile--code-designer-or-native-c64):
   - **CD:** Flight Deck → Export → `.PRG` / `.D64` on your dev machine  
   - **Native:** `MUD64CMP` on real C64 → same module, compiled on silicon  
   - **Both:** export from CD, verify hash matches native build (Team DC QA)  
5. **Run** — autostart `.D64`, [homebrewz.live](https://homebrewz.live), or Microtext `.VLT` paste

---

## 8. Full example

See [`examples/wishart-vault-adventure.mud`](examples/wishart-vault-adventure.mud) — Team DC Covenant Vault mini-adventure (MAGICK 64K canon).

---

## 9. Relationship to Microtext

MUD64 is a **documentation-first authoring layer** — not a Microtext clone or replacement. We:

- Honour frame / branch semantics from the [1986 C64 Microtext manual](https://weaselsworld.com/microtext-2-6/)
- Emit compatible export text where practical
- Add web preview, Git, Monaco, and N.O.N. covenant manifests Team DC expects

**Archivist spark:** [Perifractic](https://www.youtube.com/watch?v=DvSlWLgXcsU) (Retro Recipes) surfaced Microtext 2.6 to a new generation — scanning the manual, sharing the `.d64`, and sending the community down the rabbit hole. [Weasel's World](https://weaselsworld.com/microtext-2-6/) transcribed it for the wire. Team DC built MUD64 because Peri proved the frame-based authoring model still slaps in 2026.

*Peri — if you're reading this: 24-sprite multiplexor, raster splits, color bars, hi-res draw, SID player, all declarative in `.mud`. You broke the seal. We built the cathedral. RAAAWWK.* 🐉

Perifractic / Weasel's World preservation work on Microtext 2.6 disk + manual is the upstream inspiration — RAAAWWK to the archivists.

---

## 10. C64 Hardware Runtime API

MUD64 extends [Microtext 64](https://weaselsworld.com/microtext-2-6/) (8 sprites, `$NOTE`, `$POINT`, `$LINE`) with a **Team DC silicon layer** for demoscene-grade effects, adventure games, and training sims — authored in `.mud`, exported to runtime stubs on real hardware or [homebrewz.live](https://homebrewz.live).

**Design rule:** Microtext `$` commands remain valid passthrough on `cmd:` / `sound:` lines. MUD64 `++ c64.*` blocks declare structured manifests the exporter turns into assembly stubs, IRQ tables, or SID player binaries.

### 10.1 Capability matrix

| Subsystem | Microtext baseline | MUD64 extension | Export target |
|-----------|-------------------|----------------------|---------------|
| Sprites | 8 hardware, `$ANIMATE` | **24+ multiplexor** | `++ c64.sprites` → IRQ + sprite table |
| Display | Modes 0–3, `$LINE` | **Raster splits**, **color bars** | `++ c64.raster` → `$D011/$D016` timeline |
| Bitmap | `$POINT`, `$LINE`, `$TRIANGLE` | **Hi-res + multicolor**, fill, blit | `++ c64.draw` → plot routines @ `$2000/$D000` |
| **PETSCII vector** | `$LINE` (text mode) | **Semigraphics plot**, circles, **precalc 3D wireframe** | `++ c64.petscii` → 6510 Bresenham @ `$0400` |
| **PETSCII raycast** | — | **40×25 maze FPS**, textured walls, sprites, portals | `++ c64.raycast` → 6510 cast @ `$1000` |
| Math | — | **Fixed-point**, trig, vectors | `++ c64.math` → lookup tables + lib |
| Audio | `$VOICE`, `$FILTER`, `$NOTE`, `$SOUND` | **SID player**, SFX banks, digi | `++ c64.sid` → `.sid` / `.prg` player |

**Implementation status (May 2026):** Spec + export schema **locked**. Web player: PETSCII text frames + **`++ c64.petscii` overlay** **live** + **`++ c64.raycast` engine** **live** ([MUDDOOM](mud-doom-demo.html)). **Compile:** CD Flight Deck export + native `MUD64CMP` — **roadmap** (shared IR defined; see [§5.4](MUD64-SPEC.md#54-dual-compile--code-designer-or-native-c64)).

---

### 10.2 Sprite multiplexor (`++ c64.sprites`)

The C64 VIC-II exposes **8 sprite slots**. Multiplexing reuses those slots at different raster lines to display **24+ moving objects** (classic games/demos).

```mud
++ c64.sprites name=deck_crew capacity=24
; VIC-II sprite multiplexor manifest — Team DC
max_visible 24
hardware_slots 8
irq_mode raster
sort_by y_descending

pool gemzy
    def assets/sprites/gemzy_12x21.spr
    anim flip 4fps
    path sine x=120 amp=40 period=120

pool ceedee
    def assets/sprites/ceedee_12x21.spr
    anim bob y=8 period=60

slot 0..7 hardware
slot 8..23 multiplex pool=gemzy,ceedee rotate

frame_bind 15 enable pool=gemzy count=12
frame_bind 30 disable all
```

| Key | Notes |
|-----|-------|
| `capacity` | Logical sprites (typically 16–24; 24 = Team DC canon) |
| `hardware_slots` | Always `8` on C64 |
| `irq_mode` | `raster` — line IRQ drives multiplex pass |
| `pool` | Named sprite definition + motion script |
| `slot` | Maps logical index → hardware or multiplex pool |
| `frame_bind` | Enable/disable pools when frame `id=N` is active |

**Frame hook (inline):**

```mud
::: frame id=15
sprites: enable gemzy x12
text: |
  GEMZY ENTERS — 12 MULTIPLEXED SPRITES ACTIVE
:::
```

**Microtext passthrough:** `$SPRITE n x y` · `$ANIMATE n frame` (8-sprite limit) — use `cmd:` when targeting stock Microtext runtime.

---

### 10.3 Raster splits & color bars (`++ c64.raster`)

**Raster splits** change VIC-II scroll, bank, or mode mid-frame. **Color bars** cycle `$D020` (border) / `$D021` (background) per raster line — the classic vertical rainbow.

```mud
++ c64.raster name=wishart_split
irq base=$31           ; CIA timer + raster IRQ chain
split line=120 action scroll_y=2
split line=199 action mode=hires bank=0

colorbars
    start_line 0
    end_line 250
    palette c64_16
    speed 1              ; shift hue index each line
    target border,bg     ; or bg_only | border_only

frame_bind 5 colorbars on
frame_bind 10 colorbars off
```

| Key | Notes |
|-----|-------|
| `split line=N` | Raster line (0–311 NTSC / 0–312 PAL) |
| `action` | `scroll_x` · `scroll_y` · `mode=hires|multicolor|text` · `bank=0|1` |
| `colorbars` | Per-line colour cycling — demoscene staple |
| `palette` | `c64_16` hardware palette indices 0–15 |
| `target` | Which VIC colour registers to drive |

**Stable timing:** exporter emits NTSC/PAL tables; authors declare `machine: c64ntsc` or `c64pal` on module header when splits are frame-critical.

---

### 10.4 Hi-res & multicolor bitmap draw (`++ c64.draw`)

Extends Microtext `$POINT` / `$LINE` / `$TRIANGLE` with **bitmap-backed** drawing for modes 1–2 (hires) and 2 (multicolor charset/bitmap hybrids).

```mud
++ c64.draw name=vault_logo
mode hires                   ; 320×200 @ $2000
mode multicolor              ; 160×200 @ $D000 (MC bitmap)
buffer $2000 size $1F40

clear color 0

; Microtext-compatible (export as $POINT/$LINE calls)
point 160 100 color 1
line 40 40 280 160 color 2
triangle 80 60 240 60 160 140 color 3 fill

; MUD64 extensions
rect 16 16 304 184 color 14 stroke
fill 100 80 120 60 color 5
blit assets/petscii/shield.bin x=96 y=52
char_multicolor row=12 col=8 screencode=$A0 colorpair=1,2,3

text_mode overlay row=22 col=0
    "COVENANT VAULT ONLINE"
```

| Command | Hi-res | Multicolor | Notes |
|---------|--------|------------|-------|
| `point x y color` | ✓ | ✓ | Single pixel / fat pixel |
| `line x1 y1 x2 y2 color` | ✓ | ✓ | Bresenham |
| `triangle … fill` | ✓ | ✓ | Microtext `$TRIANGLE` parity |
| `rect … stroke\|fill` | ✓ | ✓ | Box |
| `fill x y w h color` | ✓ | ✓ | Flood fill region |
| `blit file x y` | ✓ | ✓ | Raw bitmap / KOALA import |
| `char_multicolor` | — | ✓ | Charset MC mode helpers |

**Frame hook:**

```mud
::: frame id=20
draw: vault_logo layer=background
mode: 3
text: |
  SHIELD BITMAP RENDERED TO $2000
:::
```

---

### 10.5 PETSCII vector draw (`++ c64.petscii`)

**The clever bit:** plot vectors directly on the **40×25 text matrix** using **semigraphics** — each character cell holds a **2×2 fat-pixel grid** (80×50 logical resolution). Unrolled **Bresenham** line walk, **midpoint circle**, filled rects, and **precalc wireframe meshes** for 3D — fast enough for adventure overlays, radar screens, and **PETSCII DOOM**-style corridor previews.

Microtext `$LINE` / `$POINT` target **bitmap modes**. MUD64 `++ c64.petscii` targets **screen RAM `$0400`** with PETSCII quadrant chars (`$B0–$BF`) — no mode switch required when `mode: 3`.

```mud
++ c64.petscii name=doom_corridor resolution=80x50
clear
tunnel depth=10 cx=40 cy=4
rect 36 38 44 42 fill
line 38 38 32 42
line 42 38 48 42

++ c64.petscii name=radar resolution=80x50
clear
circle 40 25 18
circle 40 25 3 fill
line 40 25 58 18

++ c64.petscii name=spin_cube resolution=80x50
clear
wireframe cube scale=20 at=40,22 rotate=35,20 spin
```

| Command | Args | Notes |
|---------|------|-------|
| `clear` | — | Zero screen / nibble buffer |
| `line x0 y0 x1 y1` | semigraphics coords | Bresenham — **6510 export: no multiply** |
| `circle cx cy r` | optional `fill` | Midpoint algorithm |
| `rect x0 y0 x1 y1` | optional `fill` | Axis-aligned box |
| `plot x y` | optional `char=$A0` | Single coarse cell (40×25 mode) |
| `tunnel` | `depth=N cx=40 cy=6` | Perspective corridor (DOOM tease helper) |
| `wireframe mesh` | `cube` · `pyramid` · custom | Uses `++ c64.petscii precalc` vertex list |
| `wireframe … rotate=a,b` | degrees | Y then X euler — bind `++ c64.math` sin/cos LUT |
| `wireframe … spin` | — | Web player: live RAF spin; export: IRQ table or precalc frames |

**Resolution modes:**

| `resolution` | Logical | Screen | Use |
|--------------|---------|--------|-----|
| `80x50` (default) | 80×50 | 40×25 semigraphics | Lines, 3D, tunnels |
| `40x25` | 40×25 | 40×25 coarse chars | HUD labels, chunky art |

**Precalc 3D pipeline (export):**

```mud
++ c64.petscii precalc name=imp_mesh
mesh imp
  verts:
    0.0  0.6  0.2
    0.2  0.0  0.0
   -0.2  0.0  0.0
    0.0 -0.4  0.0
  edges: 0-1, 1-2, 2-0, 0-3, 1-3, 2-3

++ c64.math name=tables precision=8.8
table sin 256 entries range 0..360
table cos 256 entries range 0..360
bind mesh=imp_mesh rotate uses sin,cos

; Flight Deck export: emit PRG with mesh + plotter @ $0800
; Optional: precalc frame table for fixed camera paths (demo sync)
```

**Frame hook:**

```mud
::: frame id=10
petscii: doom_corridor layer=overlay
text: |
  SOMETHING MOVES IN THE DARK...
prompt: key
:::
```

| Key | Notes |
|-----|-------|
| `layer=overlay` | Draw above frame text (web player compositing) |
| `layer=background` | Draw below text — adventure room backdrop |
| `petscii: spin_cube spin` | Web player animates mesh; export may emit spin IRQ |

**6510 export targets:** `plot_fast.s` (semigraphics OR), `line_bresenham.s`, `circle_midpoint.s`, `wireframe_project.s` — linked from `++ c64.export`. **Identical opcodes** emitted by CD Flight Deck **or** native `MUD64CMP` ([§5.4](MUD64-SPEC.md#54-dual-compile--code-designer-or-native-c64)).

**Web player:** [`petscii-draw.js`](petscii-draw.js) — live overlay on [`mud64-player.html`](mud64-player.html). Demo: [`examples/petscii-wireframe-demo.mud`](examples/petscii-wireframe-demo.mud).

*Team DC canon: if Peri can break the Microtext seal, we can absolutely raycast a corridor in PETSCII before lunch. PETSCII DOOM is not a joke — it's a milestone.*

---

### 10.6 PETSCII raycast (`++ c64.raycast`)

**First-person maze engine** in text mode — 40×25 PETSCII framebuffer, full **VIC-II 16-color palette**, distance-shaded walls, billboard sprites, portal cells, and HUD. Authored declaratively in `.mud`; web player runs [`petscii-raycast.js`](petscii-raycast.js); native `MUD64CMP` lowers to fixed-point cast routines @ `$1000`.

```mud
++ c64.raycast name=muddoom
fov 0.62
walk auto speed=0.045 turn=0.038
health 100
ammo 666
bg 0
sid assets/sid/DOOM_Guy.sid

level hell
spawn 1.5 1.5 0          ; px py angle_degrees
imp 8.5 7.5              ; sprite billboard position
map
1111111111111111         ; 0=empty 1=stone 2=metal 3=hell 4=portal
1000000000000401
...

level tech
spawn 13.5 1.5 180
imp 4.5 10.5
map
...
```

| Key | Notes |
|-----|-------|
| `name` | Scene id — referenced by `raycast:` frame hook |
| `fov` | Field of view in radians (web preview); native uses 8.8 fixed LUT |
| `walk auto` | Autonomous maze traversal; `speed` / `turn` in map cells per tick |
| `level` | Named maze; `map` rows are digits `0–4` (see wall types below) |
| `spawn` | Player start: x, y, facing degrees (0 = east) |
| `imp` | Default enemy sprite at fixed map coords |
| `sid` | Optional `.sid` path — bound via `++ c64.sid` on export |
| `health` / `ammo` | HUD initial values |
| `bg` | Global screen background colour index (`$D021`) — default `0` |

**C64 colour model (no cheating):** Text mode allows **one global background** (`$D021`) plus **one foreground colour per cell** (`$D800` color RAM). Each screencode (`$0400`) is a single PETSCII glyph; half-block ceiling/floor chars (`$E0`/`$E2` upper/lower) ink the filled half in **fg** only — the empty half shows **global bg**. Distance shading varies **fg index and glyph choice** (`▓▒█`), not per-cell background. Multicolor mode is a separate export path.

**Wall map cells:**

| Cell | Texture | PETSCII pattern |
|------|---------|-----------------|
| `0` | — | Walkable floor |
| `1` | stone | `▓▒█▒▓█` distance bands |
| `2` | metal | `▐█▐░█▐` |
| `3` | hell | `█▙█▘█░` |
| `4` | portal | Walk-through → next `level` (wraps) |

**Frame hook:**

```mud
::: frame id=1
raycast: muddoom live
text: |
  *** MUDDOOM ***
  ++ c64.raycast LIVE
prompt: key
:::
```

| Key | Notes |
|-----|-------|
| `raycast: muddoom` | Static first frame (export / preview still) |
| `raycast: muddoom live` | Web player runs engine loop; native binds IRQ @ 50 Hz |
| `fire` | Default keys `f`, `ctrl`, `space`, `click` — declarative in block optional |

**MUD64-IR opcodes (shared — CD + native):**

| Opcode | Args | 6510 role |
|--------|------|-----------|
| `RAYCAST_INIT` | cols, rows, fov | Set viewport + trig LUT ptr |
| `RAYCAST_MAP` | level_id, w, h, data_ptr | Load maze grid @ `$2800` |
| `RAYCAST_TEXTURE` | wall_type, pattern_ptr | Semigraphics char rotation table |
| `RAYCAST_SPAWN` | level_id, px, py, pa | Player state vector |
| `RAYCAST_SPRITE` | id, x, y, art_ptr | Billboard imp / pickup |
| `RAYCAST_WALK` | mode, speed, turn | Auto-walk or input router |
| `RAYCAST_FRAME` | frame_id, scene_name | Bind scene to frame graph |

**6510 export targets:** `raycast_init.s`, `raycast_cast.s`, `raycast_blit.s`, `raycast_sprite.s` — linked from `++ c64.export`. **Identical opcodes** emitted by CD Flight Deck **or** native `MUD64CMP` ([§5.4](MUD64-SPEC.md#54-dual-compile--code-designer-or-native-c64)).

**Web player:** [`petscii-raycast.js`](petscii-raycast.js) — live engine on [`mud-doom-demo.html`](mud-doom-demo.html). Demo source: [`examples/mud-doom-demo.mud`](examples/mud-doom-demo.mud). Canon vault: [`team-dc/vault/muddoom_v1.json`](team-dc/vault/muddoom_v1.json).

*MUDDOOM v1.0 — textured walls, dual maze, DOOM_Guy.sid. Not a JS hack pretending to be MUD64: the `.mud` block **is** the source of truth.*

---

### 10.7 Advanced math (`++ c64.math`)

Fixed-point and lookup-table math for sprite paths, scrollers, and game logic — **no floating point** on 6510.

```mud
++ c64.math name=deck_tables precision=8.8
table sin 256 entries range 0..360
table cos 256 entries range 0..360
table atan2 64 entries

fn lerp a b t -> fixed
fn distance x1 y1 x2 y2 -> fixed
fn angle x y -> degrees

bind pool=gemzy path=sine uses sin,cos
bind scroll parallax uses lerp
```

| Key | Notes |
|-----|-------|
| `precision` | `8.8` fixed (default) · `16.16` for wide range |
| `table sin/cos` | 256-entry LUT standard for C64 demos |
| `fn` | Declarative bindings; exporter emits 6510 routines |
| `bind` | Links math assets to sprite/draw subsystems |

**Inline frame vars:**

```mud
::: frame id=40
vars:
  score: word
  angle: fixed = lookup(sin, frame_tick * 2)
:::
```

---

### 10.8 SID player & SFX (`++ c64.sid`)

Full **MOS 6581/8580** access — extends Microtext `$VOICE`, `$FILTER`, `$NOTE`, `$SOUND` with sequenced music and SFX banks.

```mud
++ c64.sid name=team_dc_theme chip=6581
player Goattracker2 export=sid/team_dc.sid

voices
    0 lead
    1 bass
    2 pad
    3 sfx

sfx bank vault_sfx
    blip   freq=$800 wave=pulse dur=8
    clack  freq=$200 wave=noise dur=12   ; Commander Beta shades CLACK
    raaawk arpeggio C-E-G wave=tri dur=60

filter
    cutoff 800
    resonance 12
    mode lowpass

frame_bind 5  play team_dc_theme loop
frame_bind 10 sfx clack
frame_bind 15 sfx raaawk
frame_bind 99 stop all
```

| Key | Notes |
|-----|-------|
| `player` | `.sid` file or Goattracker2 / SIDFactory export path |
| `voices` | Logical channel map (3 voice poly + 1 sfx typical) |
| `sfx bank` | Named one-shot effects |
| `filter` | `$D417` cutoff/res/mode block |
| `frame_bind` | `play` · `sfx` · `stop` tied to frame ids |

**Microtext passthrough (concurrent, non-blocking per manual):**

```mud
::: frame id=10
sound: $NOTE C3 $VOICE 1 $FILTER ON
cmd: $SOUND 1 100
:::
```

**Export:** `++ c64.sid` → embed player routine + `.sid` binary in `.prg` / `.d64` via `++ c64.export`.

---

### 10.8 Unified hardware module example

```mud
::: screen-module
name: DECK64.DEM
start: 1
machine: c64pal
mode: 3
charset: petscii
features: sprites,raster,draw,sid,math
:::

++ c64.sprites name=crew capacity=24
++ c64.raster name=split colorbars on
++ c64.draw name=logo mode=hires
++ c64.math name=tables precision=8.8
++ c64.sid name=theme player Goattracker2 export=sid/deck.sid

::: frame id=1
draw: logo
sprites: enable crew x24
sound: play theme
text: |
  *** TEAM DC SILICON DEMO ***
  24 SPRITES · RASTER SPLIT · COLOR BARS
  HI-RES LOGO · SID THEME LIVE
prompt: key
branches: |
  default: 99
:::
```

See [`examples/c64-hardware-demo.mud`](examples/c64-hardware-demo.mud) for the full annotated reference module.

---

## 11. PETSCII & typography

The web player renders at **40×25** using **[C64 Pro Mono](http://style64.org/c64-truetype)** (© [Style](http://style64.org/) — embedded per license in `assets/fonts/`).

- **[PETSCII reference](https://style64.org/petscii/)** — code points, screencodes, Unicode mappings
- Dashed dividers (`----------`) auto-map to PETSCII horizontal bar glyphs in the player
- **`++ c64.petscii`** vector overlay — semigraphics lines, circles, tunnels, 3D wireframes ([§10.5](MUD64-SPEC.md#105-petscii-vector-draw-c64petscii))
- **`++ c64.raycast`** maze FPS — textured walls, sprites, portals, HUD ([§10.6](MUD64-SPEC.md#106-petscii-raycast-c64raycast))
- Future: `petscii:` inline escapes in frame text for direct screencode authoring

---

## 12. Compile pipeline summary

```mermaid
flowchart LR
  MUD[".mud source"]
  IR["MUD64-IR\nframes + ++ c64.* + plot ops"]
  CD["Code Designer\nFlight Deck"]
  NAT["C64 native\nMUD64CMP"]
  PRG[".PRG / .D64"]
  RUN["Run on silicon\nor homebrewz.live"]

  MUD --> IR
  IR --> CD --> PRG
  IR --> NAT --> PRG
  PRG --> RUN
```

| Stage | CD | Native |
|-------|----|--------|
| Parse `.mud` | Flight Deck Monaco | `MUD64CMP` tokenizer @ `$0801` |
| Build IR | Export service | On-disk compiler |
| Lower PETSCII | Acme → `plotter.s` | Inline 6510 codegen @ `$0C00` |
| Lower raycast | Acme → `raycast.s` | Inline 6510 codegen @ `$1000` |
| Link | cc65/Acme | `SAVE"MODULE",8` |
| Verify | SHA256 manifest | `VERIFY both` in `++ c64.compile` |

*Document once. Compile anywhere. PETSCII DOOM on the machine that invented PETSCII.*

---

## 13. Version

| Version | Date | Notes |
|---------|------|-------|
| 0.1 | 2026-05-26 | Initial MUD64: module, frame, branches, web player, microtext export |
| 0.2 | 2026-05-26 | C64 Hardware API: 24-sprite mux, raster splits, color bars, hi-res/MC draw, math LUTs, SID player/SFX |
| 0.3 | 2026-05-26 | **`++ c64.petscii`** vector draw — semigraphics plot, tunnel, precalc 3D wireframe, web overlay ([petscii-draw.js](petscii-draw.js)) |
| 0.4 | 2026-05-26 | **Dual compile** — Code Designer Flight Deck **or** native C64 `MUD64CMP`; shared MUD64-IR ([§5.4](MUD64-SPEC.md#54-dual-compile--code-designer-or-native-c64), [§12](MUD64-SPEC.md#12-compile-pipeline-summary)) |
| 0.5 | 2026-05-19 | **`++ c64.raycast`** PETSCII maze engine — dual levels, textures, imp sprite, portals, HUD, shared `RAYCAST_*` IR ([petscii-raycast.js](petscii-raycast.js), [examples/mud-doom-demo.mud](examples/mud-doom-demo.mud), [MUDDOOM](mud-doom-demo.html)) |

**FutureVision Labs · Team DC · Code Designer**  
[MUD-SPEC v0.1](MUD-SPEC.md) · [MUD64 hub](mud64.html) · [Play adventure](mud64-player.html) · [homebrewz.live](https://homebrewz.live)
