一键导入
frontend-worker
Handles Vite + TypeScript frontend, canvas display rendering, keyboard/mouse input, controls UI, browser persistence, and emulator integration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Handles Vite + TypeScript frontend, canvas display rendering, keyboard/mouse input, controls UI, browser persistence, and emulator integration.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | frontend-worker |
| description | Handles Vite + TypeScript frontend, canvas display rendering, keyboard/mouse input, controls UI, browser persistence, and emulator integration. |
NOTE: Startup and cleanup are handled by worker-base. This skill defines the WORK PROCEDURE.
Use for features involving:
Read the feature description, preconditions, expectedBehavior, and verificationSteps. Read AGENTS.md for boundaries and conventions. Read .factory/library/ files for architecture and environment details. Read research docs if needed (QEMU_WASM_RESEARCH.md, QEMU_WASM_DISPLAY_RESEARCH.md).
Write Vitest unit tests BEFORE implementation:
Run tests — they MUST fail initially (red). Then implement to make them pass (green).
Follow the feature's expectedBehavior precisely. Key patterns:
For Emscripten integration:
Module['mainScriptUrlOrBlob'] for Web Worker URLFor display rendering:
setInterval at ~30ms (NOT requestAnimationFrame — rAF is hijacked by PROXY_TO_PTHREAD)Module._qemu_display_data(), _qemu_display_width(), _qemu_display_height()new Uint8ClampedArray(Module.HEAPU8.buffer, fbPtr, width * height * 4)For keyboard input:
keydown and keyup on the canvas containerKeyboardEvent.code to QEMU scancodes (PS/2 Set 1)Module._qemu_input_send_key(scancode, isDown ? 1 : 0)preventDefault() for F-keys, Escape, and other interceptable shortcutsdocument.activeElement)blur event), release all currently held keysFor mouse input:
mousemove, mousedown, mouseup on canvasModule._qemu_input_send_mouse(dx, dy, buttons)For controls UI:
For persistence (OPFS/IndexedDB):
navigator.storage.getDirectory()beforeunloadnavigator.storage.persist() to reduce eviction riskFor COOP/COEP headers (Vite config):
// vite.config.ts
server: {
port: 3200,
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
}
}
Run full test suite: npm test
Run typecheck: npm run typecheck
Run lint: npm run lint (if configured)
Start dev server and verify in browser where possible.
Execute all verification steps from the feature definition.
For features that affect the browser UI:
npm run dev)For each manual check, record: what you did, what you observed, and whether it matched expectations. Each check becomes an interactiveChecks entry in the handoff.
IMPORTANT: Do not leave the dev server running after verification. Kill it explicitly.
{
"salientSummary": "Implemented canvas display rendering with BGRX->RGBA conversion and VGA mode switch handling. Linux PoC boots successfully in browser with visible kernel messages on canvas. Keyboard input (typing in busybox shell) confirmed working. Ran `npm test` (12 tests passing) and `npm run typecheck` (clean).",
"whatWasImplemented": "Created src/display.ts with setInterval-based render loop polling QEMU framebuffer via EMSCRIPTEN_KEEPALIVE exports. Pixel format conversion handles BGRX->RGBA swap. Canvas resizes on VGA mode changes via dpy_gfx_switch callback detection. Loading spinner shown until first non-blank frame. Integrated with Emscripten module loader.",
"whatWasLeftUndone": "",
"verification": {
"commandsRun": [
{ "command": "npm test", "exitCode": 0, "observation": "12 tests passing: 6 display tests (BGRX conversion, resize, mode switch), 4 scancode mapping tests, 2 module loader tests" },
{ "command": "npm run typecheck", "exitCode": 0, "observation": "No type errors" }
],
"interactiveChecks": [
{ "action": "Started dev server, opened http://localhost:3200, clicked Start", "observed": "Loading spinner appeared, then Linux kernel boot messages rendered on canvas within 30 seconds. Canvas sized at 640x480." },
{ "action": "Typed 'ls' + Enter in busybox shell via browser keyboard", "observed": "Characters appeared on canvas with ~500ms latency. Directory listing rendered correctly." },
{ "action": "Checked browser console", "observed": "No errors or warnings. SharedArrayBuffer available. Emscripten module initialized." }
]
},
"tests": {
"added": [
{ "file": "src/__tests__/display.test.ts", "cases": [
{ "name": "converts BGRX to RGBA correctly", "verifies": "Blue byte 0 maps to RGBA byte 2 (blue channel)" },
{ "name": "handles canvas resize on mode switch", "verifies": "Canvas width/height update when framebuffer dimensions change" },
{ "name": "detects first non-blank frame", "verifies": "Loading indicator hidden when framebuffer has >2 distinct colors" }
]},
{ "file": "src/__tests__/input.test.ts", "cases": [
{ "name": "maps KeyA to scancode 0x1E", "verifies": "Alphanumeric key mapping" },
{ "name": "maps Enter to scancode 0x1C", "verifies": "Special key mapping" },
{ "name": "maps F5 to scancode 0x3F", "verifies": "Function key mapping" }
]}
]
},
"discoveredIssues": []
}