一键导入
frontend
Prime context for working on the Svelte 5 frontend in /src/ — components, stores, WASM bridge, audio, canvas rendering
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Prime context for working on the Svelte 5 frontend in /src/ — components, stores, WASM bridge, audio, canvas rendering
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Profile-driven performance optimization for SvelteBoy AssemblyScript/WASM backend. Use when asked to optimize emulator performance, profile hotspots, or reduce CPU usage.
Prime context for working on the SvelteBoy APU — architecture, channel implementations, register layout, event queue, render pipeline, and test patterns
Prime context for working on the AssemblyScript/WASM GameBoy emulator backend in /assembly/
Guide for writing AssemblyScript backend tests in assembly/tests/ — patterns, helpers, ROM setup, and wiring
Complete Game Boy DMG hardware reference — all registers, timing, opcodes, PPU modes, APU circuits, MBC banking. Authoritative inline spec for emulator implementation.
Prime context for architectural discussions about SvelteBoy's design patterns, component interactions, timing model, and trade-offs vs. general emulator approaches
| name | frontend |
| description | Prime context for working on the Svelte 5 frontend in /src/ — components, stores, WASM bridge, audio, canvas rendering |
| argument-hint | optional: specific area, e.g. debugger, audio, canvas, stores |
You are working on the Svelte 5 frontend of SvelteBoy, a GameBoy DMG emulator.
$state, $derived, $effect)pnpm run dev | Build: pnpm run buildsrc/emulator/ module — re-exports build/backend via wasmBridge.ts, facade in index.tssrc/stores/| File/Dir | Purpose |
|---|---|
src/emulator/index.ts | Emulator+Debug facades, re-exports AudioSuspended/FrameStats/RenderFrames |
src/emulator/wasmBridge.ts | re-export build/backend, frame/audio typed-array views |
src/emulator/loop.ts | requestAnimationFrame loop, pre/postRun, FrameStats, callbacks |
src/emulator/audio.ts | AudioContext, queue, fade, mute subs, suspendAudio/resumeAudio |
src/emulator/lifecycle.ts | pause/unpause/reset/runUntilBreak, visibility, HMR |
src/emulator/saveState.ts | QuickSave/QuickLoad + thumbnails |
src/emulator/rom.ts | playRom, getRomBuffer, loadSaveGame |
src/inputs.ts | Keyboard → joypad bitmask → setJoypad() WASM call |
src/types.ts | TypeScript types mirroring WASM-exported shapes |
src/stores/playStores.ts | GameFrames, KeyPressMap, emulator running state |
src/stores/debugStores.ts | Breakpoints, logs, debug info reactive state |
src/stores/optionsStore.ts | Volume, pixel size, FPS target |
src/stores/romStores.ts | Loaded cartridge reference |
src/lib/Player.svelte | Top-level game player container |
src/lib/PlayCanvas.svelte | 160×144 <canvas> — receives Uint8ClampedArray frame, calls putImageData |
src/lib/PlayerControls.svelte | Play/Pause/Reset buttons |
src/lib/debug/Debugger.svelte | Full debugger UI container |
src/lib/debug/CpuDebugInfo.svelte | Registers, flags display |
src/lib/debug/Disassembler.svelte | Disassembly view using getCartLines() |
src/lib/debug/HexView.svelte | Memory hex dump using hexDump() |
src/lib/debug/LogView.svelte | Serial/debug log viewer |
Inside src/emulator/* use relative ./wasmBridge. Outside, import from ./emulator (facade).
// inside src/emulator/*
import {
initEmulator, runEmulator,
setJoypad, getDebugInfo, loadCartridgeRom,
getGameFrameView, getCgbGameFrameView, getAudioBufferView,
backendMemory
} from "./wasmBridge";
// Pass data TO wasm (bindings handle pointer/length automatically)
loadCartridgeRom(new Uint8Array(romArrayBuffer));
// Zero-copy frame view (helper wraps backendMemory + ptr)
const frame = getGameFrameView(); // Uint8Array(160*144) palette indices
// or RGBA (CGB): getCgbGameFrameView() — Uint16Array RGB555
// Get managed objects (copy via bindings)
const info = getDebugInfo(); // → plain JS object matching DebugInfo shape
// Called in postRun after each emulation step
const count = getAudioBuffersToReadCount();
for (let i = 0; i < count; i++) {
const leftPtr = getAudioBufferToReadPointer(0);
const rightPtr = getAudioBufferToReadPointer(1);
const size = getAudioBuffersSize();
// Zero-copy typed array views
const left = new Float32Array(backendMemory.buffer, leftPtr, size);
const right = new Float32Array(backendMemory.buffer, rightPtr, size);
// Feed to Web Audio API
const buf = audioCtx.createBuffer(2, size, getAudioSampleRate());
buf.copyToChannel(left, 0);
buf.copyToChannel(right, 1);
const src = audioCtx.createBufferSource();
src.buffer = buf;
src.connect(audioCtx.destination);
src.start(nextAudioTime);
nextAudioTime += buf.duration;
}
markAudioBuffersRead(count);
Loop logic in src/emulator/loop.ts. Audio postRun registered via addPostRunCallback from audio.ts. Render callbacks fire when ≥1 GB frame advanced this rAF tick.
// loop.ts
function run(time: number) {
accumulator += wallDt * get(EmulatorSpeed);
while (accumulator >= GB_FRAME_MS && framesThisTick < MAX_CATCHUP) {
preRun(); // setJoypad(inputBits)
LastStopReason.set(runEmulator(GB_FRAME_MS));
postRun(); // fetchLogs, GameFrames++, debug snapshot, AutoSave, postRunCallbacks
accumulator -= GB_FRAME_MS; framesThisTick++;
}
if (framesThisTick > 0) renderCallbacks.forEach(cb => cb());
if (!get(EmulatorPaused)) requestAnimationFrame(run);
}
Emulator.AddRenderCallback / AddPostRunCallback for components (Player, AudioDebug) to hook in.
<script lang="ts">
// Reactive state (replaces writable store in component)
let frame = $state<Uint8ClampedArray | null>(null);
// Derived (replaces $: reactive declaration)
let isRunning = $derived(frame !== null);
// Side effects (replaces onMount + $: with cleanup)
$effect(() => {
const unsub = someStore.subscribe(v => { ... });
return () => unsub();
});
</script>
| Store | Use for |
|---|---|
playStores.ts | Emulator running state, current frame, key press map |
debugStores.ts | Debug info snapshot, logs, breakpoints list |
optionsStore.ts | User settings (volume, scale) — persisted to localStorage |
romStores.ts | Currently loaded cartridge metadata |
// Combined with bitwise OR, passed to setJoypad(keys)
Right=1, Left=2, Up=4, Down=8, A=16, B=32, Select=64, Start=128
$ARGUMENTS