Skip to content

The browser preview moves into the scene editor's Preview drawer, and frames serve the runtime - #489

Closed
mariusandra wants to merge 4 commits into
mainfrom
scene-editor-preview-panel
Closed

mariusandra wants to merge 4 commits into
mainfrom
scene-editor-preview-panel

Conversation

@mariusandra

Copy link
Copy Markdown
Collaborator

Under the frame pages the scene editor's preview was a split button with three
options and a modal, while scenes.frameos.net has had the preview inline for a
while. The Preview drawer now carries the picture itself.

The drawer

Three pinned pieces, the same in both hosts (the scene page's utility drawer
and the frame dashboard's scene control drawer): the picture on top, the
scene's state fields and the preview's own controls scrolling in the middle,
the buttons below — always in the fold.

Two buttons, plus Reset:

  • Preview in browser swaps the picture for the live wasm canvas in place.
    Editing a state field re-renders the preview once you stop typing; Stop
    preview
    gives the picture back.
  • Deploy to frame decides what that means on its own: send the whole
    edited scene when there are pending edits, activate by id and carry the
    state fields when there are none. The mechanism only ever shows up in the
    tooltip (docs/ui-vocabulary.md). frontend/src/utils/scenePreviewDeploy.ts
    is that rule as one pure module, which the button, its tooltip and the tests
    all read.

On the cloud the deploy is the durable set_scenes push carrying the frame's
whole scene list: that shim REPLACES what the device holds, so an ad-hoc
subset would silently drop the frame's other scenes. It is the same action the
drawer's change notice offers under the same name.

The surface shows the scene's stored snapshot when the frame has one. A deploy
dims it under a spinner until the frame reports the render — over whichever
signal that control plane has (a websocket render event, a new scene image,
the frame image bumping, the activation settling) — and then shows the frame's
own picture. A frame that says nothing gives up after 90 s with a notice
rather than spinning forever.

The scene page's left sidebar no longer carries a frame picture: two pictures
of the same frame competed for the same glance. The live badge and refresh
button it had moved onto the drawer's surface. LivePreviewModal is now only
the template preview; its pieces live in LivePreviewParts.tsx, shared with
the drawer, and the diagram toolbar offers the same two actions (a stored
"Preview on frame" preference folds into "Deploy to frame").

Frames serve the runtime

On the device the preview had nothing to run: the wasm runtime was never
served, so the button failed into a message telling the user to run a build
script. web_routes.nim now answers GET and HEAD /frameos-wasm/@asset out
of the embedded frame_web table under the same access rules and gzip
passthrough as /static/@asset, with application/wasm and text/javascript
content types. The release chain and the Docker image build the runtime into
frontend/public/frameos-wasm before the frame assets are baked, so a frame
previews with exactly the runtime version it runs — and the status row shows
which one. Pull-request builds stay wasm-less: there the route 404s, the SPA's
HEAD probe disables the button and says why. The embedded bytes cost about
1.25 MiB gzipped per binary, looked up per request and never decompressed at
startup.

The device also has no scene_preview_settings route, so the preview reads
the admin API's /api/settings there, through the same consent gate as every
other mode.

Tests

  • frameos/src/frameos/server/tests/test_web_routes_behavior.nim: the access
    rules, the 404s (including traversal-looking segments), the content types,
    gzip passthrough and the HEAD. The positive assertions skip themselves on a
    build without the runtime, so the suite passes in both worlds — verified by
    running it with the entries stripped. 18 tests pass.
  • cloud/apps/auth-web/src/test/shared-spa/scene-preview-deploy.test.ts: all
    twelve mode × changes × active combinations of the deploy rule as one exact
    table, the status line for every surface, and the split-button key
    normalisation. 19 tests.
  • e2e/frontend-visual/tests/frontend-e2e.spec.ts: the drawer's footer holds
    exactly the two buttons and Reset, with the old three-option labels absent.

pnpm verify from cloud/ is green (28/28). The scene-workspace and
frame-scenes visual snapshots will change; CI regenerates them.

Needs a bench

docs/manual-testing-todo.md has the box: all three control planes, the
snapshot → live → deploy sequence, and on the cloud a check that the frame's
other scenes survive a deploy from the drawer.

🤖 Generated with Claude Code

https://claude.ai/code/session_0189Yr2ywLDSYr6UvmRYS4w1

… frames serve the runtime

The per-frame scene editor's preview was a split button with three options and
a modal, while scenes.frameos.net has had the preview inline for a while. The
drawer now carries the picture itself, in three pinned pieces.

- The Preview drawer — the scene page's utility drawer and the frame
  dashboard's scene control drawer arrange the same three parts — pins the
  picture above the scroll area and the buttons below it, so the actions are
  always in the fold.
- Two buttons, plus Reset. "Preview in browser" swaps the picture for the live
  wasm canvas in place, and editing a state field re-renders it as you stop
  typing; "Stop preview" gives the picture back. "Deploy to frame" decides on
  its own what that means: send the whole edited scene when there are pending
  edits, activate by id and carry the state fields when there are none. The
  mechanism only ever shows up in the tooltip (docs/ui-vocabulary.md).
  utils/scenePreviewDeploy.ts is the rule, in one pure module the button, its
  tooltip and the tests all read.
- On the cloud that push is the durable set_scenes one, carrying the frame's
  whole scene list: the shim REPLACES what the device holds, so an ad-hoc
  subset would silently drop the frame's other scenes.
- The surface shows the scene's stored snapshot when the frame has one. A
  deploy dims it under a spinner until the frame reports the render — over
  whichever signal that control plane has — and then shows the frame's own
  picture. A frame that says nothing gives up after 90 s with a notice rather
  than spinning forever.
- The scene page's left sidebar no longer carries a frame picture: two
  pictures of the same frame competed for the same glance. The live badge and
  refresh button it had moved onto the drawer's surface.
- LivePreviewModal is now only the template preview. Its pieces live in
  LivePreviewParts.tsx, shared with the drawer, and the diagram toolbar offers
  the same two actions (a stored "Preview on frame" preference folds into
  "Deploy to frame").

On the device the preview had nothing to run: the wasm runtime was never
served, so the button failed into a message telling the user to run a build
script. web_routes.nim now answers GET and HEAD /frameos-wasm/@asset out of
the embedded frame_web table under the same access rules and gzip passthrough
as /static/@asset, with application/wasm and text/javascript content types.
The release chain and the Docker image build the runtime into
frontend/public/frameos-wasm before the frame assets are baked, so a frame
previews with exactly the runtime version it runs; PR builds stay wasm-less,
where the route 404s and the SPA's HEAD probe disables the button and says
why. The embedded bytes cost about 1.25 MiB gzipped per binary, looked up per
request and never decompressed at startup.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0189Yr2ywLDSYr6UvmRYS4w1
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

ESP32 firmware size

Built from d62421d by this run; compared with the latest release v2026.9.15.

Image This PR v2026.9.15 Δ
esp32-s3 app (OTA image) 3,160,224
87.7% of 3520K slot, 434 KB free
3,160,224 ±0
esp32-s3 merged flash image 3,225,760 3,225,760 ±0
esp32-s3-32mb app (OTA image) 3,160,208
76.5% of 4032K slot, 946 KB free
3,160,208 ±0
esp32-s3-32mb merged flash image 3,291,280 3,291,280 ±0

Breakdown by subsystem — esp32-s3

Subsystem This PR v2026.9.15 Δ
FrameOS core (Nim) 404,620 404,620 ±0
QuickJS 356,328 356,328 ±0
FrameOS apps (Nim) 316,786 316,786 ±0
pixie 300,949 300,949 ±0
Wi-Fi stack 295,300 295,300 ±0
Nim stdlib 249,026 249,026 ±0
ESP-IDF misc 178,065 178,065 ±0
Embedded font 146,358 146,358 ±0
String pool (attributed to efuse) 132,857 132,857 ±0
mbedTLS + certificates 132,539 132,539 ±0
lwIP / HTTP / WebSocket 126,644 126,644 ±0
fos_* firmware shell (C) 116,897 116,897 ±0
libc / libm / newlib 116,259 116,259 ±0
Storage (SPIFFS / FatFS / SD / NVS) 94,132 94,132 ±0
Nim packages (chrono, zippy, chroma, qrgen, ...) 72,043 72,043 ±0
Display drivers (C) 64,934 64,934 ±0
Crypto (monocypher) 35,149 35,149 ±0
Total mapped flash 3,138,886 3,138,886 ±0
Inside each subsystem

FrameOS core (Nim) — 404,620

Part This PR v2026.9.15 Δ
frameos/js_runtime 102,097 102,097 ±0
frameos/interpreter.nim 97,276 97,276 ±0
frameos/utils 89,928 89,928 ±0
embedded_main.nim 18,319 18,319 ±0
lib/tz.nim 16,751 16,751 ±0
embedded_runtime.nim 15,056 15,056 ±0
frameos_nim_glue.c.obj 9,814 9,814 ±0
frameos/planner.nim 9,605 9,605 ±0
frameos/types.nim 7,913 7,913 ±0
frameos/values.nim 6,873 6,873 ±0
frameos/apps.nim 6,054 6,054 ±0
frameos/spool.nim 5,678 5,678 ±0
embedded_scene.nim 4,945 4,945 ±0
frameos/app_config.nim 2,871 2,871 ±0
frameos/reboot_reason.nim 2,628 2,628 ±0
frameos/node_config.nim 2,590 2,590 ±0
frameos/app_capabilities.nim 2,489 2,489 ±0
fos_netguard.c.obj 2,092 2,092 ±0
frameos/runtime_diagnostics.nim 763 763 ±0
fos_version.c.obj 324 324 ±0
frameos/cloud 255 255 ±0
frameos/ids.nim 137 137 ±0
frameos/channels.nim 122 122 ±0
frameos/hal 40 40 ±0

QuickJS — 356,328

Part This PR v2026.9.15 Δ
quickjs.c.obj 283,813 283,813 ±0
libunicode.c.obj 50,174 50,174 ±0
libregexp.c.obj 13,995 13,995 ±0
dtoa.c.obj 5,681 5,681 ±0
cutils.c.obj 2,141 2,141 ±0
fos_qjs_glue.c.obj 449 449 ±0
fos_quickjs_tz.c.obj 75 75 ±0

FrameOS apps (Nim) — 316,786

Part This PR v2026.9.15 Δ
apps/data/icalJson 50,265 50,265 ±0
apps/render/calendar 30,707 30,707 ±0
apps/render/chart 21,541 21,541 ±0
apps/data/immich 17,695 17,695 ±0
apps/data/wikicommons 17,110 17,110 ±0
apps/data/openaiImage 13,970 13,970 ±0
apps/data/unsplash 11,084 11,084 ±0
apps/data/weather 10,193 10,193 ±0
apps/data/beRecycle 9,918 9,918 ±0
apps/render/split 9,648 9,648 ±0
apps/data/localImage 9,202 9,202 ±0
apps/data/eventsToAgenda 9,060 9,060 ±0
apps/data/googlePhotos 9,044 9,044 ±0
apps/apps.nim 8,636 8,636 ±0
apps/render/zoomPan 8,544 8,544 ±0
apps/data/haSensor 7,287 7,287 ±0
apps/data/openaiText 6,762 6,762 ±0
apps/data/xmlToJson 5,420 5,420 ±0
apps/render/text 5,419 5,419 ±0
apps/render/svg 5,176 5,176 ±0
apps/render/image 4,510 4,510 ±0
apps/data/rotateImage 3,457 3,457 ±0
apps/logic/setAsState 3,441 3,441 ±0
apps/data/downloadImage 3,345 3,345 ±0
apps/render/gradient 3,173 3,173 ±0
apps/data/qr 3,118 3,118 ±0
apps/data/frameOSGallery 3,046 3,046 ±0
apps/data/downloadUrl 3,045 3,045 ±0
apps/render/color 2,804 2,804 ±0
apps/data/newImage 2,676 2,676 ±0
apps/data/resizeImage 2,550 2,550 ±0
apps/data/log 2,283 2,283 ±0
apps/render/opacity 2,272 2,272 ±0
apps/data/prettyJson 2,213 2,213 ±0
apps/data/parseJson 1,844 1,844 ±0
apps/data/clock 1,835 1,835 ±0
apps/logic/nextSleepDuration 1,639 1,639 ±0
apps/logic/ifElse 1,476 1,476 ±0
apps/logic/breakIfRendering 1,378 1,378 ±0

pixie — 300,949

Part This PR v2026.9.15 Δ
pixie/fontformats/opentype.nim 55,507 55,507 ±0
pixie/fileformats/webp.nim 37,525 37,525 ±0
pixie/fileformats/svg.nim 37,143 37,143 ±0
pixie/paths.nim 32,570 32,570 ±0
pixie/fileformats/jpeg.nim 25,338 25,338 ±0
pixie/fileformats/png.nim 22,849 22,849 ±0
pixie/images.nim 15,783 15,783 ±0
pixie/fonts.nim 11,019 11,019 ±0
pixie/paints.nim 9,889 9,889 ±0
pixie/fileformats/bmp.nim 8,234 8,234 ±0
pixie/common.nim 7,416 7,416 ±0
pixie/blends.nim 6,520 6,520 ±0
pixie/fileformats/gif.nim 5,925 5,925 ±0
pixie/inflatestream.nim 5,325 5,325 ±0
pixie.nim 5,224 5,224 ±0
pixie/fileformats/webp_vp8_tables.nim 3,881 3,881 ±0
pixie/fileformats/ppm.nim 3,681 3,681 ±0
pixie/contexts.nim 3,038 3,038 ±0
pixie/fileformats/qoi.nim 2,682 2,682 ±0
pixie/internal.nim 754 754 ±0
pixie/rgb565.nim 381 381 ±0
pixie/fontformats/svgfont.nim 215 215 ±0
pixie/decodebudget.nim 50 50 ±0

Wi-Fi stack — 295,300

Part This PR v2026.9.15 Δ
libnet80211.a 136,168 136,168 ±0
libpp.a 62,154 62,154 ±0
libwpa_supplicant.a 54,900 54,900 ±0
libphy.a 34,176 34,176 ±0
libesp_wifi.a 4,780 4,780 ±0
libesp_phy.a 2,541 2,541 ±0
libesp_coex.a 291 291 ±0
libcore.a 287 287 ±0
libespnow.a 3 3 ±0

Nim stdlib — 249,026

Part This PR v2026.9.15 Δ
pure/collections/tables.nim 70,556 70,556 ±0
system.nim 46,659 46,659 ±0
pure/unicode.nim 17,405 17,405 ±0
pure/times.nim 16,984 16,984 ±0
pure/json.nim 13,414 13,414 ±0
std/private/dragonbox.nim 10,351 10,351 ±0
pure/strutils.nim 8,520 8,520 ±0
pure/parsexml.nim 5,999 5,999 ±0
pure/algorithm.nim 5,368 5,368 ±0
pure/base64.nim 5,302 5,302 ±0
pure/hashes.nim 4,114 4,114 ±0
pure/xmlparser.nim 3,567 3,567 ±0
pure/parsejson.nim 3,553 3,553 ±0
std/formatfloat.nim 3,508 3,508 ±0
pure/uri.nim 3,225 3,225 ±0
pure/collections/sets.nim 3,211 3,211 ±0
pure/streams.nim 2,820 2,820 ±0
pure/strformat.nim 2,641 2,641 ±0
std/syncio.nim 2,355 2,355 ±0
pure/xmltree.nim 2,051 2,051 ±0
pure/lexbase.nim 1,805 1,805 ±0
pure/parseutils.nim 1,757 1,757 ±0
system/exceptions.nim 1,598 1,598 ±0
pure/strtabs.nim 1,568 1,568 ±0
pure/pathnorm.nim 1,356 1,356 ±0
pure/options.nim 1,118 1,118 ±0
std/private/ospaths2.nim 1,032 1,032 ±0
pure/collections/lists.nim 983 983 ±0
system/dollars.nim 891 891 ±0
pure/random.nim 835 835 ±0
std/private/digitsutils.nim 651 651 ±0
pure/math.nim 650 650 ±0
std/oserrors.nim 637 637 ±0
std/private/osdirs.nim 580 580 ±0
std/monotimes.nim 401 401 ±0
std/private/oscommon.nim 329 329 ±0
std/envvars.nim 250 250 ±0
std/private/decode_helpers.nim 240 240 ±0
std/private/ossymlinks.nim 187 187 ±0
pure/bitops.nim 162 162 ±0
pure/os.nim 99 99 ±0
std/private/osfiles.nim 96 96 ±0
std/assertions.nim 87 87 ±0
core/macros.nim 69 69 ±0
system/iterators.nim 33 33 ±0
system/ctypes.nim 9 9 ±0

ESP-IDF misc — 178,065

Part This PR v2026.9.15 Δ
libesp_hw_support.a 37,650 37,650 ±0
libhal.a 21,464 21,464 ±0
libfreertos.a 17,194 17,194 ±0
libesp_system.a 13,780 13,780 ±0
libesp_driver_uart.a 11,627 11,627 ±0
libheap.a 8,660 8,660 ±0
libesp_driver_i2c.a 8,062 8,062 ±0
libesp_driver_spi.a 7,756 7,756 ±0
libconsole.a 5,733 5,733 ±0
libjson.a 4,940 4,940 ±0
libesp_driver_gpio.a 3,890 3,890 ±0
libbootloader_support.a 3,813 3,813 ±0
libxtensa.a 3,691 3,691 ±0
libesp_driver_usb_serial_jtag.a 3,408 3,408 ±0
libesp_ringbuf.a 3,322 3,322 ±0
libesp_event.a 3,257 3,257 ±0
libesp_mm.a 2,451 2,451 ±0
libapp_update.a 2,422 2,422 ±0
libesp_psram.a 2,329 2,329 ±0
libesp_timer.a 2,326 2,326 ±0
libsoc.a 2,315 2,315 ±0
libesp_adc.a 2,289 2,289 ±0
liblog.a 1,375 1,375 ±0
libpthread.a 1,365 1,365 ±0
libesp_security.a 1,050 1,050 ±0
libesp_rom.a 902 902 ±0
libesp_app_format.a 507 507 ±0
libxt_hal.a 437 437 ±0
libesp_common.a 26 26 ±0
libesp_pm.a 24 24 ±0

Embedded font — 146,358

Part This PR v2026.9.15 Δ
assets/fonts.nim 146,358 146,358 ±0

String pool (attributed to efuse) — 132,857

Part This PR v2026.9.15 Δ
esp_efuse_utility.c.obj 131,811 131,811 ±0
esp_efuse_rtc_calib.c.obj 566 566 ±0
esp_efuse_table.c.obj 268 268 ±0
esp_efuse_api.c.obj 151 151 ±0
esp_efuse_startup.c.obj 61 61 ±0

mbedTLS + certificates — 132,539

Part This PR v2026.9.15 Δ
libmbedcrypto.a 71,391 71,391 ±0
libmbedtls.a 45,803 45,803 ±0
libmbedx509.a 7,084 7,084 ±0
libesp-tls.a 6,709 6,709 ±0
libesp_https_server.a 1,552 1,552 ±0

lwIP / HTTP / WebSocket — 126,644

Part This PR v2026.9.15 Δ
liblwip.a 78,305 78,305 ±0
libhttp_parser.a 10,350 10,350 ±0
libesp_http_server.a 10,016 10,016 ±0
libtcp_transport.a 8,237 8,237 ±0
libespressif__esp_websocket_client.a 6,826 6,826 ±0
libesp_http_client.a 6,666 6,666 ±0
libesp_netif.a 6,244 6,244 ±0

fos_ firmware shell (C)* — 116,897

Part This PR v2026.9.15 Δ
fos_http.c.obj 22,202 22,202 ±0
fos_cloud.c.obj 16,975 16,975 ±0
fos_console.c.obj 13,601 13,601 ±0
fos_client.c.obj 10,499 10,499 ±0
fos_scenes.c.obj 7,551 7,551 ±0
fos_settings.c.obj 6,511 6,511 ±0
fos_ota.c.obj 5,039 5,039 ±0
fos_config.c.obj 4,298 4,298 ±0
fos_wifi.c.obj 3,201 3,201 ±0
fos_assets.c.obj 3,124 3,124 ±0
fos_cloud_contract.c.obj 2,896 2,896 ±0
fos_sd_probe.c.obj 2,753 2,753 ±0
fos_assets_sd.c.obj 2,480 2,480 ±0
fos_schedule.c.obj 2,351 2,351 ±0
fos_buttons.c.obj 2,139 2,139 ±0
fos_status_screen.c.obj 2,049 2,049 ±0
main.c.obj 1,667 1,667 ±0
fos_config_parse.c.obj 1,467 1,467 ±0
fos_url_guard.c.obj 1,397 1,397 ±0
fos_tz.c.obj 1,381 1,381 ±0
fos_battery.c.obj 1,140 1,140 ±0
fos_minisig.c.obj 497 497 ±0
fos_framebuffer.c.obj 483 483 ±0
fos_assets_path.c.obj 259 259 ±0
fos_power.c.obj 241 241 ±0
fos_battery_filter.c.obj 214 214 ±0
fos_wake.c.obj 184 184 ±0
fos_board.c.obj 179 179 ±0
fos_json_guard.c.obj 119 119 ±0

libc / libm / newlib — 116,259

Part This PR v2026.9.15 Δ
libc.a 76,467 76,467 ±0
libm.a 31,563 31,563 ±0
libnewlib.a 6,609 6,609 ±0
libstdc++.a 1,476 1,476 ±0
libgcc.a 98 98 ±0
libcxx.a 46 46 ±0

Storage (SPIFFS / FatFS / SD / NVS) — 94,132

Part This PR v2026.9.15 Δ
libspiffs.a 20,380 20,380 ±0
libfatfs.a 20,133 20,133 ±0
libspi_flash.a 14,168 14,168 ±0
libnvs_flash.a 13,741 13,741 ±0
libsdmmc.a 13,013 13,013 ±0
libvfs.a 6,196 6,196 ±0
libesp_driver_sdspi.a 3,858 3,858 ±0
libesp_partition.a 1,960 1,960 ±0
libesp_vfs_console.a 678 678 ±0
libnvs_sec_provider.a 5 5 ±0

Nim packages (chrono, zippy, chroma, qrgen, ...) — 72,043

Part This PR v2026.9.15 Δ
QRgen 3.1.0 22,036 22,036 ±0
chrono 0.3.1 15,510 15,510 ±0
zippy 0.10.19 15,280 15,280 ±0
chroma 1.0.0 14,924 14,924 ±0
checksums 0.2.1 3,371 3,371 ±0
flatty 0.3.4 533 533 ±0
jsony 1.1.5 272 272 ±0
bumpy 1.1.3 117 117 ±0

Display drivers (C) — 64,934

Part This PR v2026.9.15 Δ
(everything else) 21,290 21,290 ±0
frameos_panel_table.c.obj 6,685 6,685 ±0
EPD_13in3e.c.obj 1,792 1,792 ±0
EPD_3in7.c.obj 1,564 1,564 ±0
EPD_5in79.c.obj 1,481 1,481 ±0
DEV_Debug.c.obj 1,309 1,309 ±0
EPD_2in7.c.obj 1,292 1,292 ±0
EPD_4in2.c.obj 1,262 1,262 ±0
EPD_7in3e.c.obj 1,208 1,208 ±0
EPD_4in2_V2.c.obj 1,184 1,184 ±0
DEV_Config_esp.c.obj 1,180 1,180 ±0
EPD_4in26.c.obj 1,123 1,123 ±0
29 smaller rows 23,564 23,564 ±0

Crypto (monocypher) — 35,149

Part This PR v2026.9.15 Δ
monocypher.c.obj 31,916 31,916 ±0
monocypher-ed25519.c.obj 3,233 3,233 ±0
Largest 30 objects
Object Subsystem This PR v2026.9.15 Δ
quickjs.c.obj QuickJS 283,813 283,813 ±0
assets/fonts.nim Embedded font 146,358 146,358 ±0
esp_efuse_utility.c.obj String pool (attributed to efuse) 131,811 131,811 ±0
frameos/interpreter.nim FrameOS core (Nim) 97,276 97,276 ±0
nim/lib/pure/collections/tables.nim Nim stdlib 70,556 70,556 ±0
frameos/js_runtime/app_runtime.nim FrameOS core (Nim) 61,493 61,493 ±0
pkgs/pixie-6.1.0/pixie/fontformats/opentype.nim pixie 55,507 55,507 ±0
libunicode.c.obj QuickJS 50,174 50,174 ±0
nim/lib/system.nim Nim stdlib 46,659 46,659 ±0
apps/data/icalJson/ical.nim FrameOS apps (Nim) 44,568 44,568 ±0
pkgs/pixie-6.1.0/pixie/fileformats/webp.nim pixie 37,525 37,525 ±0
pkgs/pixie-6.1.0/pixie/fileformats/svg.nim pixie 37,143 37,143 ±0
frameos/utils/image.nim FrameOS core (Nim) 34,490 34,490 ±0
pkgs/pixie-6.1.0/pixie/paths.nim pixie 32,570 32,570 ±0
monocypher.c.obj Crypto (monocypher) 31,916 31,916 ±0
frameos/js_runtime/runtime.nim FrameOS core (Nim) 30,086 30,086 ±0
pkgs/pixie-6.1.0/pixie/fileformats/jpeg.nim pixie 25,338 25,338 ±0
apps/render/calendar/app.nim FrameOS apps (Nim) 23,659 23,659 ±0
pkgs/pixie-6.1.0/pixie/fileformats/png.nim pixie 22,849 22,849 ±0
fos_http.c.obj fos_* firmware shell (C) 22,202 22,202 ±0
apps/render/chart/app.nim FrameOS apps (Nim) 18,940 18,940 ±0
embedded_main.nim FrameOS core (Nim) 18,319 18,319 ±0
frameos/utils/status_screen.nim FrameOS core (Nim) 18,111 18,111 ±0
x509_crt_bundle.S.obj mbedTLS + certificates 17,928 17,928 ±0
nim/lib/pure/unicode.nim Nim stdlib 17,405 17,405 ±0
nim/lib/pure/times.nim Nim stdlib 16,984 16,984 ±0
fos_cloud.c.obj fos_* firmware shell (C) 16,975 16,975 ±0
lib/tz.nim FrameOS core (Nim) 16,751 16,751 ±0
apps/data/immich/app.nim FrameOS apps (Nim) 16,148 16,148 ±0
pkgs/pixie-6.1.0/pixie/images.nim pixie 15,783 15,783 ±0

Flash = .text + .rodata from the linker map via esp_idf_size; "Inside each subsystem" splits every bucket one level down (the Nim core by directory, apps by app, packages by package, ESP-IDF by archive) over all objects, not just the largest. "String pool (attributed to efuse)" is the linker's merged string-literal pool for the whole image, not efuse code — see docs/esp32-image-size.md.

FrameOS Bot and others added 3 commits September 12, 2026 22:54
Conflicts:
- docs/manual-testing-todo.md — main (#490) closed the whole non-ESP32 side
  and left only the ESP32 bench; this branch had added a Preview drawer box
  main never saw. Took main's closures and carried the Preview drawer box
  over under its Backend (self-hosted) bench heading, header line reworded
  so it no longer claims the non-ESP32 side is empty.
- four frame-scenes--expanded-scene snapshots — took main's baseline (#490's
  real UI change). CI re-renders these with --update-snapshots and the bot
  job commits the result, so this branch's own diffs come back from CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019tywARkZTUQNozKsXMHEq9
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