Skip to content

feat: add Stack-chan WASM build support - #402

Merged
meganetaaan merged 15 commits into
dev/v1.0from
feat/wasm-stackchan-build
May 14, 2026
Merged

feat: add Stack-chan WASM build support#402
meganetaaan merged 15 commits into
dev/v1.0from
feat/wasm-stackchan-build

Conversation

@meganetaaan

@meganetaaan meganetaaan commented Apr 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a Moddable wasm manifest for firmware/stackchan
  • Add wasm-safe stubs for hardware, network, speech, and default-mod entrypoints
  • Add npm run build:wasm to build mc.js/mc.wasm into web/simulator/

Verification

  • npm ci (firmware)
  • MODDABLE=/.local/share/moddable + emsdk 3.1.2 + FONTBM=/.local/bin/fontbm npm run build:wasm

Stacked follow-up will wire these artifacts into the deployed web page.

Do not merge yet; stacked CI deploy PR will target this branch.

Summary by CodeRabbit

  • New Features

    • WebAssembly build and browser simulator support with a WASM-targeted runtime, presets, renderer and utility manifests, plus simulator subsystems (drivers, LED, tone, microphone, network, preferences, and multiple TTS backends as stubs).
  • Chores

    • Build tooling extended to produce and stage WASM artifacts for the web simulator; CI setup enhanced to ensure required SDK and host tooling.
  • Stability

    • Startup now emits richer trace logs and surfaces initialization errors.

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds WASM build tooling and manifests, many WASM-target stub modules (drivers, services, TTS, hardware shims), and a WASM startup branch that evaluates defaultMod.onLaunch, may create the robot and calls onRobotCreated, with additional trace logging and CI/setup adjustments.

Changes

Cohort / File(s) Summary
Build & Manifests
firmware/package.json, firmware/stackchan/manifest_wasm.json, firmware/stackchan/utilities/manifest_wasm_utility.json, firmware/stackchan/renderers-piu/manifest_wasm_renderer_piu.json
Adds build:wasm script and multiple WASM manifests configuring module mappings, preloads, fonts, memory/layout, runtime options, and relaxed tsconfig settings.
Startup & Mods
firmware/stackchan/main.ts, firmware/stackchan/default-mods/wasm/on-launch.ts
Adds WASM-specific startup branch with detailed tracing; evaluates defaultMod.onLaunch, conditionally creates robot and calls onRobotCreated; new onLaunch mod returns true.
WASM Drivers (stubs)
firmware/stackchan/drivers/wasm/driver-stub.ts, firmware/stackchan/drivers/wasm/dynamixel-driver.ts, firmware/stackchan/drivers/wasm/none-driver.ts, firmware/stackchan/drivers/wasm/rs30x-driver.ts, firmware/stackchan/drivers/wasm/scservo-driver.ts, firmware/stackchan/drivers/wasm/sg90-driver.ts
Introduces driver stub classes for multiple driver types; applyRotation/setTorque are no-ops and getRotation returns null/zero as stubs.
WASM Services
firmware/stackchan/services/wasm/network-service.ts, firmware/stackchan/services/wasm/preference-server.ts
Adds placeholder NetworkService and PreferenceServer with minimal lifecycle/connect APIs that invoke onConnected when provided.
WASM TTS implementations
firmware/stackchan/speeches/wasm/tts-elevenlabs.ts, firmware/stackchan/speeches/wasm/tts-local.ts, firmware/stackchan/speeches/wasm/tts-openai.ts, firmware/stackchan/speeches/wasm/tts-remote.ts, firmware/stackchan/speeches/wasm/tts-stub.ts, firmware/stackchan/speeches/wasm/tts-voicevox-web.ts, firmware/stackchan/speeches/wasm/tts-voicevox.ts
Adds multiple TTS stub classes exposing stream(text, volume?) with empty implementations.
WASM Hardware shims
firmware/stackchan/wasm/tone.ts, firmware/stackchan/wasm/led.ts, firmware/stackchan/wasm/microphone.ts
Adds stubbed Tone, Led, and Microphone classes with no-op methods used by the WASM runtime/simulator.
CI & Setup
.github/workflows/build.yml, .github/actions/setup/action.yml
Adds SDK pin/checkout step in CI and installs additional host packages (libglib2.0-dev, pkg-config) in the setup action to ensure required build tooling and reproducible SDK revision.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Main as Main
    participant Trace as Trace
    participant DefaultMod as DefaultMod
    participant Robot as Robot
    Main->>Trace: log("main start")
    Main->>Trace: log("install button bridge")
    Main->>Trace: log("wifi stage")
    Main->>DefaultMod: call onLaunch()
    DefaultMod-->>Main: true
    Main->>Trace: log("shouldRobotCreate = true")
    Main->>Robot: createRobot()
    Robot-->>Main: robotInstance
    Main->>Trace: log("calling onRobotCreated")
    Main->>DefaultMod: call onRobotCreated(robotInstance)
    DefaultMod-->>Main: (done)
    Main->>Trace: log("onRobotCreated completed")
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • stc1988

Poem

🐰 I stitched a tiny WASM trail,
Stubbed the motors, tunes, and tale,
Manifests set, simulator hums,
The build script hops and now it runs,
A rabbit cheers as testing comes.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly and specifically summarizes the main objective: adding WASM build support to Stack-chan firmware.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wasm-stackchan-build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52e849fa60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4 to +5
async getRotation(): Promise<null> {
return null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Return Maybe shape from WASM getRotation

Robot.updatePose assumes driver.getRotation() returns an object with a success field and immediately dereferences result.success. In the WASM path, this stub returns null, so the default WASM config (driver.type: "none" in manifest_wasm.json) will hit a runtime error as soon as pose updates run. This prevents normal simulator behavior and should return a valid Maybe<Rotation> object like the non-WASM NoneDriver implementation.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@firmware/stackchan/drivers/wasm/driver-stub.ts`:
- Around line 6-8: WasmDriver.getRotation() currently returns ZERO_ROTATION
directly which violates the driver result contract expected by callers to check
result.success; change getRotation to return a result object wrapping the
rotation, e.g. { success: true, rotation: ZERO_ROTATION } (or { success: false,
error: ... } on failure) so call sites that inspect result.success continue to
work; update the getRotation implementation and any related tests to return the
standardized result shape and reference ZERO_ROTATION inside that result.

In `@firmware/stackchan/drivers/wasm/dynamixel-driver.ts`:
- Around line 4-5: DynamixelDriver.getRotation currently returns null which
breaks callers expecting a Maybe object; change the function signature from
Promise<null> to Promise<Maybe<number>> (or the appropriate Maybe<T> for
rotation) and update the implementation to always return a Maybe shaped object
(e.g., { success: false } on error or { success: true, value: rotation } on
success) so callers can safely read result.success; ensure any internal paths
that previously returned null now return the correct Maybe form.

In `@firmware/stackchan/drivers/wasm/none-driver.ts`:
- Around line 4-5: getRotation currently returns null which breaks callers
expecting a Maybe-shaped object; change the implementation of getRotation to
return a Maybe-shaped object (e.g., an object containing the expected success
flag and value fields rather than null) so callers can safely read
result.success and result.value; update the returned Promise from getRotation to
resolve to that object shape (keeping the async signature) and ensure it matches
the project's Maybe type contract used elsewhere.

In `@firmware/stackchan/drivers/wasm/rs30x-driver.ts`:
- Around line 4-5: RS30XDriver.getRotation currently returns Promise<null>,
which breaks callers expecting a success-tagged result; update the method
signature and implementation in RS30XDriver.getRotation to return the expected
result shape (e.g., an object with a success boolean and either a rotation value
or an error message), ensure the Promise resolves to that object instead of
null, and adjust any internal logic to produce success: true with the rotation
data on success or success: false with an error on failure so downstream code
can reliably inspect the success tag.

In `@firmware/stackchan/drivers/wasm/scservo-driver.ts`:
- Around line 4-6: The getRotation() implementation currently returns null;
change it to return the zero-rotation object used by the existing WASM driver
baseline (not null). Update the method signature from Promise<null> to the
correct Rotation type (matching the other WASM driver code) and return the
zero-value rotation object (the same shape/fields the rest of the code expects)
so downstream callers no longer need null guards; adjust any imports/types if
necessary to reference the Rotation type and ensure the returned object matches
its shape.

In `@firmware/stackchan/drivers/wasm/sg90-driver.ts`:
- Around line 4-6: The getRotation method on PWMServoDriver currently returns
Promise<null> which violates the driver contract; change the signature to return
the correct rotation-shaped type (e.g., Promise<Rotation> or Promise<number> to
match other drivers) and return a real rotation value instead of null: implement
PWMServoDriver.getRotation to read the servo's current state (from an existing
field such as this.rotation/this.currentAngle or by converting pulse width /
calling the internal read method like getPulseWidth()/readPWMPosition()) and
return a Rotation-shaped object (or numeric angle) wrapped in a resolved Promise
so the method matches other driver implementations.

In `@firmware/stackchan/main.ts`:
- Around line 175-181: The onLaunch and onRobotCreated hooks are called
synchronously but may return Promises, so await their results to preserve
StackchanMod hook semantics and allow async errors to flow; change the call site
to await onLaunch() when computing shouldRobotCreate (e.g., const
shouldRobotCreate = await onLaunch?.() ?? true) and await
onRobotCreated?.(robot, globalEnv.device) after createRobot() (or make the
surrounding function async) so both hook results are handled correctly and any
thrown/rejected errors are propagated.

In `@firmware/stackchan/manifest_wasm.json`:
- Around line 15-19: The modules["*"] array in manifest_wasm.json is
mis-formatted for Biome; reformat the value of modules["*"] to match the
repository's JSON formatting style (one string per line, properly indented, with
commas placed/omitted as in the rest of the file) so the file passes the Biome
formatter; update the array entries for "./touch", "./robot", and "./main"
accordingly and run the Biome formatter (or commit the exact formatting used
elsewhere in the file) before pushing.

In `@firmware/stackchan/speeches/wasm/tts-stub.ts`:
- Around line 2-3: The constructor and stream method in this WASM TTS stub use
untyped parameters; change their signatures to match the explicit types used in
the other WASM TTS implementations (e.g., tts-voicevox.ts, tts-elevenlabs.ts,
tts-remote.ts, tts-openai.ts, tts-local.ts). Specifically, update
constructor(_options) to constructor(options: /* same options type used by the
other WASM TTS classes */) and update async stream(_text, _volume) to async
stream(text: string, volume?: number): /* same return type as other WASM TTS
stream methods */ so the parameter names, types, and return type match the rest
of the implementations.

In `@firmware/stackchan/wasm/microphone.ts`:
- Line 3: Restore the original optional parameter on the microphone API by
changing the record function signature back to record(durationMilliSec?:
number): Promise<ArrayBuffer> (i.e., accept an optional durationMilliSec
parameter), keep existing internal WASM logic unchanged but consume or ignore
durationMilliSec as appropriate (e.g., pass it into the WASM call or use it to
set a timeout/default), and ensure callers remain compatible with non-WASM code
paths; update the record method declaration in microphone.ts accordingly so
TypeScript call-sites don’t break.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a752a29-2d01-41ed-998e-8b788a080ea3

📥 Commits

Reviewing files that changed from the base of the PR and between caca377 and 52e849f.

📒 Files selected for processing (24)
  • firmware/package.json
  • firmware/stackchan/default-mods/wasm/on-launch.ts
  • firmware/stackchan/drivers/wasm/driver-stub.ts
  • firmware/stackchan/drivers/wasm/dynamixel-driver.ts
  • firmware/stackchan/drivers/wasm/none-driver.ts
  • firmware/stackchan/drivers/wasm/rs30x-driver.ts
  • firmware/stackchan/drivers/wasm/scservo-driver.ts
  • firmware/stackchan/drivers/wasm/sg90-driver.ts
  • firmware/stackchan/main.ts
  • firmware/stackchan/manifest_wasm.json
  • firmware/stackchan/renderers-piu/manifest_wasm_renderer_piu.json
  • firmware/stackchan/services/wasm/network-service.ts
  • firmware/stackchan/services/wasm/preference-server.ts
  • firmware/stackchan/speeches/wasm/tts-elevenlabs.ts
  • firmware/stackchan/speeches/wasm/tts-local.ts
  • firmware/stackchan/speeches/wasm/tts-openai.ts
  • firmware/stackchan/speeches/wasm/tts-remote.ts
  • firmware/stackchan/speeches/wasm/tts-stub.ts
  • firmware/stackchan/speeches/wasm/tts-voicevox-web.ts
  • firmware/stackchan/speeches/wasm/tts-voicevox.ts
  • firmware/stackchan/utilities/manifest_wasm_utility.json
  • firmware/stackchan/wasm/led.ts
  • firmware/stackchan/wasm/microphone.ts
  • firmware/stackchan/wasm/tone.ts

Comment thread firmware/stackchan/drivers/wasm/driver-stub.ts Outdated
Comment thread firmware/stackchan/drivers/wasm/dynamixel-driver.ts Outdated
Comment thread firmware/stackchan/drivers/wasm/none-driver.ts Outdated
Comment thread firmware/stackchan/drivers/wasm/rs30x-driver.ts Outdated
Comment thread firmware/stackchan/drivers/wasm/scservo-driver.ts Outdated
Comment thread firmware/stackchan/drivers/wasm/sg90-driver.ts Outdated
Comment thread firmware/stackchan/main.ts Outdated
Comment thread firmware/stackchan/manifest_wasm.json Outdated
Comment thread firmware/stackchan/speeches/wasm/tts-stub.ts Outdated
Comment thread firmware/stackchan/wasm/microphone.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant