Conversation
Compile HelixScreen's actual LVGL 9.5 widgets to WebAssembly and run them in a browser — a fast, headless-screenshotable way to iterate on widget visuals and animation without a device or the full app. build_widget.sh links a harness main() (smoke / widget / ace — the last a full interactive ACE-page mockup with a mocked load/unload run) against LVGL + helix-xml + a small stub layer for the app-side symbols the widgets touch. launch.sh builds + serves; pw_shot.py / ace_shot.py drive Playwright/Chromium for autonomous screenshots. Full docs in wasm/README.md; CLAUDE.md points future agents at it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
set_multiace_mode() wrote names, display names and per-unit topologies behind `if (system_info_.units.size() >= 3)`, but nothing in it ever grew that vector past the single entry the constructor pushes, so the guard was always false and the block dead. get_system_info() overlays system_info_.units onto the registry-built ones, so unit 0 kept the generic "Mock MMU" and the U1 screen captioned itself with a name that belongs to no product; only unit_topologies_ kept the ACEs drawing as combiners. Build the metadata the way every other multi-unit profile does, with "SnapSwap" scoped to this profile and the ACE names mirroring AmsBackendMultiAce (display "ACE 1"/"ACE 2" — the model name is what a lone ACE shows, and the dead block put it on both). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Compiles ~600 app TUs unmodified for wasm32 and boots them from app_main.cpp the way Application::run() boots the desktop, so the three Snapmaker U1 screens — Multi-Filament, SnapSwap, multiACE — render as production XML driven by the real AmsOverviewPanel, theme_manager, subject graph and AmsState. Only the printer is mocked. app_srcs.txt is derived, not curated: the link closure of the AMS panel objects taken from a native build with nm, filtered to what emcc accepts; stubs_app.cpp holds the whole remainder (libhv's sync HTTP client, the wpa_supplicant socket) — 26 symbols the AMS pages never call. helix_ctl exports the `helix-screen ctl` command surface into the page through RemoteControlServer::serve_inproc(), so the same JSON-RPC vocabulary and widget locators drive a browser; ctl_shot.py walks all three screens headlessly. Its single-threaded arm queues onto UpdateQueue and pumps rather than calling inline, because handlers that rebuild widget subtrees expect to run inside process_pending(), and pumps on the CLOCK because hundreds of idle lv_timer_handler() calls fit inside the queue timer's 1 ms period. wifi_backend/wifi_manager gain __EMSCRIPTEN__ arms beside the existing ESP_PLATFORM ones (no radio in a tab), and HistoryListPanel::PAGE_SIZE is renamed — it collides with a macro in Emscripten's limits.h. Build flags that are load-bearing rather than tuning (the C++-only PCH force-include, -fexceptions, the non-unwinding main-loop form) are documented in wasm/README.md along with the two known limitations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
topmost_visible() packs its ranking key with a field at bit 40, in a `long`. That is 64 bits on the x86-64 desktop this was written on and 32 bits on every 32-bit target we build for, where a shift wider than the type is undefined behaviour and clang emits an unconditional trap. So `ctl click btn_unload` -- any name that exists in more than one panel, which is most of them -- killed the process on armhf/MIPS devices instead of picking the visible copy. Found by running the command surface under wasm32, which has the same 32-bit long. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ScriptedU1 derives from the real AmsBackendMultiAce and replaces only the two ends of the wire: execute_gcode() is intercepted rather than reaching Moonraker, and the reply arrives as handle_status_update() frames on an lv_timer, in the channel_state vocabulary classify_channel_state() reads. Everything between -- the dispatch rules, the load latch, the phase-to-step mapping, the ACE-fed vs feeder split -- is production code, so an unload on an ACE-fed head ends at preload_finish because the ACE performs the retract, and loading a bay onto an occupied head emits ACE_UNLOAD_HEAD + ACE_LOAD_HEAD into one 6-step LOAD_SWAP bar. Frame shapes follow the live capture in tests/fixtures/snapmaker_u1/. Heaters are modelled rather than scripted: frames set a target and never a temperature, and one 5 Hz owner interpolates toward it -- deadline-based, so a ramp lands on target at exactly the requested time whatever distance it covers. Scripts that wrote temperatures directly while a second timer wrote the same field made the Heat step's live readout look like noise. A heater held at an active target is now dead steady; only a cold one wanders. HEAT_MS is 3 s for a full ambient-to-working span and proportionally less for a shorter ramp, so a swap's second half does not sit through a heat cycle for a temperature its first half already reached. Each frame is published to both the AMS backend and PrinterState, as the notify stream does; feeding only the backend left every temperature in the UI at 0 C and the sidebar's preheat gate never opened. ops_shot.py drives all three operations headlessly through the helix_ctl bridge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Compile HelixScreen's actual LVGL 9.5 widgets to WebAssembly and run them in a browser — a fast, headless-screenshotable way to iterate on widget visuals and animation without a device or the full app. build_widget.sh links a harness main() (smoke / widget / ace — the last a full interactive ACE-page mockup with a mocked load/unload run) against LVGL + helix-xml + a small stub layer for the app-side symbols the widgets touch. launch.sh builds + serves; pw_shot.py / ace_shot.py drive Playwright/Chromium for autonomous screenshots. Full docs in wasm/README.md; CLAUDE.md points future agents at it.