A browser-based tool for generating 16x16 pixel track icons for Yoto music player custom cards. Enter a label, choose a color, and download a ready-to-upload ZIP of numbered icons for every track on your card.
Live app: https://pwarf.github.io/YotoIconGenerator/
- Custom label — up to 4 characters (A-Z, 0-9, space, and a small set of punctuation), rendered in a pixel font sized to fit Yoto's 16x16 icon format
- Batch generation — generates one icon per track (1 to 99), each stamped with its track number
- Live preview — see exactly how an icon will look, at actual size and scaled up, before generating
- Custom icon color — pick any color via a standard color picker
- Auto-named ZIP export — downloads a single ZIP containing all icons as
01.png,02.png, etc., inside a folder you can name - Client-side only — no uploads, no server round-trip; everything is generated and packaged directly in the browser
The app is a Blazor WebAssembly (.NET 9) single-page application with no backend — it's compiled to WASM and served as static files, which is what makes GitHub Pages hosting possible.
- UI layer (
Pages/Home.razor) — a single-page Razor component that owns all form state (label, track count, color, folder name), validates the label against the supported glyph set, and drives a live preview. IconGeneratorService(Services/IconGeneratorService.cs) — orchestrates icon creation: renders a single icon to PNG bytes, produces a base64 data URI for the live preview, and bundles a full run of track icons into a ZIP usingSystem.IO.Compression.PixelFontRenderer(Services/PixelFontRenderer.cs) — lays out and rasterizes text onto a 16x16 RGBA pixel buffer, centering the label on one line and the track number below it using a 3x5 bitmap font.GlyphData(Services/GlyphData.cs) — static glyph bitmaps (3x5 pixel grids) for every supported character, plus width lookups used for centering and label-length validation.PngEncoder(Services/PngEncoder.cs) — a minimal, dependency-free PNG encoder that writes raw RGBA pixel data out as a valid PNG (IHDR/IDAT/IEND chunks, zlib-compressed image data, CRC32 checksums), avoiding the need for any image or graphics library in a WASM context.- JS interop (
wwwroot/js/download.js) — a small JavaScript helper that turns the base64-encoded ZIP produced in .NET into aBloband triggers a browser download, since WASM has no direct filesystem access.
All image generation — font rendering, pixel buffer construction, and PNG/ZIP encoding — runs entirely client-side in the WebAssembly runtime; the browser never sends data to a server.
The app is deployed to GitHub Pages via .github/workflows/deploy.yml. On every push to main, the workflow:
- Publishes the app in Release mode with the
wasm-toolsworkload - Rewrites the
<base href>to match the GitHub Pages subpath - Adds
.nojekylland a404.htmlfallback (so client-side routing works on refresh/deep links) - Uploads and deploys the published
wwwrootoutput as a Pages artifact
Requires the .NET 9 SDK.
dotnet runThen open the local URL printed in the console (see Properties/launchSettings.json).