TRMNLc is a self-hosted server that serves rendered displays to [TRMNL](https://usetrmnl.com/) e-ink devices. It renders plugin UIs as HTML using React SSR, screenshots with Puppeteer (Firefox), dithers with ImageMagick for e-ink, and serves via the TRMNL device API.
Each device is configured with a `plugin` name and `settings` object. The plugin registry (`src/plugins.ts`) maps names to factory functions that return a `Renderable`. The `Renderable` interface (`src/template.ts`) requires `hash`, `nextEvent?`, and `async render()`.
The today plugin fetches from external services during `render()`, all in parallel:
- **`tana.ts`** — Fetches daily focus/success text and due/overdue tasks from a Tana server. Focus: calendar node → markdown field parsing. Tasks: single search query (`lt` tomorrow), split client-side by due date.
- **`ics.ts`** — Fetches today's non-full-day events from ICS feeds, returns `AgendaEvent[]`. Note: `location` lives on `instance.event.location`, not on the expanded instance directly.
- **`donetick.ts`** — Fetches chores from a Donetick instance (defaults to `app.donetick.com`). Filters by `user_id` and `isActive`. Done status: `nextDueDate > today` means completed.
Deployed as a NixOS module via `flake.nix` / `default.nix`. The `default.nix` defines a systemd service with `DynamicUser=true`. The Nix derivation copies source directly (no build step — runs with `bun run` at runtime).
## Formatting
Uses Prettier: single quotes, trailing commas (es5), 2-space indent, bracket same line.