Rewrite notes/MOUSE.md as the real-hardware as-built: the 6520 PIA + 6805
controller + banked 342-0270-C ROM, the port-B handshake, the commands, the
X=$Cn/Y=$n0 calling convention and the screen-hole layout (Pos/Read
slot-indexed; ClampMouse's fixed slot-0 quirk), the interrupt model (][+
works, //e backlog), host input, the EWM integration, and the MousePaint
confirmation. Drop the retired synthetic-firmware description and its (now
resolved) "Known limitation".
Update README and notes/IDEAS.md to describe the mouse as the card's real
hardware, and mark plans/20260721-01 (the synthetic card) as superseded by
this plan.
Docs only; no code change.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The closer for the AppleMouse II card (plans/20260721-01, now complete). No
code — the as-built record and the config surface's documentation.
- notes/MOUSE.md: the as-built — synthetic firmware and the identification /
screen-hole map, the private DEVSEL protocol, the interrupt model and the
reusable maskable-IRQ line (so Mockingboard inherits it), and the
coordinate decision (absolute/mapped, revised from the plan's
relative/captured).
- README: the "What's emulated" list gains the AppleMouse II; a runnable
example (examples/mouse.json, a slot-4 mouse //e) checked by
readme_examples_parse.
- notes/JSON_CONFIG.md: the slot-card inventory gains "mouse" (one, any slot
1-7, both families); notes/STATE.md lists the Mou Persist fields;
notes/IDEAS.md ticks the AppleMouse item and points Mockingboard at the
shared IRQ line.
Gate: readme_examples_parse + standard gates (382 pass).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Record the reset-fidelity gap found while testing the original //e: EWM's
Ctrl-Reset is only cpu.reset() (CPU registers), but a real //e's RESET line
also clears the memory soft switches (80STORE/RAMRD/RAMWRT/ALTZP/INTCXROM/
SLOTC3ROM) before the ROM handler runs — and the ROM relies on that. Measured:
after Ctrl-Reset from an all-switches-on state, RAMRD/RAMWRT/ALTZP/INTCXROM
persist on both //e, so a program that leaves aux memory active and resets
comes back still in aux memory (never happens on hardware).
New "Emulation accuracy" section in notes/IDEAS.md with the story, the fix
shape (a hardware-reset hook distinct from a program's soft reset through the
vector), what to pin against a reference before implementing, and the //e-only
scope. No code change here — backlog only.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The closer for the original //e: a `builtin:apple2e` config so the machine
E3 added is reachable by name, and the docs to match. This completes
plans/20260720-02.
- configs/apple2e.json: model apple2e, aux ext80col, UniDisk 3.5 (Liron) in
slot 5, Disk ][ in slot 6, RGB — the same layout as apple2enhanced, on the
6502. Registered in BUILTINS (sorted apple2 < apple2e < apple2enhanced);
the builtin list / title / model / self-containment tests extend.
- Boot gate: builtin_apple2e_boots_dos33 builds the machine through the
config pipeline and boots DOS 3.3 to the Applesoft `]` prompt (the //e
autostarts the slot 6 disk; DOS 3.3 runs on the 6502).
- Docs: README "What's emulated" folds the original and Enhanced //e into
one entry and gains a builtin:apple2e profile; notes/JSON_CONFIG.md model
inventory + the aux-validity note cover both //e models; IDEAS.md marks
"NMOS //e" landed.
Gates: cargo fmt / clippy -D warnings / cargo test (365 pass, incl. the new
boot gate and readme_examples_parse with the new builtin:apple2e example).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Spell out the two-family model tokens so every machine reads the same
way — apple1, apple2e, apple2plus, replica1 — ahead of adding the
original Apple ][ as `apple2` (plans/20260720-01). Pre-1.0, so the old
terse tokens go outright: `--set machine:model=2plus` and
`--config builtin:2plus` are now apple2plus / apple2e, and an old name
errors with the available list.
Mechanical and wide: the config::Model serde tokens and Model::token(),
the BUILTINS table (renamed, re-sorted, include_str paths), configs/
files (git mv 2plus.json/2e.json -> apple2plus.json/apple2e.json) and
their model values, the ewm/tests/configs fixtures, every "2plus"/"2e"
string literal in tests and error messages, the examples, both schemas,
and the live docs (README, JSON_CONFIG, IDEAS, MAC_APP). Guarded
word-boundary replacement so e2e, new_2e and hex escaped it. The
builtin:list column widened to fit the 10-char "apple2plus".
Verified: fmt, clippy -D warnings, the full suite (37 binaries incl.
golden-BMP and the README example check) pass; builtin:list and the
old-token error checked against the real binary.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Flag retirement F1: the quiet seven
Plan 20260719-01: --scanlines, --fps, --strict, --debug, --boot-delay,
--trace/--trace= and --state are gone from `ewm two` — they were
single-value duplicates of config keys (display.scanlines, display.fps,
cpu.strict, debug.enabled, boot.delay, debug.trace, state.path), all
reachable via --set or any config source. Retired flags fall into the
generic usage error (owner's ruling: v0.0.1, no transition ceremony);
a test sweeps the list and pins the --set spellings.
Scanlines::parse went with its only caller (the flag's optional-value
peek); MonitorStyle::parse follows in F2 with --color. Docs swept:
README's feature blurb, STATE.md and REMOTE.md speak state.path /
--set state:path now, IDEAS.md's trace item names debug.trace.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Flag retirement F2: the muscle-memory trio
Plan 20260719-01: --model, --color and --aux are gone from `ewm two` —
machine.model, display.monitor and machine.aux are config keys, and
`--config builtin:2e` is as short as `--model 2e` was. The --model
alias spellings (2+, ][+, //e, iie) go with it, as does --color's
optional-value peek (bare --color meant rgb) and MonitorStyle::parse,
its last caller. The aux token survives internally (Options.aux,
rebuilt by apply_config); only the flag is gone.
Swept the consumers: main.rs's getting-started hint and subcommand
line, the README feature blurbs and quick-start (builtin-first now,
enforced by readme_two_examples_parse), JSON_CONFIG.md's schema
inventory (sources are config + --set for everything), and the
--color/--aux comment references in scr.rs, aux.rs, config.rs and
two.rs. `one` keeps its --model — it has no config surface (plan
non-goal). Historical notes (APPLE_IIE_ENHANCED, REWRITE, landed
IDEAS items) keep their period wording.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Flag retirement F3: --memory
Plan 20260719-01, last phase: --memory is gone from `ewm two`; memory
regions come from config or overlay files (machine.memory), the one
setting --set cannot reach (arrays) — apply_set's error text now says
so. two's parse_memory_option went with the flag (one keeps its own
copy and its --memory flag: no config surface there, plan non-goal).
The print-config round trip composes the region through an overlay
now, which is exactly the documented replacement.
With this, `ewm two`'s surface is the plan's goal shape: the four
sources (--config, --config-overlay, --set, --print-config), --serve,
and the debug tooling (--wozbug, --break, hidden --screenshot). Plan
marked complete with the kickoff decisions recorded as built.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* README: wrap the quick-start commands; document the three two profiles
The "start a machine directly" commands wrap with backslash
continuations (the readme_two_examples_parse test joins them, so they
stay checked). A new section explains that bare `ewm two` boots the
default machine — a ][+ with the 16K Language Card (the classic 64K
build), Thunderclock, and Disk II — and documents all three machine
profiles in English and JSON: the default (with its config-terms
equivalent, printable via --print-config), builtin:2plus, and
builtin:2e, each with its explicit `--config builtin:<name>` boot
command. The later ready-made-configs paragraph folded into it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* README: brief Experimental section for WozBug, VNC, and the Mac app
WozBug's walkthrough and the Native Mac app section fold into a new
Experimental section at the bottom — three short bullets, each linking
to its working document (notes/DEBUGGING_TOOLS.md, notes/REMOTE.md,
notes/MAC_APP.md). The remote console gets its first README mention
there; its --serve bullet leaves the source-kinds list, which is back
to the three document sources.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* README: drop the cc65 tests/ sentence
The C-era assembly test programs are being removed in #284; the
Testing section no longer mentions them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* README: complete Key commands section
The keys table becomes a "Key commands" section and gains the missing
entries: Cmd-K (the Command Palette, available on every machine) and
Cmd-Shift-R (reboot, power off/on), plus a Machines column instead of
per-row parentheticals. A short paragraph documents the palette's own
keys (type to filter, arrows, Return, Esc), that everything else —
including Ctrl-A..Z control characters — goes to the emulated machine,
and drag-and-drop disk swapping.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phase C5, the last phase of plans/20260718-02-config-sources.md.
The README's config section is rewritten around the compositional
model — one document, four source kinds merged in command-line order
(--config base, --config-overlay layers, --set overrides, convenience
flags on top) — with the Total Replay overlay as the worked example
and --config builtin:2e in the quick-start. The example configs are
now committed under examples/ (myiie.json and
drive-with-total-replay.json, shown verbatim in the README), so every
example references real files. --print-config closes the section as
the "what machine did I just describe?" / linter answer.
The gate's scripted check is the readme_two_examples_parse test in
two.rs: it extracts every `cargo run --release -- two ...` example
from the README (quote-aware, continuation-joining) and runs it
through parse_options, which opens every --config/--config-overlay
source — so a renamed flag, a bad example path, or an example config
that stops validating fails the suite.
Notes brought up to date: JSON_CONFIG.md's status table gains the
config-sources row (C1-C5 done) and Phase C is marked as seeded by
options_to_config; IDEAS.md moves machine config files from "in
progress" to "landed" with the remaining palette work named;
MAC_APP.md's Phase 3 bullet records that .ewmachine bundles can be a
thin layer over the landed source surface. Also fixes the --fps usage
text (the default is 40, not 30 — drift spotted during C4).
Verified: the README's composed, complete-config, and overlay-only
examples run against the real binary from the repo root (exit 0,
expected documents); fmt, clippy -D warnings, and the full suite
(including the golden-BMP screenshot tests) pass.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Add the debugging-tools plan (notes/DEBUGGING_TOOLS.md)
WozBug: a MicroBug-inspired (TN1136), Woz-Monitor-dialect minimal
debugger — one command core with test, TCP-line-server, and
breakpoint-pause frontends — plus CPU breakpoints, device-state
commands, and a built-in symbol table. Grounded in what the PR #253
RWTS hunt actually required.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* WozBug phase 1: CPU breakpoints and the monitor command core
Cpu gains PC breakpoints (add/remove/stopped/stop/resume): a hit makes
step() return 0 without executing until resume(), which skips the
breakpoint at the current PC once so stepping off a hit makes progress.
The empty-breakpoint fast path is one always-false branch — the Dormann
suite times identically (0.19s release) before and after, so this lives
in the normal build with no debug split.
ewm/src/wozbug.rs is the command core: MicroBug in role (TN1136), Woz
Monitor in dialect. 280.29F dumps (a bare Return continues from the dot
address), 300:A9 20 deposits, R / PC=BD00 / A=FF registers, S [n]
stepping with trace lines, G / 300G, B breakpoints — plus the
machine-aware commands DSK, SW, TEXT, and SLOTS, and a built-in symbol
table for Monitor/DOS/ProDOS landmarks (B RWTS works; R prints
PC=BD25 (RWTS+$25)). Dumps read through the bus, soft-switch side
effects included, as on real hardware.
ewm/tests/wozbug.rs replays the PR #253 hunt with tools instead of
temporary code: boot DOS 3.3, B RWTS, CATALOG lands on the breakpoint,
R names the site, DSK shows the controller, Y/A -> IOB verified, S/G
resume cleanly to the catalog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* WozBug phase 2: the --wozbug line server and --break flag
`ewm two --wozbug [port]` (default 6502) serves WozBug on a local TCP
port, one nc-friendly client at a time; `--break addr[,addr]` arms
breakpoints at boot — hex or built-in symbols (--break RWTS) — and
implies the server. The server threads only move strings over channels:
the frame loop drains commands and executes them on the machine's own
thread between frames, so there is no locking and an idle server costs
one try_recv per loop. The frame burst breaks on a 0-cycle step, and a
rising stopped edge announces "stopped at ..." + registers to both the
client and stderr.
Verified live: --break RWTS with the DOS 3.3 disk, nc connect receives
the stop announcement, R shows the IOB pointer in Y/A, S 3 traces
RWTS's first instructions, G resumes the boot. README gains a
"Debugging with WozBug" section.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* WozBug Phase 3: watchpoints, trace toggle, and disassembly
Watchpoints live in Memory as inclusive address ranges. When any are
set, reads and writes record the first watched access per instruction
(WatchHit: address, direction, value); the CPU checks after each
instruction completes and stops post-instruction, so registers show the
state right after the touching access. Opcode/operand fetches count as
reads; the trace formatter's peeks are excluded by clearing the hit
after the trace block. With no watchpoints armed the recording paths
are gated on an empty-vec check: the Dormann suite measures 0.19s
release either way, and 0.21s with a watchpoint armed, so the feature
stays in the normal build.
New WozBug commands:
W list watchpoints
W 2000.3FFF watch a range (W 400 for one byte)
W-2000.3FFF clear one, W- clears all
T / T- CPU trace to stderr on/off
L [addr] disassemble 16 instructions, plain L continues
The stop banner now names the access that fired:
watch: write 0427 = C1.
Dialect fix recorded as a regression test: B, W, and L only act as
commands when the argument is separated by a space or '-'. B and D are
hex digits, so BD00 must examine memory at $BD00, never set a
breakpoint at $D00.
ewm_core::fmt grows disassemble(cpu, addr) -> (line, next_addr),
reusing the trace formatter and instruction table.
Also adds a server test that sequential client connections are served
after a client disconnects.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
A whole machine can now be described in one JSON file and started with
`ewm two --config myemulator.json`:
- ewm/src/config.rs: serde types mirroring the schema; load() parses,
validates semantically (Phase A accepts only today's buildable layout:
slot 1 thunderclock, slot 6 diskii, slot 7 harddrive, any aux card),
and resolves relative paths against the config file's directory.
- --config in parse_options via a two-pass parse: pass 1 seeds Options
from the file, pass 2 is the unchanged flag loop — so explicitly given
CLI flags override config values structurally.
- Config-only settings cpu.speed and input.controller wire to the
existing palette mechanisms at startup (including the audio
cycle-to-sample pairing and a preferred-gamepad name scan).
- schema/ewm-config.schema.json: draft 2020-12, derived from the config
structs by a golden-file test (schemars is a dev-dependency only;
regenerate with EWM_UPDATE_SCHEMA=1 cargo test -p ewm).
- Tests: schema lockstep, parse/validation/rejection messages,
relative-path resolution, CLI-overrides-config precedence, and a boot
gate (a config naming the DOS 3.3 disk boots to the ] prompt exactly
like --drive1 does).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plan for `ewm two --config myemulator.json`, per the owner's decisions:
JSON over TOML (better supported); a committed JSON Schema
(schema/ewm-config.schema.json, derived from the serde structs via
schemars and locked by a round-trip test) covering everything the CLI
and Command Palette configure today -- model, drives, hdd, aux card,
monitor style, scanlines, boot delay, fps, memory regions, the palette's
accelerator speeds and controller pick; plus configurable slots 1-7
(diskii with drive images, harddrive, thunderclock, empty -- multiple
Disk ][ controllers legal in the schema). CLI options stay; only
--config is added, with explicit flags overriding config values, and
relative paths resolving against the config file's directory (the
property .ewmachine bundles need).
Three phases: A = --config + schema + today's layout expressible (other
layouts error clearly); B = table-driven machine construction for real
slot flexibility (multiple controllers at $C080+slot*16 with per-slot P5
ROMs, empty slots, boot-scan order); C = palette "save machine
configuration" round-tripping into the .ewmachine story.
MAC_APP.md Phase 3 rewritten TOML->JSON; the IDEAS.md bullet now points
here.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four phases: a self-contained double-clickable EWM.app (static SDL3,
hand-rolled bundle script, ad-hoc signing, .dsk/.woz/.hdv file
associations delivered as SDL drop events, an icon rendered by the
emulator's own character generator); distribution polish (Developer ID +
notarization + DMG); .ewmachine machine documents built on the config-file
idea; and finally the VMware-Fusion-style library app that spawns each
machine as its own app instance. Option 1 first, as the owner decided --
it produces exactly the building blocks option 2 orchestrates. Grounded
against the tree: the binary currently links Homebrew SDL3 dynamically,
sdl3 0.18 offers build-from-source-static, and the rewrite already made
the binary Finder-launch-safe (include_bytes ROMs, no cwd dependence).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The auxiliary slot becomes an AuxCard trait (ewm/src/aux.rs) with one
implementation file per card, selected with --aux:
- aux/text80.rs -- the plain Apple 80-Column Text Card (1K): only the aux
half of text page 1 ($0400-$07FF) answers; 80-column text works while
RAMRD/RAMWRT, ALTZP, the aux language card and double-res graphics have
no memory behind them (reads float 0xFF, writes drop).
- aux/ext80.rs -- the Apple Extended 80-Column Text Card (64K): one full
bank for body, display pages and aux LC. The default; behavior-identical
to what IouE hardwired before.
- aux/ramworks.rs -- the Applied Engineering RamWorks III: up to 128 x 64K
banks. A write to $C073 selects the bank that replaces aux memory for
RAMRD/RAMWRT/ALTZP and the aux language card, but the 80STORE display
pages and the video scanner always use bank 0 (the 80-column video
buffers only exist there). The register is write-only; unpopulated banks
float, which sizing probes depend on.
The trait is method-based with per-card address decode (the 1K card cannot
hand out a 64K bank, and real cards decode which addresses they answer):
read/write (selected bank body), video_read/video_write/video_ram (bank 0
/ display), lc_read/lc_write (aux LC via an LcRegion the MMU resolves),
io_write ($C070-$C07F register decode), label.
IouE drops its hardwired aux vec and the [main, aux] LC arrays for a
Box<dyn AuxCard> plus main-side LC vecs; Two::new_with_aux(model, card)
constructs (the ][+ rejects cards -- no aux slot); Two::new keeps the
default so every existing caller and test is untouched.
CLI: --aux <80col|ext80col|ramworksiii[:SIZE]>, SIZE any multiple of 64K
from 64k to 8m (default 8m), parsed by the aux::parse factory.
Gates: ewm/tests/two_e_aux_cards.rs -- bank isolation at $C073, per-bank
ALTZP, 80STORE pinned to bank 0, unpopulated float, a sizing probe
counting exactly 4 banks on a :256k card, the ROM self-test reporting
System OK with RamWorks installed, the 1K card's text-only matrix, the
extended card ignoring $C073, and the ][+ rejection. Per-card unit tests
live in each impl file; the whole existing suite stays green with the
default card (the IouE refactor is behavior-neutral). Quirks recorded in
APPLE_IIE_ENHANCED.md (#7).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field report from the Xbox pad: A/B buttons worked but movement did not.
Two real causes, both fixed:
1. The //e never modelled the analog paddles: IouE::set_joystick was a
documented no-op and $C070/$C064/$C065 were unhandled, so on
--model 2e the buttons ($C061/$C062) worked while the stick read
nothing. The ][+ 558-timer model (PTRIG arms cycle timers from the
axes; PADL reads report bit 7 until expiry, PADL1 keeping its timer
quirk) is now ported into IouE verbatim.
2. The D-pad reports as buttons (DPadUp/Down/Left/Right) and was
unmapped on every machine. It now folds into the joystick axes at
full deflection, winning over the analog stick in the per-frame feed
and releasing cleanly per direction.
Gate: ewm/tests/two_e_paddles.rs -- the timer charges and expires with
the axis value, PTRIG without a joystick is inert, and a parity test
locks the //e to the ][+ across an axis/wait matrix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bluetooth pads (the owner's Xbox Wireless controller) usually connect
after launch, but two.rs only opened the first gamepad present at startup.
Now the controller is hot-pluggable and choosable:
- ControllerDeviceAdded: auto-connect when no pad is active (a pad already
present at startup also fires Added -- a no-op, one is active). When a
pad IS active, the newcomer is announced but does not take over.
- ControllerDeviceRemoved: losing the active pad falls back to the first
remaining one (or none), with stderr lines for every transition.
- A "Controller: <name>" palette row (submenu triangle) opens a quick-pick
of connected pads by name, check mark on the active one; picking one
switches instantly. Names come from GamepadSubsystem::name_for_id, no
open needed for the listing.
- Button events now filter on `which`: only the active pad drives the
machine (previously any connected pad's buttons passed through). Axis
polling already read only the active Gamepad.
The picker rows need to carry which pad they select, and bare fn pointers
cannot capture data, so TwoAction becomes an enum:
Run(fn(&mut TwoCtx)) | PickController(u32), matched in the palette Execute
handler. All existing registrations wrap in TwoAction::Run; the palette
module itself is unchanged.
SDL notes: sdl3 0.18 exposes the SDL_EVENT_GAMEPAD_ADDED/REMOVED events as
ControllerDeviceAdded/Removed with a u32 `which`; JoystickId is the
sys::joystick::SDL_JoystickID newtype, constructed via the sys re-export.
Hot-plug is hardware-bound (no headless coverage); the full suite stays
green and the TwoAction change is compile-verified across all sites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scanline dimming for the 3x window: every emulated row maps to three
window rows and the third is dimmed, giving the classic CRT raster look.
Implemented as a static overlay texture multiplied over the screen rect
with BlendMode::Mod (dstRGB = srcRGB * dstRGB): zero per-frame cost (the
overlay is rebuilt only on a setting change), no alpha-channel dependence,
and it composes with every monitor style. The effect is applied at the SDL
copy, after Scr::frame(), so goldens and --screenshot never see it.
CLI: --scanlines [off|light|heavy], with the --color optional-value
convention -- bare --scanlines means light, unrecognized values are left
for the next flag, default is off. Light multiplies dimmed rows by 200,
heavy by 140 (named constants, tuned by eye).
Command palette: a "Scanlines: <current>" submenu row alongside "Monitor
Style", both using the triangle affordance. With two choice submenus the
reopen mechanism is generalized: TwoCtx's open_monitor_menu bool becomes
open_submenu: Option<Submenu>, matched in the Execute handler.
Tests: Scanlines::parse round-trips; scanline_overlay dims exactly the
y % 3 == 2 rows at the right levels; parse_options covers absent, bare,
valued and peek-don't-consume forms. Visually verified by compositing a
DOS 3.3 boot screen with the heavy overlay. CRT bloom stays on the ideas
list (needs shader work). README updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A MonitorStyle (Green | Amber | White | Rgb) replaces the boolean color
switch. The monochrome styles are the existing Monochrome pipeline with a
parameterized phosphor -- text, HGR mono and DHGR mono now draw in a
phosphor color instead of hardwired green (amber is the classic P3
#FFB000). Rgb is the existing color pipeline. set_color_scheme stays as a
compatibility shim delegating Monochrome -> Green and Color -> Rgb, so the
DLGR/DHGR tests and goldens are untouched (both golden BMPs verified
byte-identical -- the default is still green).
CLI: --color now takes an optional value, green|amber|white|rgb. Bare
--color keeps its historical meaning (rgb), so the README examples still
work; the parser peeks and only consumes a recognized value, so
'--color --drive1 x' parses as before. No flag = green, as always.
Command palette: a new "Monitor Style: <current>" row opens a VS Code
quick-pick style submenu (Green/Amber/White/Color, check mark on the
active style); picking one applies instantly and marks the screen dirty.
The palette module itself is unchanged -- the submenu is loop state using
the existing commands-registered-per-activation design, via two new TwoCtx
fields (monitor, open_monitor_menu). The speed rows now share the same
choice_label helper.
Tests: MonitorStyle::parse round-trips; a render test proving each
phosphor lands in pixels (and that no green survives in amber mode); a
parse_options test covering bare --color, valued --color and the
peek-don't-consume case. README updated; IDEAS.md item marked landed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
It is a platform, not a cloud feature: client-side EWM in the browser
(canvas + Web Audio, no server), expanded with the infra note that the
core/frontend crate seam and the pure renderer are already WASM-ready.
Cloud & web keeps a cross-reference as the no-server counterpart to the
hosted instances.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the single mlua bullet with a comparison of embedding options:
Lua 5.4 and Luau via mlua (Luau = gradually-typed Lua, the strongest
'Lua but more static' answer), pure-Rust Rhai/Rune, Meta's hermetic
Starlark (deterministic by construction, matching EWM's test culture),
WASM plugins via wasmtime (the TinyGo answer: typed plugins in
TinyGo/Rust/Zig against a host API), TypeScript via deno_core/QuickJS,
and statically-typed Gluon (flagged risky). Cross-cutting notes on the
per-instruction hook perf cliff, determinism, two-tier composition, and
the shared hook-API design that keeps the choice deferrable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- AI: an MCP server exposing the headless core to agents (boot, type,
read text_screen, screenshot -- what our own tests already do), an AI
debugging assistant (how the E7 and lowercase bugs were actually
cracked), an automatic cheat finder via memory diffing, a BASIC
copilot, and an RL harness (determinism + snapshots = perfect episode
resets).
- Cloud & web: a WebAssembly build (client-side, embeddable), cloud disk
library + save-state sync, deterministic shareable replays, spectator
mode, and the control socket as a hosted emulation API.
- Mobile: an iPad/iPhone app (post-2024 App Store retro-emulator rules),
touch/motion controls, Handoff via synced states, WASM as the
no-install fallback.
- Apple Watch: the watch as a peripheral, not a host -- the Digital Crown
as the most faithful rotary paddle Apple has shipped since 1983, a
status complication for hosted instances, and BELL notifications.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Game cheats: a palette submenu backed by per-title TOML cheat files
(pokes/patches matched to the mounted image), e.g. 'Hard Hat Mack --
more lives'.
- Quit & resume: auto-save machine state on exit and restore on next
launch, on top of the save-state work.
- A new Input category: the real //e paddle-timer gap ($C064-$C067 are
unhandled in IouE today), gamepad hot-plug/mapping/calibration,
keyboard-as-joystick and mouse-as-paddles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two new categories and an expanded launch story:
- Configuration & launch experience: YAML/TOML machine config files,
runtime disk management (start with no disks, insert/eject/mount from
the Command Palette), a well-known disk library directory, fetching
images from the Internet Archive (4am collections via the archive.org
JSON API), and the north-star theme of starting ewm with no command-line
options at all.
- Distribution & platforms: a native double-clickable macOS app with
.dsk/.woz file associations, a Raspberry Pi boot image that powers on
straight into the boo menu (the bootloader's original purpose), and
hosted virtual Apple //e instances used from a browser via VNC/noVNC.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ideas gathered from a survey of AppleWin, Virtual ][, MAME's apple2e
driver, izapple2 and Apple2TS, merged with the future-work lists already
in REWRITE.md, APPLE_IIE_ENHANCED.md and WOZ1.md. Nine categories --
hardware cards, machine models, storage/disk images, video, audio,
debugging tools, command palette, save states/rewind, and automation --
each item sized (S/M/L) and annotated with the existing EWM infrastructure
it builds on. A living backlog, not a plan: ideas graduate into their own
working documents.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>