Field notes
One URL, 264 possible wallpapers
Inside the small API, deterministic content system, and edge cache behind WallCab.
WallCab’s public interface is intentionally dull: selected interests, a visual choice, a size, and an optional personal note go in; a PNG comes out. The machinery behind it has a harder job. It must make provider-driven content feel stable, source-aware photography feel safe, optional private uploads feel controlled, and full-resolution image composition feel immediate.
One lesson, many presentations
Eight learning categories, eleven themes, and three screen sizes produce 264 possible daily images. That does not mean 264 different lessons. The selected interest set and UTC date resolve one category; theme and size affect only its presentation. Five photographic themes change their source image daily, while six fixed SVG originals keep a consistent art direction.
An optional custom upload creates another presentation without expanding the built-in matrix. Its opaque ID replaces only the background, while the lesson, date, size, and selected built-in fallback keep the same deterministic rules.
This detail matters. A person can switch from Nature to AMOLED—or from a standard iPhone to a Max—without quietly changing what the day was meant to teach.
External first does not mean external only
Vocabulary begins with advanced semantic prompts in Datamuse. WallCab uses syllable count and corpus-frequency metadata to reject basic candidates, then combines Datamuse and Free Dictionary pronunciation data with a sourced definition. The resulting IPA pronunciation is printed beneath the term. The remaining categories rotate through deeper, category-specific Wikimedia searches before using the selected page’s summary and URL.
Every result is untrusted until it passes validation. WallCab checks each candidate’s structural fields, text length, source presence, unsafe titles, and composition fit. Bad candidates are discarded individually. If no complete result survives, a reviewed local lesson takes over. Mixing half of a provider result with half of a fallback would create muddled attribution, so the fallback is atomic.
The accepted lesson is cached once for the UTC day. Response headers and the companion status endpoint report whether it came from an external provider or the reviewed catalog.
The local catalog is a seat belt, not the engine.
Rendering is a bounded problem
Sharp turns the chosen background and SVG text layer into a full-size PNG. Each device preset has exact dimensions, but the composition uses proportional safe zones so the hierarchy survives all three.
The encoder tries a descending sequence of indexed palettes. The first output below 2.2 MiB wins. A file that cannot meet the ceiling is an error rather than an unexpectedly enormous response.
Cache without dependence
A Cloudflare Worker and KV store generated variants for the active day. The public asset URL is signed and short-lived. Private cache reads and writes use an HMAC over the request method, path, timestamp, and body hash.
This is an optimization boundary, not a correctness boundary. On a cache miss, Next.js renders the image and returns it immediately, then uploads it in the background. If the Worker is down, the caller still gets the wallpaper.
Personal notes change that final step. The renderer escapes and bounds the text, then returns the personalized image directly without putting that final PNG in the shared Worker cache. The daily lesson and background can still use their ordinary active-day caches.
That principle appears throughout WallCab: every external service can improve the result, but none should have the power to leave the lock screen empty.