/ recent work / dnd-cards

DND Cards

Kanban board, but every column is a campaign. Inline dice rolls, DM-only lists, wax-seal buttons.

DND Cards — preview
Year
2024
Role
Fork + rebrand + features
Status
live
Stack
  • Next.js
  • tRPC
  • PostgreSQL
  • Docker
  • Coolify

A Kanban board redesigned around D&D campaign management. Forked from the kan.bn project, then rebranded, restyled, and extended with three D&D-specific features.

Features added

  • DM-only lists. Lists can be hidden from players entirely. Amber parchment background + lock icon. Server-side filtering so players never receive the data.
  • D&D templates. “Descent into Avernus” and a generic “Campaign Tracker” template wired into the New Board picker.
  • Inline /roll dice parser. Type /roll 2d6+3 in any description or comment, get 🎲 2d6 → [4,2] = **6** rendered inline. Supports d20, advantage/disadvantage, keep-highest. Custom parser, ~80 lines.

Design notes

Wax-seal embossed buttons (pill-shaped, radial highlight, inner stamped ring, press animation in orange #c87633, danger variant in oxblood #a04030). Card detail uses a 50/50 split when the first attachment is an image so portrait covers fill column width.

Deploy

Docker image built by GitHub Actions on push to main, pushed to GHCR, pulled by Coolify on a DigitalOcean droplet. The Coolify pull occasionally caches stale digests; documented manual unstick in the deploy notes.

Recent shipping

  • Vanity URLs — boards open at /{workspaceSlug}/{boardSlug} instead of opaque ids. Shallow URL replacement in the board view, readable slugs in imports, and admin/public-view detection done via tRPC getUser (not router params) to survive SSR mismatch.
  • AI card art — generate cover images via gpt-image-1 (DALL-E successor), with batched generation across an entire column and a replace-on-regenerate flow. Attachments now copy correctly when duplicating lists.
  • Strobe fixes — three separate fixes to kill the URL-replace flicker that happened with shallow routing on the board view, eventually landing on a window.history solution that doesn’t fight Next.js’s router.
  • Compiled translations for upstream i18n strings as part of localization rollout.