Lightweight, pure client-side path. Complements design_deac.md and .cursorrules.
Reproduce what ACE did in as simple an environment as possible. Simulation of the AmigaOS API surface that ACE programs actually used is enough; full hardware emulation is not. Prefer the smallest stack that still runs real ACE programs faithfully.
Complexity is a defect. Avoid build systems, frameworks, and layers that do not earn their keep.
Ship a pure client-side ACE experience in the browser:
- Pick an existing program from a program picker (curated examples, later user files)
- Always see the ACE source alongside the running program — source is never hidden behind “run only”
- Edit that source in place, recompile, and run again
- Compile in the browser to readable JavaScript
- Run that JS against a small AmigaOS-inspired runtime (Canvas, Web Audio, Speech, IndexedDB)
No native toolchain required for end users. No Amiga hardware emulation.
| Invariant | Meaning |
|---|---|
| Source always visible | Editor (or equivalent) remains on screen while the program runs |
| Source always editable | User can change .b / .bas text at any time |
| Picker-first loading | Built-in examples load from a simple picker; optional file open later |
| Minimal chrome | Picker + editor + run/stop + output/canvas — nothing else until needed |
| Option | Verdict |
|---|---|
Modify ACE C gen_ backend; run compiler natively |
Rejected for product path — not pure client-side |
| Compile ACE C → WASM once; emit JS in-browser | Possible, but not lightweight |
| JS compiler + JS runtime; use C ACE as a spec | Chosen |
The recursive-descent parser in the original ACE 2.4 sources (and the original docs) are reverse-engineering sources for grammar and semantics; vidarh’s Linux fork is useful for Linux-port / retargeting notes. The shipped product does not include the C compiler.
Compiler output remains JavaScript (not WASM), for the reasons already logged in the design doc: DOM/API calls live in JS, debuggability, and ACE programs are not compute-bound.
| Source | Role |
|---|---|
| Programmer’s Guide v2.3 | Language model, structure, how programs are written |
| Language Reference v2.3 | Commands/functions → runtime surface |
| Reserved Words v2.3 | Lexer keyword set |
| Doc index | Entry point for the above |
| dbenn/ACE | Original ACE 2.4; prgs/ demos by David Benn (acceptance corpus); C parser/codegen reference |
| vidarh/ACE | Linux-port / retargeting notes for parse*.c / codegen.c — not the author of prgs/ |
docs/design_deac.md |
Architecture and UX intent |
.cursorrules |
Standing project guidance for agents |
When docs, examples, and C disagree on intent, David Benn’s original semantics take precedence.
Keep the tree small until something earns its place:
docs/ design + this plan
examples/ curated .b fixtures (ACE prgs/-style folders + ACEBasicJS/)
ACEBasicJS/ host demos (hello, window, …)
Turtle/ BenchMarks/ Gfx/ Sound/ Misc/ …
manifest.json picker entries with folder → <optgroup>
src/
compiler/ lexer, parser, codegen → JS string
runtime/ AmigaOS-ish API (console → intuition → gfx → audio → …)
ui/ picker + always-visible editor + run/stop + canvas
public/ static assets (Topaz later)
No C subtree in the default product path. Optional vendor/ace-c/ only if needed as an offline reference checkout — not a build dependency for the browser app.
- Static page: program picker + always-visible editable source + Run/Stop + output area
- Picker loads a stub example into the editor (source stays visible after Run)
- Compiler/runtime stubs behind Compile/Run
- README points at design, plan, and ACE docs
Done when: opening the host page lets you pick a stub program, see and edit its source, and run a hard-coded path that prints via the runtime stub.
Extract a construct checklist from the Programmer’s Guide + Language Reference→docs/construct-checklist.mdSeed→examples/with a tiny ordered suitehello,loops,sieve,ackermann(seeexamples/README.md)- C
parse*.c/codegen.cremain reference-only (not ported)
Seed suite (actual):
| Example | Why |
|---|---|
examples/ACEBasicJS/hello.b |
Phase 0 PRINT smoke test (ACE Library/hello.b needs LIBRARY dos — deferred) |
examples/BenchMarks/loops.b |
Nested FOR / WHILE / REPEAT, CONST, TIMER |
examples/BenchMarks/sieve.b |
DIM, IF, GOTO, line numbers |
examples/BenchMarks/ackermann.b |
SUB, recursion, EXIT SUB |
Done when: a written construct checklist exists and the seed examples are in-repo with expected-behaviour notes.
Subset grammar… Implemented in src/compiler/compiler.js (structured codegen + linear/GOTO mode).
Done when: seed logic examples compile to readable JS and execute in the browser with correct numeric/string results (no Intuition yet).
Verify: node tests/phase2-smoke.js
— PRINT, INPUT on a simple terminal surfacePRINT separators/padding (Phase 2 follow-up) plus async INPUT with a host input row and inputLines for tests. Demo: examples/input.b.
Done when: hello.b / print.b-class programs run end-to-end in-page.Interactive INPUT works in-page; smoke tests cover prompt / ? / comma forms.
Verify: node tests/phase2-smoke.js (includes INPUT cases).
Closer to the Amiga CLI / shell experience… One #console surface: PRINT into #output, live typing + blinking caret after the prompt, Enter submits; detached INPUT row removed. Headless inputLines / provideInput unchanged.
Done when: examples/input.b feels like a single shell session; detached INPUT row gone.
Why a half-step, not a full phase: no new language constructs — only host UX. Done before Phase 4 Intuition so CLI-style programs stay authentic, and windowed I/O can later reuse the same “text in a surface” ideas.
— custom screen host in the Display panel, Amiga-style title-bar chrome (close / depth / drag), WINDOW / SCREEN, text in windowsPRINT into the current window, close-gadget ≈ ACE -w (stops the program). Demo: examples/window.b.
Done when: one small windowed example matches the Amiga UX intent closely enough to iterate.
Still deferred within Phase 4+: MENU / GADGET, full PALETTE / COLOR / LOCATE, RMB menus, Topaz webfont.
Reuse the Phase 3.5 “text in a surface” pattern for Intuition — when INPUT runs with a current window, live typing + blinking caret appear in that window (same as PRINT); Enter submits. CLI programs keep the console surface. Demo: examples/window-input.b.
Done when: windowed INPUT feels like one text surface; no detached console typing required.
— indexed framebuffer per window (palette remaps like Amiga), canvas blit in the Display panel. Demo: LINE / PSET / CIRCLE / COLOR / PALETTE / CLS / LOCATE / POINTexamples/graphics.b.
Done when: a small graphics example draws lines, boxes, and circles with a custom palette.
Phase 5+ follow-up: PAINT / AREA / AREAFILL / PATTERN (+ &H hex literals) — flood fill, polygon fill, line/area patterns. Demo: examples/Gfx/paint.b (from ACE prgs/Gfx/pattern.b).
Still deferred within graphics: SCROLL, IFF, EHB/HAM modes, Topaz webfont, MENU / GADGET (elevate when a Gfx/Turtle example needs them).
unlocked by climbing the original ACE RND / RANDOMIZE / INT / SQR / ABS / SIN / COS / …prgs/ corpus:
| Example | Features exercised |
|---|---|
examples/hi.b |
bare RND, COLOR fg/bg, coloured LOCATE/PRINT |
examples/ahl.b |
SQR(n), RND, ABS(n) |
examples/lines.b |
RANDOMIZE TIMER, INT, RND, LINE |
examples/fact.b |
recursive SUB (already Phase 2) + interactive INPUT |
Also: single-line WHILE cond:…:WEND, and window PRINT as absolutely positioned coloured runs (so hi.b keeps per-string pens).
Done when: hi / ahl / lines / fact compile and pass smoke checks.
— Paula-style period (124..32767), duration 18.2 ≈ 1s, volume 0..64, voices 0..3. Frequency = SOUND / WAVE SIN / BEEP3579546 / (period * 32) for ACE’s 32-byte sine table. Demo: examples/Sound/sound.b.
Still deferred: WAVE with ALLOC/POKE sample memory (white noise / 8SVX play.b), tracker modules.
Done when: tones play in-page after Run (user gesture); smoke tests log SOUND calls.
Drive by visible demos and the smallest stack that works. Do not expand grammar ahead of a failing example.
| Priority | Work | Why / seed |
|---|---|---|
| 1 | Turtle graphics | FORWARD / BACK / TURN* / PEN* / SETXY / HOME / SETHEADING / HEADING / XCOR / YCOR. Seeds: torus / flower / boxit / dragon / snowflake / tree / spiro |
| 1b | Async SUBs (codegen) | async function and await SUB/SLEEP/INPUT callsexamples/Turtle/spiro.b (MENU→q adaptation stays) |
| 1c | bst / STRUCT·pointer |
STRUCT / DECLARE STRUCT / ADDRESS / @ / -> / *& / *! / := / ALLOC / SIZEOF / CASE / SHARED / CALL / PRINTS / CSRLIN / STR$ LEN RIGHT$examples/Turtle/bst.b |
| 2 | Gfx corpus climb | More of the original ACE graphics demos (dbenn/ACE prgs/Gfx/). pattern.b → paint.b; pattern2.b (GADGET WAIT); shuttle.b (DATA/READ + 2D DIM) done. prgs/ifs.b (MENU / ON MENU / MsgBox) done. 7seg.b (TIME$ / MID$ / VAL / ON WINDOW / ~) done. Next before IFF/EHB/HAM: e.g. tri.b — unlock constructs only as each fails |
| 3 | SAY | Web Speech API; seed welcome.b (SAY TRANSLATE$(…)). Full SpeechTool.b waits on GADGET / requesters |
| 4 | LIBRARY selective shims |
LIBRARY open/close can be no-ops. DECLARE FUNCTION … LIBRARY must bind the few AmigaOS calls an example actually uses (e.g. FPuts → console). Not a blanket stub for every .bmap entry |
| 5 | Sequential files (demoted) | Client-side apps rarely need PRINT# persistence. When an example demands it (seq.b), use an in-memory VFS first. IndexedDB only if reload survival is wanted — optional, maybe never |
| later | GUI (BUTTON/BEVELBOX / full GADGET create), IFF/EHB/HAM, sample WAVE, tracker/PLAY |
As corpus examples force them |
Each newly passing distribution example is a milestone.
A program passes when:
- The in-browser JS compiler accepts its source, and
- Behaviour in the JS runtime is equivalent to original ACE/Amiga execution for that program’s observable effects (output, drawing, sound, etc.).
The C compiler is a reference oracle during development, not the acceptance compiler.
- Full hardware emulation (UAE/WASM Amiga) — simulation of the OS API is the point
- Shipping the C ACE compiler (native or WASM) as the product compiler
- SPA frameworks, bundler mazes, or “platform” scaffolding without a concrete need
- Hide-the-source / run-only modes
- Joystick support
- Cycle-exact graphics/audio
- 100% Language Reference coverage before the seed suite passes
ExpandREADME.md…Phase 0 host…Seed examples…Phase 1 construct checklist…Phase 2: JS compiler for seed suite (hello/loops/sieve/ackermann)Phase 3: consoleINPUT(async host prompt + smoke tests)Phase 3.5: unified console / shell I/O(print + input on one surface; Amiga CLI feel)Phase 4: Intuition basics(WINDOW/SCREEN+ chrome; seeexamples/window.b)Phase 4.5: windowed(same surface asINPUTPRINT; Enter submits;examples/window-input.b)Phase 5: RastPort graphics(LINE/CIRCLE/PSET/COLOR/PALETTE; seeexamples/graphics.b) 10b.Phase 5+:(seePAINT/AREA/AREAFILL/PATTERNexamples/Gfx/paint.b)Phase 5.5: math builtins(RND/RANDOMIZE/INT/SQR/ABS;hi.b/ahl.b/lines.b/fact.b)Phase 6: SOUND / WAVE(WAVE SIN,SOUND,BEEP; seeexamples/Sound/sound.b)Turtle graphics—FORWARD/TURN*/PEN*/SETXY;torus/flower/boxit(+dragon/snowflake/tree) 13b.Async SUBs—spiro.b(SLEEPinsideSUB); MENU→qadaptation stays 13c.—bst/ STRUCT·pointerTurtle/bst.b(STRUCT/@/*&/ALLOC/CASE/ …)- Gfx corpus climb — more ACE
prgs/Gfx/beyondpaint.b/pattern2.b/shuttle.b/7seg.b(defer IFF/EHB/HAM)—pattern2.bGADGET WAIT 0(close gadget)—shuttle.bDATA/READ+ multi-dimDIM(GOSUB→SUB adaptation)—ifs.bMENU/MENU WAIT/ON MENU/MsgBox/CHR$—7seg.bTIME$/MID$/VAL/LINE …,bf/ON WINDOW/~continuation
- SAY — Web Speech; seed
welcome.b LIBRARYshims — open/close no-ops; bind only calls examples need- Files (low priority) — in-memory VFS if/when
seq.b-class demos matter; IndexedDB optional
- Design:
docs/design_deac.md - Agent rules:
.cursorrules - ACE docs: https://dbenn.github.io/docs/doc_index.html
- Original ACE 2.4 (source + examples): https://github.com/dbenn/ACE
- Linux fork (parser/codegen notes): https://github.com/vidarh/ACE