Sliced files previewed through a vendored copy of PrettyGCode in an
iframe. It drew each move as a screen-space line -- a line has no
thickness in the scene, so it cannot occlude the layer behind it, which
is why prints came out stringy and shimmered where layers crossed. Being
a separate app in a frame, it could be neither themed nor translated, and
carried its own machinery for detecting a proxy refusing the embed.
Now built on libvgcode, the renderer OrcaSlicer draws its own preview
with, vendored from three-slicer (AGPL, same as us). It takes the THREE
namespace as an argument and imports nothing, so it runs on our 0.181
rather than the 0.160 its package pins.
The parser is ours; upstream renders its own kernel's output and ships no
G-code parser at all. Two things it has to get right, both found by
checking a real plate rather than assuming:
- BambuStudio does not use the OrcaSlicer/PrusaSlicer annotations. It
writes "; FEATURE:", "; LINE_WIDTH:", "; CHANGE_LAYER" and
"; Z_HEIGHT:", not ";TYPE:", ";WIDTH:" and ";LAYER_CHANGE". Reading
only the latter showed a 52-layer print as 23,165 layers in one colour,
because with no layer marker recognised every travel Z-hop split a
layer and every segment took the fallback feature.
- It emits a tenth of its moves as G2/G3 arcs -- 706 extruding ones in a
single plate. Ignoring them punched holes through curved walls and tree
supports. Arcs with no X/Y are the helical travel lift and lay down
nothing, so they interpolate as travels.
Four colour modes: filament (default, from the AMS slots the file was
sliced with), feature, layer height, line width. Speed, fan and
temperature are deliberately absent -- upstream derives those from
settings rather than the toolpath, and guesses dressed as measurements
are worse than an honest omission. The parser now carries the data to do
them properly later.
Legend entries are switches. Hiding removes the records before the mesh
is built rather than recolouring them: the shader packs colour into a
single float with no alpha, so there is no transparent to set, and
removal is the useful behaviour anyway -- a hidden support stops
occluding what it covered.
The scene is built once and only the toolpath rebuilds. Doing otherwise
constructed a new WebGLRenderer on every render, because the buildVolume
default is an object literal and so a fresh identity each time; browsers
cap live WebGL contexts and drop the oldest, which blanked the canvas
after a few interactions.
utils/framing.ts goes with the iframe, along with six now-orphaned
strings in all 13 locales. src/lib/vendor is excluded from eslint --
acting on findings in vendored code makes it impossible to re-copy on the
next upstream release.
A clean Windows 10 install crashed on startup: init_db() -> SQLAlchemy async
engine -> greenlet failed with "DLL load failed while importing _greenlet:
The specified module could not be found", so uvicorn never bound :8000 and the
dashboard refused all connections while the NSSM service still showed running.
greenlet's _greenlet.pyd is C++ and needs vcruntime140_1.dll, which the
python.org embeddable distribution does not ship (it includes only
vcruntime140.dll, enough for the pure-C python313.dll). Machines with the VC++
2015-2022 redistributable already installed have the DLL in System32, which
masked the bug in testing.
Stage vcruntime140_1.dll and msvcp140.dll next to python.exe at build time,
from a vendored copy or the runner's System32, failing loudly if absent. The
Inno Setup [Files] step already copies staging\python\* recursively.
When the Windows build is triggered by a tag push (the path
docker-publish.sh and docker-publish-daily-beta.sh both take), use
the tag as the installer version instead of APP_VERSION. So a daily
tag v0.2.5b1-daily.20260610 produces
bambuddy-0.2.5b1-daily.20260610-windows-x64-setup.exe
matching the docker `daily` image and the GitHub prerelease. The
stable docker-publish.sh path is unchanged (tag v0.2.5b1 →
bambuddy-0.2.5b1-windows-x64-setup.exe). Manual workflow_dispatch
and local builds fall back to APP_VERSION as before.
nssm.cc returned 503 mid-CI-run, breaking the staging step. NSSM 2.24
hasn't shipped a new release since 2014, so the binary is effectively
static — vendoring under installers/windows/vendor/nssm.exe makes
builds reproducible and removes the only single-source download in
the pipeline. SHA-256 pinned in the comment in build.py for audit.
ffmpeg stays fetched from BtbN's GitHub mirror — it's actively
maintained and large (~80MB) so vendoring it would be unreasonable;
GitHub Releases are also far more reliable than nssm.cc.
- build.py now reads APP_VERSION from backend/app/core/config.py
(the canonical source used everywhere else — /system, support
bundles, FastAPI title) instead of pyproject.toml's stale 0.1.5.
Next installer is bambuddy-0.2.5b1-windows-x64-setup.exe.
- installers/windows/bambuddy.ico is a multi-resolution .ico
(16/32/48/64/128/256) generated from frontend/public/img/
favicon.png. Wired into SetupIconFile (installer .exe icon),
UninstallDisplayIcon (Add/Remove Programs), and the Start Menu /
desktop shortcuts — replaces the NSSM placeholder everywhere a
user sees Bambuddy on Windows.
vite.config.ts sets outDir to '../static' so the bundle lands at
<repo>/static/ — not frontend/dist/. Matches the runtime expectation
in config.py where static_dir = _app_dir / "static".
Also stage gcode_viewer/ next to static/ so the 3D preview iframe
routes in main.py (resolved via static_dir.parent / "gcode_viewer")
find their assets.
Strip macOS metadata files (.DS_Store, ._.*) from both copies — they
leak in from dev boxes and would only bloat the installer.
get-pip.py installs only pip itself; the embedded Python distribution
ships without setuptools or wheel. pip needs setuptools.build_meta as
the PEP 517 build backend for any sdist-only package — Bambuddy's
requirements.txt hits this on pyftpdlib 2.2.0 (sdist-only on PyPI).
Install both right after the pip bootstrap so requirements.txt installs
cleanly.
Lays down the Inno Setup + embedded Python pipeline for producing a
self-contained Bambuddy Windows installer .exe. The installer ships
an embedded Python 3.13, the pre-built React bundle, NSSM (service
supervisor) and ffmpeg — no host Python or Node required on the
target machine.
Architecture:
- Install: C:\Program Files\Bambuddy (admin install, one-time UAC)
- Data: C:\ProgramData\Bambuddy\data (preserved on uninstall)
- Service: registered via NSSM, runs as LocalSystem, autostart on boot
- UI: browser at http://localhost:8000 (Start Menu shortcut)
Files:
- installers/windows/build.py stages embedded Python + deps,
frontend bundle, NSSM, ffmpeg
- installers/windows/bambuddy.iss Inno Setup compiler script
- installers/windows/service/*.bat NSSM register/deregister
- .github/workflows/windows-installer.yml CI build on tag push + manual
dispatch, uploads .exe artifact
build.py hard-fails on non-Windows hosts; Wine cross-build is an
unsupported escape hatch behind --allow-non-windows. v1 ships unsigned
(SmartScreen warns on first run) — production signing will be wired up
via SignPath OSS once the application is approved.
See installers/windows/README.md for build prerequisites and the
embedded-Python ._pth gotchas.