- Trading-card layout: accent stripe with github.com/<login> link,
square dithered avatar with frame, faux-bold display name,
flexible bio that wraps cleanly (no mid-word cuts, no ellipsis),
3-column stats panel (STARS / FOLLOWERS / REPOS).
- Bio falls back to a deterministic filler line when the user has
none, so the slot never reads as a render bug.
- Tighter 7-px line height for the bio gets one extra line into
the same band on 208x112.
- Drop heatmap + month axis (cleaner card; halves render time).
- Add month-initial axis under the heatmap
- Add current-streak counter in caption (accent-highlighted)
- Replace stats/bio fight with a single icon stat row (star, followers, repos)
- Fix bullet/middle-dot rendering bug (U+00B7 -> U+2022, in font table)
- Allow display name at scale 2 on wide tags only; safer truncation
- Robust avatar URL ?s= append (handles avatars without query string)
- Tighter geometry tuned for 208x112; still scales to 296x128
Worker (cloud-plugins/):
- New plugin 'GitHub Profile': avatar dithered upper-left, display
name + @handle (with accent star) + word-wrapped bio in the right
column, followers/repos line, and a 53x7 contribution heatmap
with an accent palette (red dots for everyday activity, black for
the rare hottest days). Tuned for 208x112 ESLs and adapts to
296x128 with a bigger avatar and roomier heatmap.
- Identicon plugin gains DiceBear style selector (pixel-art /
bottts / lorelei / adventurer / micah / fun-emoji / shapes) on
top of the original symmetric grid 'local' mode. Both are
rendered through the new shared image_util pipeline.
- Crypto plugin redesigned: editorial layout with corner brackets,
bold price headline, white-knockout delta badge with a real
triangle glyph, currency symbol prefix using the canvas font's
new euro / pound / yen glyphs, and a stippled accent fill under
the sparkline.
Canvas:
- setPixel is now last-write-wins across planes, so drawing black
on top of an accent-filled area produces a clean black pixel
instead of the muddy plane-conflict the e-paper driver was
showing previously. Every pixel is therefore exactly one of
white / black / accent which is what plugin authors intuit.
- New whitePixel + drawTextWhite primitives for knockout text
(e.g. white labels punched through a coloured badge).
- FONT_EXTRA shipped with the canvas for currency / arrow / shape
/ star / bracket glyphs. Plugins can now write '\u20AC1234' and
have the euro symbol Just Work.
Image pipeline (new image_util.ts):
- One fetchImageGray() that sniffs PNG vs JPEG, decodes via
upng-js / jpeg-js, composites alpha over white, and returns a
tightly-packed grayscale buffer.
- One blitGrayDither() that nearest-neighbour scales the gray
buffer to a destination rect and serpentine Floyd-Steinberg
dithers it on the way in. Used by identicon and github.
FAP:
- WiFi BMP writer is now plane-aware: writes the same biPlanes=1,
biBitCount=2, 3-entry palette layout the rest of the IR TX
pipeline already understood for web-image-prep BMPs. Tri-colour
tags now actually receive accent ink from cloud-rendered plugins.
- WiFi run scene un-forces accent: plugins are invoked with the
tag's actual accent capability and the BMP is opened with the
matching plane count.
- Run scene now calls bmp_abort on exit so an aborted transfer
doesn't leak the ~10 KB pixel buffer.
- Plugin manifest cache capped at TT_WIFI_MAX_FAP_PLUGINS=8 (down
from 16) and the UART RX stream buffer shrunk to 8 KB. Together
these cut WiFi-flow heap pressure by ~23 KB and fix the OOM
crashes that occasionally happened when opening WiFi Plugins.
- Broadcast scene auto-transmit fix: enter_callback now filters
by the >> Transmit << row index, and the cursor defaults to
row 0 instead of Transmit. Previously a stale OK key-release
from the prior submenu would land on the Transmit row and
blast the radio without any user action.
Previous version pulled accent ink too aggressively (accentPull 0.85)
so anything red-leaning collapsed to solid red. Real photographic feel
from a 3-ink palette comes from W/B halftones simulating greys with
the chromatic ink only sparsely overlaid - the newsprint illusion.
Three knobs now make this work:
- L_WEIGHT 3.5 (was 1.6): lightness completely dominates the metric
- CHROMA_CAP: source a/b axes pre-scaled to the achievable accent
chroma so the dither isn't asked for more colour than one ink can
deliver. Excess chroma gets dropped via FS error diffusion through
B+W neighbours.
- accentPull 0.06 (was 0.85): only a tiebreaker bonus, used in the
most strongly hue-aligned pixels.
The old quantiser pulled accent ink toward any chromatic pixel using a
flat chroma bonus, which smeared red across shadows and produced flat
red blobs without depth. Two fixes:
- Distance now weights L (lightness) ~1.6x more than chroma, so dark
pixels go to black and light pixels to white before colour competes.
That preserves the photograph's tonal structure.
- Accent attraction is the squared *signed projection* of the pixel's
chroma onto the accent direction. Red ink only pulls red-leaning
pixels (positive a*); blue/green never picks red. The squaring gives
a smooth ramp, so faint reds get sparse red dither and saturated
reds get dense red - matching how a real risograph layers a single
chromatic ink under W/B halftones.
Also flipped Floyd-Steinberg to a serpentine scan with mirrored kernel
on reverse rows, killing the diagonal worm artefacts that gave smooth
gradients an obviously-dithered look.
- Flipper FAP: WiFi Setup, Plugins picker, plugin-run scene wired into
Targeted Payloads -> <tag> -> WiFi Plugins
- Framed UART link to the dev board with bulk-read RX path and 16 KB
stream buffer to keep up with full plugin bursts
- ESP firmware: 900 KB UART<->HTTPS bridge, USB-Serial-JTAG console,
cert-bundle TLS, 16 KB worker stack to host mbedTLS handshake
- Cloudflare Worker: Crypto, Weather, Identicon plugins out of the
box; new plugins are a single TypeScript file, no Flipper reflash
- Shared protocol header + 1bpp BMP writer that matches web-image-prep
palette/stride conventions
- Add web-image-prep/: self-contained HTML5 image preparer with
perceptual Oklab 3-colour quantisation, Floyd-Steinberg/Atkinson/
Bayer dither, all supported tag profiles, BMPs that match the FAP
reader exactly. Auto-deployed to GitHub Pages.
- Add 'Set Image' under Targeted Payloads. Lists every BMP in
apps_data/tagtinker/dropped/, scrolls long names, marks foreign-
resolution files with a '~' prefix.
- Stream-time nearest-neighbour rescaling so any BMP can target any
tag at any page; image options screen is now Page-only.
- Remove Phone Sync menu and the Android companion app: replaced by
the browser preparer + drop folder.
- Static, IR-friendly transmit screen ('Tinkering Tag', point hint,
3-dot loader, 'Flipped ;)').
Add "+ Scan NFC" option in the Targeted Payloads menu.
Scans Mifare Ultralight NDEF tags, decodes the encoded
ESL ID, and auto-creates the target — no manual barcode
entry needed. Cyan LED blinks during scan. Loops until
a tag is found or the user presses Back.
New files:
- nfc/tagtinker_nfc.c/.h — NDEF URI decoder module
- scenes/tagtinker_scene_nfc_scan.c — NFC scan scene
Version bumped to 2.1, NFC credit added to About screen.
Pricer barcodes validate with (sum of all 17 chars) mod 10 == 0,
with the letter prefix contributing by its ASCII offset from '0'.
The old formula compared sum of the first 16 digits to the 17th,
rejecting valid codes like A4120365539013704.