atproto pds in zig pds.zat.dev
pds atproto
zds docs iconography-proposal.md
4.5 kB
Markdown
at main

Doodl drawings in ZDS #

ZDS assigns individual Doodl drawings to presentation slots. It does not read or require tech.waow.doodl.iconset records: drawings can come from different accounts, and their authors do not need to organize them into sets.

Operator workflow #

Edit config/drawings.json. Each key is a slot; its value is a drawing strong reference with uri and cid. Use a DID-based AT URI pointing to a tech.waow.doodl.drawing record and the record's CID, not its image blob CID. The default configuration is empty. config/pds.zat.dev.drawings.json holds this instance's account and navigation selections.

Run just drawings (or just drawings path/to/config.json), then review and commit the configuration, generated manifest and PNGs under src/internal/web/icons/. Enable that manifest explicitly with zig build -Dweb-drawings=src/internal/web/icons/generated.zig. An ordinary zig build excludes custom artwork entirely, regardless of cached PNGs. Docker accepts the equivalent ZDS_WEB_DRAWINGS build argument; this instance's fly.toml sets it explicitly. Refreshing is explicit; normal builds and server startup never fetch drawings. A failed refresh leaves the previous manifest active. Unreferenced cached PNGs can be removed manually. Omitting the build option restores all bundled defaults. An empty {} configuration followed by refresh also clears the selected manifest.

The refresh tool resolves the author's DID to its HTTPS PDS, disallows redirects, bounds responses, verifies the requested record revision against its DAG-CBOR hash, and verifies the image blob hash. Only PNGs up to 1 MB with dimensions up to 4096 × 4096 are accepted. The operator initiates these public PDS requests; the server never resolves arbitrary drawing URLs supplied by visitors.

AT URIs identify mutable record locations; a CID pins the selected revision. If the author changes or deletes that record, refresh may fail until the operator chooses another revision. Already packaged images continue working. ZDS never silently substitutes the latest revision.

Presentation boundary #

The manifest, assets and replacement script live under src/internal/web/. Pages receive local image URLs; /ui/icon?cid=… serves only embedded assets with immutable caching. No database schema, authentication logic, runtime setting or resident account-management page is added. The browser retains the bundled icon until the replacement loads successfully. Visible labels remain, and images are decorative for assistive technology.

Slot Default / purpose
zds.nav.home Home
zds.nav.account Account, including homepage account link
zds.nav.apps Apps
zds.nav.about About
zds.account.passkeys Fingerprint
zds.account.app-passwords Key
zds.account.email Envelope (account settings and overview)
zds.account.spaces Four spaces (overview)
zds.account.status Power
zds.header.brand ZDS brand
zds.header.source Source forge
zds.header.zat Zat
zds.header.atproto AT Protocol
zds.header.menu Menu
zds.header.preferences Preferences

Omitted slots retain their bundled defaults. Unknown slot names are rejected to catch configuration mistakes. Account drawings use a 44-pixel box; header and navigation drawings have dedicated dimensions. Preview selected artwork at its actual size on light and dark backgrounds: arbitrary drawings may not make good small icons.

Doodl's current icon-set lexicon uses the fixed record key self. That is a Doodl authoring concern, independent of ZDS's selection model. Future pickers or presets can produce the same slot map without changing the PDS core.

Validation (2026-09-05) #

The four configured drawings passed record/blob hash verification and rendered at 44 pixels on desktop and a 390-pixel viewport, with no horizontal page overflow. Forced image 404s retained all four SVG defaults. GET returned the embedded PNG bytes, HEAD returned no body, and unknown asset CIDs returned 404. Missing configuration, unknown slots and unavailable revisions left the manifest unchanged; an empty selection built successfully.

Five ReleaseSafe startup samples on macOS/arm64 measured median readiness of 22.11 ms fresh, 9.59 ms on restart and 9.85 ms with the history fixture. The preceding local baseline was 22.13 / 9.16 / 9.22 ms. These warm-filesystem samples include polling overhead and do not measure VM replacement or production routing.