Skip to content

feat: compress MicroCode's images with //% packable - #155

Merged
thomasjball merged 2 commits into
mainfrom
humanapp/image-opts
Sep 19, 2026
Merged

thomasjball merged 2 commits into
mainfrom
humanapp/image-opts

Conversation

@humanapp

@humanapp humanapp commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Moves MicroCode's images onto ui-core's new //% packable image compression (see related PR in microbit-apps/ui-core). 115 images now ship as one compressed pack instead of individual bmp literals: pixel data goes from 18,328 B to 9,922 B, and the V2 image from 475,236 B to 457,468 B (-17,768 B) against main.

//% packable
//% whenUsed
export const thermometer = bmp`...`

Images are still authored as literals in assets.ts. img.keys.json maps MicroCode's keys (tile ids and string ids) to them, npm run img:gen generates img.g.ts, and icons.get looks them up with _img.get(key).

What changed

  • Icons. The 98 tile and editor icons are back in assets.ts as //% packable + //% whenUsed literals, restored from the earlier move to scripts/icon-literals.json.
  • ui-core's icons. 12 of ui-core's icons that MicroCode uses are absorbed into its pack by qualified name ("ui.thermometer"), so they no longer ship as separate literals. ui.MISSING stays a literal, as the fallback.
  • Lookup. icons.get resolves the six operator glyphs and MISSING itself, then everything else through _img.get.
  • Direct references. Two images were referenced by const, which prevents packing: the editor's disk button now uses icons.get("disk"), and numberToImage's num2image array is replaced by _img.get("blocks" + n), so the classic-mode number images are decoded only if classic mode shows them.
  • Name collision. A packed melodyEditor literal collided with icondb.melodyEditor, which is drawn from a melody at startup. The packed one is now melodyEditorIcon, and tid 179 points at it.
  • Web-only samples. The sample-gallery images now have //% whenUsed. This annotation keeps them off the device.
  • Unused images. 11 literals nothing uses on the device (btn_stop, settingsGear, loud, quiet, arith_plus, arith_equals, one to five) are now //% whenUsed, and drop out.
  • Every image literal that isn't packed got a comment explaining why.

Heap

A packed image is decoded into the heap on first use and cached for the rest of the run. In MicroCode: if every image is decoded, that's 18,328 B. Measured on a microbit with every packed image decoded at boot, the GC heap still had 13,380 B free and the app ran normally. The classic-mode number images cost heap only if classic mode is used.

Testing

  • Every packed icon decodes to pixels identical to main's icon table (98/98), checked against its uncompressed data.
  • The post-build check finds no image shipping twice.
  • On a micro:bit V2, every icon renders correctly on the home screen, the editor and the tile pickers.
  • Classic mode can't be reached in the UI (HOME_ADD_SETTINGS is false), so the number images were checked with a diagnostic build that forced it on: all five matched checksums computed from their source literals.
  • The committed language hexes are current: microcode-v2.en.hex matches a fresh build byte for byte.

Other changes

  • README.md: the hex download link pointed at assets/microcode-v2.hex, a hand-committed build from November 2025. It now points at assets/microcode.hex, which the release workflow builds and commits.
  • .github/copilot-instructions.md: same filename correction.
  • Removes the stale assets/microcode-v2.hex.
  • package.json: adds img:gen, and removes build:hardware:v2, which passed a --variant flag the current makecode CLI doesn't accept.
  • Dependencies: ui-controls #v0.0.7 -> #v0.0.10 (pxt) and @microbit-apps/ui-core #v0.0.6 -> #v0.0.9 (npm).
  • Regenerated language hexes in assets/hex/.

Merge order

Merge after ui-core v0.0.9 and ui-controls v0.0.10 are tagged; until then CI can't resolve the new refs. Then npm install to refresh package-lock.json and the img-gen bin link.

@thomasjball
thomasjball merged commit 234b583 into main Sep 19, 2026
1 check failed
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.

2 participants