Public
Design & print employee ID badges with photo + logo uploads
design-toolhonointernal-toolsreact
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Employee Badge Designer

Design employee ID badges in the browser — upload a headshot and your company logo, pick a layout and colors, then print on standard CR80 card stock or export a PNG.

Open the designer

What it does

  • Image uploads — drag-and-drop (or click) a photo and a company logo. Both are downscaled in the browser with a canvas before upload, then stored as blobs and served from /img/:file with immutable caching.
  • Three layouts — Classic (header bar + round photo), Modern (full-bleed color panel), Minimal (type-led). Each renders in portrait or landscape.
  • Custom colors — six presets plus accent / card / text color pickers.
  • True-to-life sizing — cards are laid out at 2.125in × 3.375in (CR80), so printing at 100% gives a badge that fits a standard holder.
  • Roster — save badges to SQLite, reload them for editing, and print the whole roster as one sheet.
  • PNG export — renders the preview at 4× with html-to-image.

Architecture

Rendering mermaid diagram...

Files

index.ts                       ← Hono server: pages, upload + roster APIs
backend/
  uploads.ts                   ← image upload to blob storage, /img/:file serving
  badges.ts                    ← saved-badge CRUD in SQLite
shared/
  types.ts                     ← Badge shape, templates, presets, card sizing
frontend/
  root.tsx                     ← HTML shell (Twind + the @media print rules)
  index.tsx                    ← React entrypoint
  lib/images.ts                ← canvas downscaling + upload helper
  components/
    App.tsx                    ← layout, save/print/export actions
    Controls.tsx               ← the design form
    BadgeCard.tsx              ← the badge itself (3 templates × 2 orientations)
    ImageUpload.tsx            ← drag-and-drop upload widget
    Roster.tsx                 ← saved badge list

Printing notes

Print rules live in frontend/root.tsx as the app's only stylesheet — @page margins and print-only visibility can't be expressed as utility classes. When printing, enable Background graphics in the browser's print dialog so accent colors render, and print at 100% scale (no "fit to page") for accurate card dimensions.

Storage

Photos and logos are blobs; on the free plan all blobs share a 10MB budget, which is why uploads are downscaled to a 640px (photo) / 480px (logo) long edge first. Removing a badge from the roster does not delete its uploaded images.