From fe001d728c2750702035a4e78164d642729097ca Mon Sep 17 00:00:00 2001 From: David Montero Date: Wed, 3 Jun 2026 21:30:42 +0200 Subject: [PATCH] =?UTF-8?q?fix(examples):=20board-less=20chip=20example=20?= =?UTF-8?q?=E2=80=94=20Run=20enabled=20on=20load=20+=20editable=20program?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two UX bugs in the board-less "Z80 Larson Scanner (no board)" example: - It loaded "running" (electrical sim defaults to paused=false), so Run was disabled and Stop enabled even though the chip hadn't started — the user had to Stop then Run. loadExample now starts a board-less example that contains a custom chip in the STOPPED state (paused=true) so Run is enabled; pure analog/digital circuits stay live. - The chip's program wasn't editable: it shipped a pre-baked ROM and the board-less loader only setCode'd into an orphan file group (no-op → blank editor). The example now ships larson.s as a real file (programFile), and the board-less loader points the editor at the default group and loadFiles() the example's files, so the program shows on the left and is editable, like the board-backed examples. Run compiles it. Co-Authored-By: Claude Opus 4.8 --- frontend/src/data/examples-retro-intel.ts | 8 +++--- frontend/src/utils/loadExample.ts | 30 ++++++++++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/frontend/src/data/examples-retro-intel.ts b/frontend/src/data/examples-retro-intel.ts index 3724c46a..b93dc67b 100644 --- a/frontend/src/data/examples-retro-intel.ts +++ b/frontend/src/data/examples-retro-intel.ts @@ -638,7 +638,8 @@ export const retroIntelExamples: ExampleProject[] = [ difficulty: 'intermediate', boardFilter: 'digital', tags: ['retro', 'z80', 'zilog', 'cpu', 'leds', 'larson', 'no-board', 'power-supply', 'custom-chip', 'spice', 'programmable'], - code: `// Z80 Larson Scanner — NO Arduino, just the chip + a power supply.\n//\n// Velxio runs custom chips as a general-purpose electronics simulator: the\n// programmable Z80 on the canvas executes its ROM and drives the 8 LEDs\n// directly, powered by the regulated supply (no MCU needed). Click Run.\n\nvoid setup() {}\nvoid loop() {}\n`, + code: larsonZ80Asm, + files: [{ name: 'larson.s', content: larsonZ80Asm }], components: [ { type: 'power-supply', @@ -657,9 +658,8 @@ export const retroIntelExamples: ExampleProject[] = [ sourceC: z80CpuC, chipJson: z80CpuJ, wasmBase64: '', - // Pre-baked larson.s ROM (LD SP,0xBFFF; rotate a bit across 0xC000). - romBytes: 'Mf+/PgEyAMD1zRAA8QcY9Q5QBgAQ/g0g+ck=', - programFile: '', + romBytes: '', + programFile: 'larson.s', programTarget: 'z80', }, }, diff --git a/frontend/src/utils/loadExample.ts b/frontend/src/utils/loadExample.ts index 07ae175d..d4d09074 100644 --- a/frontend/src/utils/loadExample.ts +++ b/frontend/src/utils/loadExample.ts @@ -248,10 +248,21 @@ export async function loadExample( const filename = isPiBoardKind(liveBoard.boardKind) ? 'main.cpp' : 'sketch.ino'; editorStore.loadFiles([{ name: filename, content: example.code }]); } else { - // Truly board-less: write the placeholder code to whatever the editor - // currently shows (boardless examples ship a `void setup()/loop()` - // stub — content barely matters since the user won't compile it). - useEditorStore.getState().setCode(example.code); + // Truly board-less. There is no board file-group, so point the editor at + // the default group and load the example's files THERE — otherwise the + // editor's activeGroupId still points at a deleted board's group and + // setCode silently no-ops, leaving the editor blank/uneditable. This is + // what lets a board-less custom-chip example show its program (.s/.c) on + // the left, editable, just like the board-backed examples. + const editorStore = useEditorStore.getState(); + if (example.files && example.files.length > 0) { + editorStore.setActiveGroup('group-arduino-uno'); // = DEFAULT_GROUP_ID + editorStore.loadFiles(example.files); + } else { + // Pure analog/digital circuits ship no editable program — keep the + // legacy behaviour (write the placeholder to the current file). + editorStore.setCode(example.code); + } } const componentsWithoutBoard = example.components.filter( @@ -270,6 +281,17 @@ export async function loadExample( })), ); + // A board-less example with a custom chip must START STOPPED so the Run + // button is enabled: the chip needs an explicit Run to compile its + // WASM/ROM and begin executing. Pure analog/digital circuits stay live + // (paused=false) as before. + if (isBoardless) { + const hasCustomChip = componentsWithoutBoard.some( + (c) => stripBrandPrefix(c.type) === 'custom-chip', + ); + useElectricalStore.getState().setPaused(hasCustomChip); + } + // After possibly removing every board, re-read activeBoardId. const liveActiveBoardId = useSimulatorStore.getState().activeBoardId; // For analog (board-less) examples we leave any 'arduino-uno' references