A dark-academia artifact database for anthropology collections.
Antiquary is a working Next.js 16 + React 19 + TypeScript app. It runs locally as a single-process Next dev server or Docker container, and in production on Vercel against Turso (hosted libSQL) with private Vercel Blob storage for uploaded files. The design system below is still the visual source of truth.
What's in the app today:
- Email/password login with HMAC-signed session cookies; one-time admin bootstrap from environment variables in production.
- Catalogue browse, search, filter, and sort, plus a grouped view by universal ID number.
- Artifact create / edit / view with image, PDF, audio, and video previews, plus a separate invoice file slot.
- Soft-delete with a
/catalogue/removedreview surface and a permanent-delete step. - Per-artifact annotations and a tag vocabulary.
- Admin-only user management at
/people. - A public
/aboutpage.
For engineering details (project structure, routes, data layer, recipes), see
DEVELOPER.md. For the production deployment guide, see
VERCEL_DEPLOYMENT.md.
npm install
npm run devOpen http://localhost:3000.
Bootstrap account:
| Role | Password | |
|---|---|---|
| Admin | admin@antiquary.local |
antiquary-admin |
docker compose up --buildBy default, the single app container stores durable local state in /data:
- libSQL database:
/data/antiquary.sqlite - Uploads:
/data/uploads
For real use, set a strong AUTH_SECRET. Set ANTIQUARY_UPLOAD_DRIVER=blob
and Turso/Vercel Blob environment variables when deploying through Vercel.
Antiquary is a working internal collection database. Admins and regular users catalogue, upload, annotate, search, and maintain anthropology records: specimens, casts, photographs, field notes, fossil material, objects, recordings, and related documentation.
It is not a marketplace, an LMS, a museum CMS, or a SaaS product with sign-up funnels. It is a single internal tool for a department or collection team.
Think of it as a shelf in the collection room, made digital. Upload a record. Find a record. Annotate a record. Keep the archive usable. That is the whole product.
The application itself: a logged-in database with login, catalogue browse/filter/search, artifact detail, upload, removed-record review, and basic user management. There is no marketing site, no pricing page, no public landing.
- Primary: Collection admins and regular archive users.
- Secondary: Department staff and researchers who need catalogue access.
The aesthetic resonates with the discipline's source material — old books, candlelit libraries, field notebooks, sepia photographs, brass instruments, leather-bound volumes. It signals scholarly seriousness without being austere; it makes uploading a photograph of a pot sherd feel meaningful rather than transactional.
| Path | What it contains |
|---|---|
README.md |
This file — brand overview, content fundamentals, visual foundations, iconography |
DEVELOPER.md |
Engineering guide — tech stack, project structure, routes, data layer, recipes |
VERCEL_DEPLOYMENT.md |
Production deployment guide for Vercel + Turso + Vercel Blob |
SKILL.md |
Agent skill definition — how to use this system to design new things |
colors_and_type.css |
All design tokens (colors, type scale, spacing, radii, shadows) |
app/ |
The live Next.js application (App Router): pages, layouts, API routes, server actions |
components/ |
Shared React components (app-shell, artifact-form, artifact-card, icons, UI primitives) |
lib/ |
Server-side logic and pure utilities (db.ts, auth.ts, runtime.ts, upload.ts, etc.) |
tests/ |
Vitest unit tests and Playwright e2e specs |
public/assets/ |
Static assets served from /assets/* (logos, ornaments, team photo) |
assets/ |
Source SVGs for logos and ornaments |
preview/ |
Standalone HTML preview pages for design-system tokens and components |
ui_kits/app/ |
Original HTML/CSS reference UI from the brand kit (predates the live app/) |
Scholarly but approachable. Antiquary speaks with the calm precision of a well-kept archive: specific, curious, never condescending. We use the second person ("your collection," "you've added") and the first-person plural sparingly ("we've grouped these for you").
- Marketing copy: evocative, slightly literary. Quote-worthy. Headlines can be a fragment or a question.
- Product UI: plain, instructive, calm. Field labels are nouns, buttons are verbs.
- Empty states: warm and inviting, never apologetic. ("No artifacts yet. Begin with what you have at hand.")
- Errors: specific and unembarrassed. ("This file is larger than 50MB. Try compressing it, or split into multiple uploads.")
- Sentence case for everything except brand names: page titles, buttons, menu items, labels.
- Never ALL CAPS in body copy. Small caps (
font-variant: small-caps) are used decoratively in eyebrow labels and section markers — this is a defining feature of the system. - The brand name is always Antiquary (capitalized A, never italicized).
- ✅ "Add to your collection" (button)
- ✅ "Sherd · Late Bronze Age · Fieldwork, Crete 2024" (artifact metadata, em-dash separated)
- ✅ "Catalogue" (UK spelling intentional — adds gravitas)
- ✅ "Begin where you are." (empty state)
- ❌ "Upload Now!" (too peppy, wrong casing)
- ❌ "Oops! Something went wrong 😬" (no exclamations, no emoji, no apology)
- Prefer artifact, specimen, object, record, entry, catalogue, collection, field, annotation, plate (for image), folio (for document).
- Avoid: "stuff," "thing," "asset" (too SaaS-y), "drop" (too consumer), "vibe."
Never. Antiquary uses no emoji anywhere in product or marketing copy. If a visual mark is needed, we use a small ornament (✦ ❦ ◆) or an icon glyph from Lucide.
- Dates:
12 March 2024orc. 1450 BCEfor historical references (italicized circa). - Numbers in catalogue: zero-padded IDs (
ANT-00142). - Use en-dashes for ranges (
1450–1200 BCE), em-dashes for asides.
Antiquary's palette is deep, warm, and earthen. The dominant impression is parchment and ink, lit by candle.
- Backgrounds are not pure white — they're a warm ivory (
--paper) with a hint of yellow. - Foreground text is not pure black — it's a deep ink (
--ink) with brown undertones. - Primary accent is
--oxblood, a muted burgundy that reads on both light and dark surfaces. - Secondary accent is
--brass, a desaturated warm gold for highlights, hover, and section markers. - Tertiary is
--moss, a deep botanical green for tags, success states, and "biological" categorizations. - A dark mode flips to
--obsidian(near-black with warm undertone) and--vellum(warm cream text).
No bluish-purple gradients. No neon. No cool grays. Even the "blues" are dusty.
A two-family system with a third for code:
- Display: Cormorant Garamond (serif, oldstyle figures, optical sizes) — for H1, hero titles, section openers, the wordmark.
- Body: Source Serif 4 (serif, designed for screen reading) — for paragraphs, metadata, UI labels. We are intentionally a serif-first product.
- Mono: JetBrains Mono — for IDs, code, exact citations.
- Smallcaps: Source Serif 4 with
font-variant: small-caps, letter-spaced — for eyebrow labels.
We do not use sans-serif anywhere. This is a defining choice.
- Primary surface: solid
--paper. - Secondary surface:
--paper-2, slightly darker, for cards and sidebars. - Special surfaces use a subtle paper-grain texture (low-opacity SVG noise overlay).
- Hero areas may use a deep ink wash (dark
--obsidianbackground) with a warm vignette. - No full-bleed photography on the marketing site except in dedicated plate/figure blocks (always with a thin frame).
- Slow and considered. Easing:
cubic-bezier(0.2, 0.8, 0.2, 1)(gentle out) or simpleease-out. - Default duration:
200msfor hover,320msfor layout,480msfor entrance. - No bounces, no springs, no parallax, no scroll-jacking. Page transitions fade and translate ~6px.
- Page reveal: items fade in at 30ms staggers, like ink developing on a plate.
- Links: color shifts from
--inkto--oxblood, with a thin oxblood underline drawn in viatext-decoration-thickness: 1pxandtext-underline-offset: 3px. - Buttons: background darkens by ~6% (using
oklchlightness drop). No scale, no shadow change. - Cards: border darkens from
--ruleto--rule-strong. Optional: a--brasscorner mark appears.
- Buttons: background darkens ~10%, content shifts down 1px (no scale).
- No ripple effects.
- Hairline rules (
1pxsolid--rule) are a structural element of the system — they replace shadows in many places. - Double rules (Garamond-style ornamental dividers) appear in marketing.
- Corner radii are restrained:
2pxfor inputs,3pxfor buttons,4pxfor cards. Nothing is pill-shaped. Nothing is sharp-cornered either.
Used sparingly. When present, they are warm and subtle:
--shadow-sm:0 1px 2px rgba(58, 38, 24, 0.06)— input depth--shadow-md:0 4px 12px rgba(58, 38, 24, 0.08)— popovers, dropdowns--shadow-lg:0 12px 32px rgba(58, 38, 24, 0.12)— modals only
Never use shadows for cards inline with the page — use rules instead.
- Used in modal scrims (
oklch(0.18 0.02 60 / 0.5)over content) and the command-bar backdrop (backdrop-filter: blur(8px)over--paper / 0.85). - Not used decoratively elsewhere.
- Sepia and warm-toned. Slight grain. As if scanned from a book plate.
- Black-and-white photography is welcome but should be warm-tinted B&W (slight ochre cast), not cool.
- Real artifact photography over illustration whenever possible.
- Generous margins. Body content max-width
~720pxfor prose,~1200pxfor tabular/grid. - A persistent hairline frame around major content regions on the marketing site.
- Asymmetric two-column compositions are encouraged in marketing (large quote on left, small caption on right).
- In the app: classic three-pane (left nav, content, right inspector) using rules, not shadows, to separate.
A typical card is:
- Background:
--paper-2 - Border:
1px solid --rule - Radius:
4px - Padding:
20px 24px - No shadow at rest. Border darkens on hover.
- Title in display serif, metadata in smallcaps eyebrow, body in body serif.
8px base. Scale: 4, 8, 12, 16, 20, 24, 32, 48, 64, 96. See colors_and_type.css.
Antiquary uses Lucide via the lucide-react npm package. Icons are imported and re-exported through components/icons.tsx, which exposes a single <Icon name="…" /> component over a curated subset. Lucide's clean 1.5px stroke icons read as engraved/etched at small sizes, complementing the serif type without fighting it for attention.
Substitution flagged: ideally Antiquary would have a custom etched-line icon set drawn in the style of 19th-century encyclopaedia plates (Diderot, Britannica). Lucide is the closest readily-available substitute. If you'd like a custom icon set, please advise — we could commission line-art glyphs for anthropology-specific concepts (sherd, mandible, totem, fieldbook).
Usage rules:
- Add new icons by importing them into
components/icons.tsxand adding an entry to theiconsmap — don't reach forlucide-reactdirectly elsewhere. - Default size:
16pxinline with text,20pxfor buttons,24pxfor nav,32pxfor empty-state hero. - Stroke color matches surrounding text (
currentColor). - Stroke width: Lucide default
1.5(do not increase — it would feel chunky). - Icons are decorative companions to labels, never standalone CTAs except in icon-only buttons (which always have an
aria-label).
Common icons:
- Catalogue / collection:
library,folder - Artifact:
package,archive - Upload:
upload-cloud - Search:
search - User management:
users,user - Annotation:
bookmark,pen-line - Field:
compass,map - Time / period:
clock,calendar
Emoji policy: never used. Unicode ornaments (✦ ❦ ◆ ❧) may appear sparingly in marketing typography as ornamental dividers.
Logo: see assets/logo.svg and assets/wordmark.svg. The mark is a stylized capital "A" suggesting both an arch and an inverted excavation cross-section.
This document is the source of truth. When in doubt, choose the option that feels most like a quiet university library at dusk.
- Fonts are loaded from Google Fonts (Cormorant Garamond, Source Serif 4, JetBrains Mono). No
.ttf/.woff2files were licensed and committed. If you have preferred typefaces (e.g. Adobe Caslon, Sabon, GT Sectra), please send the files and we'll wire them in. - Icons use the Lucide CDN as a stand-in for what would ideally be a custom etched-line icon set in the style of 19th-century encyclopaedia plates.
- Brand mark (the arch / capital-A / excavation cross-section) is a placeholder draft. Happy to commission a proper one.
- Imagery: no real artifact photographs are included. Plate images in cards are warm-tinted CSS gradient stand-ins. A team photo is wired in on the
/aboutpage frompublic/assets/team-photo.jpg. Please send sample artifact plates and we'll integrate. - Audience is internal collection management; education-specific affordances are not addressed.