A fast, reliable explorer for a single NFT collection (Drifella III). It keeps a local, versioned snapshot of live marketplace listings, serves data from memory, and offers a crisp, pixel‑perfect fullscreen viewer for original artwork.
- Slow & steady sync worker (rate‑limited; resilient), append‑only snapshots with atomic activation
- Normalized SQLite schema (WAL); concurrent reads while syncing
- Backend API with in‑memory cache for low‑latency reads
- Frontend (Svelte) with:
- Grid (default homepage): 3 columns, infinite scroll up/down (user‑interaction armed)
- Gallery (horizontal): near‑edge paging recenters around current mint (no jumps)
- Fullscreen hard‑pixel exploration with rich hotkeys
worker/— periodic sync from marketplace → SQLite snapshotbackend/— Node HTTP server with in‑memory snapshot cachefrontend/— Vite + Svelte app (grid + gallery + exploration)scripts/— utilities (e.g.,count-mints-images.ts,ingest-traits.ts)database/— SQLite integration, pragmas, migrationsdocs/— product & technical docs (start withdocs/01-product-overview.md)
- Node.js ≥ 24 (nvm recommended)
- Yarn Berry (PnP). The repo is configured; simply run
yarn install.
Install deps:
yarn installRun backend API (port 3000):
yarn backend:run
# Optional envs:
# DRIFELLASCAPE_PORT=4000 DRIFELLASCAPE_BACKEND_REFRESH_MS=10000 yarn backend:runRun worker (infinite loop, default 30s interval):
yarn worker:run
# Optional env:
# DRIFELLASCAPE_SYNC_INTERVAL_MS=60000 yarn worker:runRun frontend (dev server on port 5173):
yarn workspace @drifellascape/frontend dev
# Optional env:
# VITE_API_BASE=http://localhost:3000 VITE_POLL_MS=15000 yarn workspace @drifellascape/frontend devOpen http://localhost:5173 — the app will fetch from the backend by default.
Hotkeys (subset)
- Toggle data source (Listings/Tokens):
T - Enter Grid:
GorEsc(from Gallery) - Refocus last anchored token in Grid:
F - Enter Explore:
W - Toggle Explore debug overlay:
O - Focus token search:
E
Deep‑links
?token=NUM(0–1332) opens Gallery centered on that token (Tokens mode). The param updates as you browse in Gallery and is removed when you enter Grid.
- High‑resolution images live outside the build under
frontend/static/art/2560/andfrontend/static/art/540h/(git‑ignored). - The app requests them under
/static/art/2560/...and/static/art/540h/.... - For local development, symlink the
staticfolder intofrontend/publicso Vite can serve them:ln -s ../static frontend/public/static # verifies: ls frontend/public/static/art/2560 - In production,
docker-compose.ymlmountsfrontend/staticinto the Caddy container and the Caddyfile serves/static/*usinghandle_path, so requests for/static/art/...map to/srv/static/art/...on disk.
The VPS setup builds the frontend once per release and serves the static output directly from Caddy. Backend and worker services continue to run from source.
- Pull the latest code:
git pull - Build a new frontend release:
The script runs
./scripts/build-frontend-release.sh # optional custom ID: ./scripts/build-frontend-release.sh 20241021-frontenddocker compose run --rm frontend-buildand stages the build underreleases/<release-id>, updating thereleases/currentsymlink. By default the build setsVITE_API_BASE=https://api.drifellascape.art; exportVITE_API_BASEbefore running the script to override. - Reload Caddy to swap the live assets:
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile - (Optional) Roll back by re-pointing the symlink:
ln -sfn <previous-id> releases/currentfollowed by another Caddy reload.
Backend/worker containers still use docker compose up -d as before; only the frontend now deploys with a quick, no-downtime swap of static files.
If you still have the legacy frontend container running, clean it up once with docker compose up -d --remove-orphans.
- SQLite file is stored under:
database/drifellascape.db/sqlite.db
- Inspect with DB Browser for SQLite / SQLiteStudio, or the
sqlite3CLI.
Traits & ingestion
- Tokens/traits are normalized via
scripts/ingest-traits.tsusinglogs/mint_to_image.csvandmetadata/. - Duplicate images are expected — the script assigns
image_url → [mints...]in FIFO order so all 1,333 mints are inserted (uniqueness enforced ontoken_mint_addrandtoken_num, notimage_url). - Utility:
yarn tsx scripts/count-mints-images.tsprints unique mint/image counts from the CSV.
- Worker unit tests (Vitest):
yarn vitest run- Product overview:
docs/01-product-overview.md - Sync worker:
docs/02-sync-worker.md - Backend API:
docs/03-backend-api.md - Frontend:
docs/04-frontend.md - Gallery infinite scroll:
docs/gallery-infinite-scroll.md
AGPL‑3.0‑only. See LICENSE.