Implements the V09 mock end-to-end (per plans/2026-04-30_ux_redesign.md):
Top shell
- index.pug rebuilt around .app-shell with a slim 96px header.
- Underline-ribbon tab bar (Control / Program / Console / Settings)
replaces the old side menu and the inline #tab1..#tab4 system.
- Single 'All systems' pill collapses the legacy WiFi/Camera/Rotary/
IP/Version chip-soup into one popover (sys-popover) anchored to the
header; rotary toggle, camera feed and shutdown live there.
- Octagonal 88x88px STOP button wraps the existing <estop> SVG; STATE
pill with pulse-dot honors prefers-reduced-motion.
Routing
- app.js parse_hash maps every existing hash:
#control -> Control
#program / #program:auto -> Program
#console / #console:mdi|messages|indicators -> Console
#settings, #admin-general,
#admin-network, #motor:N, #tool, #io, #macros, #help,
#cheat-sheet -> Settings (rail picks inner)
- All deep links are preserved.
Control panel (control-view.pug + .js)
- 720px jog grid + 4-axis DRO + 4 KPI cards + 8-macro row.
- Jog tiles use V09 flat slate (#3f4b63) with diagonal helpers and
a ghost row for XY/Z origin shortcuts.
- Per-axis Settings/Set-zero/Home buttons grow to 72x72px.
- Status strip cards: State / Velocity-Feed / Spindle / Job. Tapping
the Spindle card opens the new override-drawer with feed + spindle
range inputs (resolved decision in plans/...).
- Macro row binds to state.macros.slice(0, 8); >8 lives in Settings.
- Drops the old <table> control-buttons, .info, .override and .tabs
blocks entirely.
Program panel (program-view.pug + .js)
- Extracts the Auto bar, file selectors, gcode-viewer and path-viewer
out of control-view.
- Action buttons (RUN/STOP/UPLOAD-FOLDER/UPLOAD-FILE/DOWNLOAD-FILE/
DELETE) at 84px with explicit color affordances.
- Reuses control-view's existing methods via the new program-mixin.
Console panel (console-view.pug + .js)
- Three sub-tabs: MDI / Messages / Indicators. Sub-tab persists in the
URL fragment (#console:messages etc.).
- MDI: terminal-style prompt + SEND, plus an 8-wide on-screen keypad
(G0/G1/G2/G3/G28/G92/M3/M5 + axis letters + CLEAR/SEND).
- Messages: pulls from .messages_log (mirrored from
state.messages); badge in the header tab counts unread.
- Indicators: mounts the existing <indicators> component.
Settings shell (settings-shell.pug + .js)
- New left rail navigator listing Display, Network, General/Firmware,
Spindle&Tool, IO, Motors 0..3, Macros, Cheat Sheet, Help.
- Inner area mounts the existing settings family templates via an
explicit v-if cascade (avoiding a Vue 1 :is reactivity quirk).
- Shutdown / Save buttons relocated from the dropped side menu.
JS plumbing
- main.js: Vue.config.async = false to keep dependent watchers in
sync when reactive data is mutated outside Vue's normal event loop
(e.g. from a hashchange listener).
- program-mixin.js extracted so control-view.js no longer carries the
file/macro/gcode methods that are now Program-only.
- control-view.js trimmed to jog/DRO/probe/home logic.
- console-view.js / settings-shell-view.js use a hashchange listener
+ local data props because Vue 1 cannot reliably observe
.sub_tab from a child component.
Stylus rewrite
- Removes the old .header (140px), .nav-header, .brand subtree, #menu,
#main, .control-view block, .info, .override, .toolbar, .macros-div,
.macros-button, the .tabs > input radio-tab system and the .control-
view #control media-query overrides. None of these are referenced
any more.
- Adds V09 tokens (jog/macro palette + accent + line/card colors) at
the top, the new shell rules, .ktab / .sys-btn / .state-badge /
.estop chrome, the .control-page grid, status strip + override
drawer, .program-page action / file bars and program body,
.console-page MDI keypad / messages / indicators panes, and the
.settings-shell rail.
- Adds a 1820px breakpoint that stacks the right column under the jog
on smaller portable monitors.
Hard cut: no config.ui.layout flag, the old shell is removed in this
single commit. side-menu.css is no longer included from index.pug.
Tested locally with agent-browser (1920x1080) on every top tab and
every settings sub-route; routing, active tab highlighting and inner
view selection all work without a controller connection.
OneFinity CNC Controller Firmware (W-axis fork)
This is the OneFinity / Buildbotics bbctrl firmware with a virtual W axis driven by an auxcnc ESP32 over USB serial. See docs/AUX_W_AXIS.md for the design and config.
Layout
src/avr/ AVR firmware (motion controller, AtxMega)
src/boot/ AVR bootloader
src/bbserial/ Linux kernel module for the bbserial driver
src/py/bbctrl/ Python control daemon (Tornado + websockets)
src/js/ Vue.js UI (legacy)
src/svelte-components/ Newer Svelte UI for dialogs and settings
src/pug/ Pug templates compiled into build/http/index.html
src/resources/ Static assets and config templates
scripts/ Install / update / RPi build helpers
docs/ Architecture, dev setup, W-axis docs
Build & flash (quick path, macOS or Linux)
The full build (make) requires avr-gcc, but the controller and UI
only depend on the Python + web parts. If you're shipping a UI/Python
change you don't need the AVR toolchain.
Prerequisites
- Node.js (any recent LTS) with npm
- Python 3 with setuptools
npm installonce at the project root (this is wired into thenode_modulesMake target, but on a fresh checkout it's clearer to do it explicitly)
npm install
(cd src/svelte-components && npm install)
macOS gotcha: esbuild platform pin
The Pi build leaves node_modules/esbuild pinned to
linux-arm64, which won't run on Darwin. If npm run build inside
src/svelte-components complains about esbuild, reinstall it for the
host:
cd src/svelte-components
rm -rf node_modules/esbuild
npm install esbuild@0.14.49 --no-save
(Use the version that matches package-lock.json.)
Build the web UI + Python sdist
# Build the Svelte components
(cd src/svelte-components && npm run build)
# Render pug templates and copy assets into build/http
make all # AVR step will fail without avr-gcc; safe to ignore
# if you didn't change anything under src/avr or src/boot
# Package
./setup.py sdist
ls dist/bbctrl-*.tar.bz2
make pkg is the canonical target but it tries to build AVR first. On
hosts without avr-gcc, run the steps above directly.
If bbctrl-*.tar.bz2 is missing src/bbserial/bbserial.ko, copy the
prebuilt .ko from a previous official release into src/bbserial/
before running setup.py sdist (the install script on the controller
just installs the existing module if a newer one isn't shipped).
Flash to a controller
curl -X PUT -H "Content-Type: multipart/form-data" \
-F "firmware=@dist/bbctrl-1.6.7.tar.bz2" \
-F "password=onefinity" \
http://onefinity.local/api/firmware/update
…or use the Make target:
make update HOST=onefinity.local PASSWORD=onefinity
The controller stops bbctrl, untars the package, runs
scripts/install.sh, and brings the service back up. Total downtime
is ~30-45s. Watch progress at http://<host>/ (you'll get 404s while
bbctrl restarts, then the new UI).
Verify the flash
curl -s http://onefinity.local/ | grep -c "OneFinity"
curl -s http://onefinity.local/api/aux/status # if W axis is enabled
Build & flash (full path, Debian/Linux)
For AVR + GPlan rebuilds, see docs/development.md.
That path uses qemu + chroot to cross-compile gplan for ARM and needs
the gcc-avr / avr-libc toolchain.
W axis (auxcnc)
This fork adds a virtual W axis. See docs/AUX_W_AXIS.md for:
- G-code surface (
G28 W0,G1 W25, etc.) - The G-code preprocessor and hook architecture
- aux.json keys
- REST API (
/api/aux/*) - UI surface (jog row in Control, settings panel in Settings)
- Edge cases (ESP reboot mid-job, limit closed at home start, …)