nx_palette.nx
buildroot/runtime/nx_palette.nx
about
nx_palette.nx -- sub-byte voxel/pixel palette encoder.
THE unlock primitive for Minecraft-equivalent on $5 ESP32-class
hardware. At 3 bits per voxel and an 8-color palette, a full 32x32x32
chunk fits in 12288 bytes (12 KiB). Pair with chunk paging from
flash and the entire walkable world streams within the working RAM
of an RP2040 / Cortex-M0+ class part. This is what makes a true
Minecraft demo on $5 of silicon feasible -- without sub-byte packing,
the same chunk needs 32 KiB minimum (one byte per voxel) which
blows past most MCU SRAM budgets.
Composes:
nx_tier -- packing density scales naturally with NX_TIER_*;
MCU tier uses 1-3bpp, workstation tier may stay
at 8bpp for cache reasons
nx_budget -- the saved RAM bytes flow directly into the cell's
ram budget headroom
V1 supports 1bpp (2-color), 2bpp (4-color), 3bpp (8-color), 4bpp
(16-color), and 8bpp pass-through. Bit-level packing is LSB-first
within each byte so unpack is a small shift + mask, friendly to
embedded targets without barrel shifters.
Gap list (V1 honest perf verdict):
- no RLE compression on top of packing (queued for chunk save format)
- no dithering helper for 1bpp displays (caller's responsibility)
- palette index lookup not included (caller supplies palette)
- no SIMD unpack on workstation tier (scalar only)
- no compile-time-specialized variants per bpp (one function with
branch; per-bpp specialization queued behind benchmark gate)
genealogy_id: classic_video_indexed_color + minecraft_chunk_format
lineage_id: substrate_palette_v1
nx_safety_envelope:
intended_use: "Sub-byte palette index packing/unpacking for
memory-constrained voxel/pixel data"
sil_target: SIL1
evidence: [bit_alignment_correct, lossless_roundtrip,
bpp_validated_at_entry]
dependencies 2 imports · 12 importers
diagram shows first 10 each side; +0 more imports, +2 more importers in the complete lists below.
imports: nx_syscalls.nxnx_tier.nx
imported by: nx_chunk_paginate_test.nxnx_ecosystem_compose_test.nxnx_game_engine_compose_test.nxnx_game_session_drive.nxnx_minecraft_mcu_compose_test.nxnx_palette_test.nxnx_raycast_voxel_test.nxnx_substrate_compose_test.nxnx_tissue_test.nxnx_voxel_native.nxnx_world_seed.nxnx_world_seed_test.nx
structs
| none |
consts
| 48 | const NX_BPP_1: nx_int = 1 |
| 49 | const NX_BPP_2: nx_int = 2 |
| 50 | const NX_BPP_3: nx_int = 3 |
| 51 | const NX_BPP_4: nx_int = 4 |
| 52 | const NX_BPP_8: nx_int = 8 |
| 56 | const NX_PAL_OK: nx_int = 0 |
| 57 | const NX_PAL_ERR_BAD_BPP: nx_int = 1 |
| 58 | const NX_PAL_ERR_BAD_INDEX: nx_int = 2 |
functions
| 62 | func nx_pal_bpp_is_valid(bpp: nx_int) -> nx_int |
| 76 | func nx_pal_max_index(bpp: nx_int) -> nx_int |
| 90 | func nx_pal_packed_bytes(n_voxels: nx_size, bpp: nx_int) -> nx_size |
| 102 | func nx_palette_pack(src: *u8, n_voxels: nx_size, bpp: nx_int, dst: *u8) -> nx_int |
| 149 | func nx_palette_unpack(src: *u8, n_voxels: nx_size, bpp: nx_int, dst: *u8) -> nx_int |