2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
2025-10-27 16:18:06 +00:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00
v2
2026-10-19 12:16:49 -04:00

Wikideck

Mine knowledge. Collect the extraordinary. A working browser-mined Wikipedia card-collecting and trading prototype, built with React, TypeScript, Vite, Express, Web Crypto, and hash-wasm.

Getting started

Install Node.js 22.12+ (Node 24 LTS recommended), then install dependencies with npm install. Start the API and browser app together with npm run dev. Open http://127.0.0.1:5173. Use that same origin consistently: localhost and 127.0.0.1 have different browser wallets.

For a production-like local preview, use npm run build followed by npm start, then open http://127.0.0.1:3001. This changes browser origin and creates a different wallet. Both servers bind to loopback only. Never expose Vite publicly.

npm test runs cryptographic, protocol, ownership, HTTP integration, replay, and persistence tests. npm run build also type-checks server and client.

Appearance

Wikideck uses the official Catppuccin palette, with Mocha as its default. Use the palette selector in the top bar to switch between Mocha, Macchiato, Frappé, and the light Latte flavor. Your preference is saved locally in this browser, restored before the app paints, and synchronized between tabs on the same origin. Theme changes never touch your wallet or chain. If browser storage is blocked, switching still works for the current page. Cards, dialogs, forms, status messages, and the block explorer all follow the selected flavor.

Docker

Install Docker Desktop with Linux containers and Docker Compose v2. No host Node.js installation is required. From the project folder, run docker compose up --build -d, then open http://127.0.0.1:3001. The image builds the browser app and serves it together with the API; Vite is not used at runtime. Stop the existing local API first if port 3001 is already occupied.

  • Check status: docker compose ps; follow logs: docker compose logs -f wikideck.
  • Stop with docker compose down. Restart/update with docker compose up --build -d.
  • Chain blocks and transfers persist in the wikideck-data named volume across restarts and rebuilds. docker compose down -v deletes that chain permanently. Back up the volume before any reset.
  • The Docker chain starts separately from any existing project-local data; that directory is deliberately excluded from the image. Wallet keys remain in browser IndexedDB, not the container. The same browser origin retains the same wallet, but its old cards will not appear on a new chain.
  • Optional Compose variables (shell environment or an ignored .env file): WIKIDECK_PORT=3002 changes the host port and default allowed origin; WIKIDECK_OFFLINE=1 selects starter articles; PUBLIC_ORIGIN allows a specific additional frontend/reverse-proxy origin. Use the documented 127.0.0.1 URL when changing ports; localhost is a separate wallet origin. A different port also creates a different browser wallet.
  • Mining still happens in the browser, not in Docker. The container only serves the app, coordinates the chain, and verifies submitted proofs.

The multi-stage Node 24 Alpine image installs locked dependencies using npm ci, excludes development dependencies from runtime, and uses native Node TypeScript stripping. The process runs as the unprivileged node user. Compose supplies a read-only root filesystem, writable data volume, temporary filesystem, dropped capabilities, resource limits, and a health check at /healthz. Host access is restricted to loopback; do not scale multiple containers against the same JSON data volume. Graceful shutdown drains active requests before exit. Fresh named volumes inherit the image's data-directory ownership; custom bind mounts must be writable by UID/GID 1000.

This remains a local prototype, not a hardened public deployment. For remote access, use an HTTPS reverse proxy (browser wallet APIs require a secure context outside localhost), configure PUBLIC_ORIGIN, and review the limits below. The Node LTS image tag receives upstream patches; rebuild regularly and scan the resulting image before deployment. For audited releases, pin the base image to a verified registry digest.

Play

  1. Your browser creates a non-extractable P-256 private key in IndexedDB. The receive address is the SHA-256 digest of its SPKI public key.
  2. Read the CPU/battery disclosure, enable mining consent, choose a worker duty cycle, and start mining. No mining happens on page load.
  3. One dedicated Web Worker runs Argon2id in WebAssembly. A block is found when the resulting hash begins with one hexadecimal zero (approximately 16 attempts at this demo difficulty).
  4. The browser signs the proof. The API independently checks the signature, work, current tip, and challenge before persisting a card.
  5. View your collection, open cards, read the source article and image license, or inspect the chain. Cards receive deterministic rarity and game stats derived from their proof hash; these values are not Wikipedia facts.
  6. To test trading, open the same URL in another browser/profile, copy its wallet address, and send it a card. Transfers require the current owner's signature and a monotonic per-card sequence. Sending is irreversible. This is gifting/transfer functionality, not an atomic barter marketplace.

The worker stops when you press Stop, switch tabs, navigate away, or find a block. Each start mines at most one card. Worker duty cycle is an approximate active/idle ratio, not a guarantee of total CPU usage. Mining consumes energy and may warm devices. Mobile devices may be substantially slower.

Protocol

Each block contains a Wikipedia pageId, revision ID, article snapshot, timestamp, block height, previous hash, unpredictable challenge seed, difficulty, wallet address, nonce, proof hash, public key, and claim signature. The shared fixed-order serialization commits the article metadata and complete snapshot into the Argon2id proof. The seed is the Argon2 salt, and the wallet address is included in the password, preventing another wallet from copying a discovered proof.

Argon2id parameters: 16,384 KiB memory, 2 iterations, 1 lane, 32-byte output. The browser searches nonces; the server only recomputes submitted candidates. The demo's fixed difficulty is intentionally low. Rarity is a hash-derived game mechanic and can be ground by a determined miner; it is not an economically fair lottery.

Blocks are hash-linked, persisted atomically to an ignored data/chain.json, and fully reverified at API startup. Transfers are a separate signed ownership journal and are not committed into proof-of-work blocks. Verification rejects altered records and replayed sequences, but a trusted operator can remove a suffix or roll back the entire local state. There is no public checkpoint or external finality.

The next Wikipedia article is selected by the coordinator using namespace-zero random article discovery. It prefers articles with images and usable introductions; this is not a uniform draw across all Wikipedia pages. Content is frozen before mining. Outages use four accurate, clearly labeled offline starter summaries with real page IDs; preview cards are never credited as owned cards.

Important limits

  • Not a decentralized cryptocurrency. This is a single-coordinator local development blockchain. No peer-to-peer consensus, fork choice, independent validator network, difficulty adjustment, token economics, contracts, or external-chain NFTs are implemented. The server can choose articles, censor submissions, and roll back state. A shared/public network needs a separate protocol and security design.
  • Not Monero or RandomX. Argon2id is a real memory-hard function, practical in browser WASM, but its ASIC resistance is not equivalent to Monero's RandomX. Neither ASIC-proof nor GPU-proof is claimed. RandomX fast mode needs roughly 2 GiB of dataset memory plus cache, native/JIT optimizations, and browser-specific feasibility work; dropping it into a typical mobile/browser game is not a production-ready solution. This prototype is not mining Monero or using a mining pool.
  • No real-money value. No token issuance, payment, financial return, exchange, resale, or monetary reward is promised. There is no combat system yet.
  • Test wallets only. Clearing browser storage/profile permanently loses the signing key. No recovery/export exists. Non-extractability is not protection from malicious same-origin scripts using a key. Do not use this wallet design for valuable assets.
  • Not hardened for public deployment. Loopback binding, strict schemas, small request limits, origin checks, Helmet CSP, rate limiting, replay protection, trusted Wikipedia hosts, and serialized expensive verification are included. Production needs HTTPS, authentication/abuse controls, bounded durable database storage, pagination, backups, independent audits, transaction finality, CSP review, and an actual decentralization strategy. One API process only; multiple writers to the JSON file are unsupported.
  • Wikipedia contains unpredictable content; no age-appropriate content filtering is provided.

Settings

Environment variables: HOST (default 127.0.0.1; Docker sets 0.0.0.0 inside the container); PORT (default 3001); WIKIDECK_DATA_DIR (default project-local data directory; Docker uses /app/data); PUBLIC_ORIGIN (additional allowed browser origin behind a production reverse proxy); WIKIDECK_OFFLINE=1 (use labeled starter content without Wikipedia requests); NODE_ENV=production (enable production HSTS; deploy behind HTTPS). The Vite development proxy expects API port 3001. Compose's WIKIDECK_PORT changes only the published host port, not the internal API port.

Attribution

Independent experiment, not affiliated with or endorsed by Wikipedia or the Wikimedia Foundation. Live text is an excerpt from English Wikipedia, by Wikipedia contributors, under CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/. Card detail views link the original page and its revision ID; text is shortened for display. Original offline starter summaries are explicitly identified. Wikimedia Commons images have their own file-specific licenses and credits: open Image & license on each card before reuse. Card ownership does not grant exclusive ownership of encyclopedia text or images.

Structure

  • src/: React interface, IndexedDB wallet, WebAssembly mining worker.
  • shared/: deterministic protocol and verified offline catalog.
  • server/: Wikipedia adapter, cryptographic verification, API, persistence.
  • tests/: protocol/security tests and isolated API lifecycle tests.
S
Description
An NFT blockchain that rewards Wikipedia trading cards.
Readme
29 MiB
Languages
TypeScript 90.7%
CSS 4.8%
C++ 1.8%
JavaScript 1.1%
Dockerfile 0.5%
Other 1.1%