Fix/remove grayscale parameter - #78
Conversation
Use the TRMNL palette as the single source of truth for display rendering so bitmap gray levels are derived instead of stored or passed independently.
Normalize device log payloads before rendering so current firmware messages and legacy log_message entries display correctly.
Prevent oversized grayscale PNGs by encoding palette-limited output, and preserve structured device log messages instead of coercing them to object strings.
The TRMNL X (model v2) is an X-class board whose firmware allocates a 750KB receive buffer, but the model registry ships a generic ~92KB limit that falsely flags valid gray-16 screens as oversized. Override the size limit for X-class models to match firmware MAX_IMAGE_SIZE.
Collapse the weekly calendar to a 3-day view on narrow screens with an optional daysToShow override (0 = auto, 1-7 = explicit). Draw a current-time line in today's column, gray out the meeting in progress, and shade events per source calendar (grayscale so it survives e-ink quantization).
Replace generated TRMNL schema artifacts with local runtime validation so registry data stays checked without carrying stale generated files.
Share bitmap URL, image, dimension, and playlist ordering helpers so dashboard, device, recipe, playlist, and mixup previews render through the same path.
Move device callback reads and writes behind scoped helpers and shared mappers so setup, display, log, and device API routes have clearer ownership boundaries.
Share pagination and device-log entry rendering so system and device log screens keep less duplicated table behavior.
Drop unused UI, proxy, logger, recipe, and TRMNL helper code so the remaining modules expose only paths that are still used.
Palette / quantization — current model + way forwardCross-ref: scope split and #80 follow-up in #80. Problem 1 — "how many gray levels" has three independent definitionsA device's gray-level count (BW=2, gray-4=4, gray-16=16) is the same fact whether we're encoding a BMP, building an error image, or quantizing a device PNG. Today it's defined in three places that can drift independently:
Adding a new grayscale palette today requires updating the map, the inline branch, and JSON independently. There is no shared Fix: one resolver — Problem 2 — the grayscale posterize path never runsFor The consequence is Problem 3. Problem 3 — Floyd–Steinberg runs on the entire frame, not just images
For UI, that's actively wrong, not just slow. Concrete cases on current recipes:
Already correct in #78Dropping the independent Way forward (for #78)
Why hard quantize is the right default now: BYOS targets many models, palettes, and bit depths (1-bit BW through 16-level gray and color). The shared payload across all of them is text, layout, and icons — not photos. Those must stay sharp and read identically in intent on every screen. A per-pixel nearest-level snap is local, content-independent in cost, and preserves crisp type and uniform fills. If a richer dither is ever wanted for UI, Bayer (fixed threshold-matrix lookup) and threshold quantize (per-pixel: luminance ≥ 50% → high level, < 50% → low level) are both local and cheap — same cost regardless of frame content, predictable across devices — and are the right tools, not FS. Images are the author's call, not the renderer's. Photographic / continuous-tone content is the only place dither helps, and the author knows their content. So for images specifically, give them two routes (both in #80): render the image themselves and pre-quantize per device (conditional classes / per-device assets), or opt into a server helper ( |
|
Working on it right now, good point on the FS applied everywhere |
This screen doesn't work anymore in 1bit no dithering |
Working as intended, I think. On 1-bit, semantic Two things worth mentioning:
Authors keep full control either way: |
Use one pixelated preview image component across dashboards, playlists, mixups, and recipe previews so loading states and bitmap rendering stay consistent.
Detect already-complete images and prioritize above-the-fold recipe previews so cached or eager bitmaps do not stay hidden behind placeholders.
Handle Date values returned by the database mapper so device status and timestamps survive pg driver type changes.
Let the app refresh visible server data on an interval and adopt fresh device props without overwriting in-progress edits.
Use the generated friendly ID in default device names so mock and provisioned devices are easier to recognize.
Move recent and full system log lists onto a shared responsive renderer, improve mobile readability, and label the header icon controls.
…r [skip release] Fix/remove grayscale parameter
Rebase onto main (#78 palette SSOT, snap quantizer) and merge the overlapping image paths into one surface: - prepareDeviceImage / prepareDeviceImageFromContext (default Bayer) - Author-selectable methods: bayer, white-noise, floyd-steinberg, etc. - Color e-ink: bayerRgbToPalette in palette-reduction - Gray paths use Lab L* luminance (lib/render/luminance.ts) - RecipeDeviceContext carries levels + colorPalette via buildRecipeDeviceContext - DeviceImage component; album/wikipedia use unified prep - responsive-example: dither-* on 1-bit, solid colors on color screens - Remove frame-wide dither flag; keep 1× rasterize (no supersample) - Document e-ink palette mapping and update image dither docs Co-authored-by: Cursor <cursoragent@cursor.com>
No description provided.