Skip to content

Nonce

Nonce is a site for a crypto exchange office: a counter where people buy and sell with a person, Bitcoin ATMs, an OTC desk for larger trades and paid wallet setup sessions. It fits Bitcoin ATM operators and crypto shops too. It is laid out like a blockchain explorer turned into print: paper white with a fine dot field, a hairline chain down the left edge, every number in a monospaced face, signal green for buying and rising prices, coral for selling and falling ones. The home page opens on the headline over today’s rate board, with Find an ATM and Book the OTC desk from the first frame. The demo is a fictional exchange office in Lisbon, Nonce.

Nonce comes in two variants, chosen when you create the site: files/Sanity (static pages, any host) and EmDash (--cms emdash, rendered on request on Cloudflare). The pages are the same in both.

Page Edit it in
Home Pages → Home page (a list of sections)
Today’s rates (the hero’s board, the header’s ticker, the Rates page, the chat) Content → Rates
Rates (the rate table with the spread, the converter, fees and limits, how a rate is set, the OTC quote form, questions) Pages → Rates page
Services (every service as a card, what comes with every trade, questions) Pages → Services page
A service (a page each: fee, limit, time, what to bring, key figures, what’s included, how it goes, questions, photo) Content → Services
ATMs (every machine in a table) Pages → ATMs page
An ATM (a page each: status, hours, buy and sell, coins, limit, fee, directions, how to find it, photo) Content → ATMs
How it works (the steps of a first trade, book the OTC desk, the paid wallet setup, questions) Pages → How it works page
Security (the promises, ID checks by amount, scam warnings, questions) Pages → Security page
Reviews Pages → Reviews page
Learn Content → Learn (one guide can be members-only)
Visit (the map, the ATMs, how to get there, opening hours, message form, questions) Pages → Visit page
Name, phone, address, registrations, rating, hours, navigation, profiles, the risk warning Pages → Site settings
Buttons, labels, chat, emails, game texts Content → Interface texts
Privacy, terms, fees and limits Pages → Legal

In headlines, words wrapped in *stars* get a highlighter sweep under them, as in “Buy and sell crypto *with a person*”.

Your rates live in one place, Content → Rates: when they were set (“Rates at 09:40 · Thu 6 Nov”), the currency, and for each coin what a customer pays, what they get, the 24-hour change and a few prices for the sparkline. The hero’s board shows the first six coins (each price’s last two digits roll into place once, the sparklines draw themselves), the header’s ticker shows them across the top of every page, and the Rates page lists every coin with its spread. These are the rates you publish, not a live feed: update them when you set new ones, and keep the time on them.

The converter on the Rates page works out a trade in the browser: buy or sell, a coin, an amount and where (each place you trade with its fee, Pages → Rates page → Converter). It takes the market price between your buying and selling rate and adds or takes off that fee, then shows the rate, the fee and what the customer receives.

Every home section after the hero is a block of a chain. A stamp strip above each shows its height, a short hash with the leading zeros of a mined block and its confirmations; as it scrolls into view the hash scrambles through hex characters and settles. The chain down the left edge fills with the accent as you scroll, the steps on How it works hang on it as blocks, and the footer ends in a strip of the latest blocks whose newest one fills as you arrive. The stamps are decoration, the same on every build (src/lib/block.ts). With reduced motion everything shows settled.

Each service has a page laid out like a transaction: the fee and what it covers, the limit, how long it takes and what to bring as fields, then what’s included, the steps and questions. A service whose button goes to /atms also shows the ATM table. Each ATM has its status (online or under maintenance), hours, whether customers can buy and sell, its coins, limit and fee, and its latitude and longitude for the Google Maps, Apple Maps and OpenStreetMap directions links. Search engines get the machines as schema.org AutomatedTellers with coordinates.

Every page’s footer carries the risk warning from Site settings, and the chat never gives investment advice. Keep both, and never promise returns in your own content.

The visit page and the home section “Visit” show a map of the streets round your office, drawn from OpenStreetMap in your colors, with a pin, your address and directions links. It is part of the page (no embed, no cookies) and follows the theme and your accent. To draw your own, put your coordinates in map.config.json and run pnpm map -- fetch.

Everything works without keys; each feature switches on with its variables in .env.example.

Feature Where Service
Book the OTC desk How it works page, loads on click; a preview of the calendar until connected Cal.com
Paid wallet setup session How it works page (one-time payment) Stripe or Lemon Squeezy
Rate alerts by email Home and Learn pages, with a welcome email Supabase or Mailchimp
OTC quote requests and messages Rates and visit pages; to the email in Site settings Resend
AI chat Every page; answers about rates, fees, ATMs, ID checks and how a trade works; no investment advice, warns about scams Claude or OpenAI
Members-only guide Learn Clerk
Search ⌘K or the search field: services, ATMs, pages, guides built in, or Algolia
Analytics Every page; Google Analytics only after consent Plausible, Umami, Google Analytics, PostHog
Photos Production builds Cloudinary (optional)

The home page is built from these sections, in any order: Hero (the rate board), Services, ATMs (a table of machines), Numbers (over a chart of blocks that fills as it scrolls in), How it works (the steps along the chain), Security (a photo, facts and a button), Reviews, Learn, Rate alerts, Visit (the map) and Closing call (a photo beside the headline).

src/content/singletons/brand.json (Pages → Brand in Keystatic) holds three colors: the accent (signal green: buying, rising prices, the buttons and filled blocks), the second (coral: selling and falling prices, the scam warnings) and the third (blue: hashes and step numbers). Buttons are adjusted until their dark text is readable and the text colors for each theme; a color that can’t get there stops the build with a message. Brand also sets the fonts and the corners. The site opens in its light theme; the toggle switches to a graphite dark theme and the browser remembers it.

Nonce is ready for more languages: see Languages.

A small game, Fill the block: you are the miner. Transactions wait in the mempool, each with a size in vB and a fee in sats. Pick which ones go into a block of 1,000 vB (tap them, or move with ← → and press Space), then mine it (the button, Enter or M) before the timer runs out, when the network mines it with whatever you had in. The highest fee rate first is not always the best block. You score 100 × your fees ÷ the most fees that fit. Three blocks: 8 transactions in 30 seconds, 10 in 25 and 12 in 20; the best score is kept in the visitor’s browser.

  • AGENTS.md describes the project for coding assistants (Claude Code reads it through CLAUDE.md, Cursor through .cursor/rules/).
  • /llms.txt lists your pages, services, ATMs and guides for AI assistants, in every language.
  • Pages carry JSON-LD: the company as a FinancialService (hours and rating), services as Services, ATMs as AutomatedTellers with coordinates, the paid session as an offer, the reviews, questions as a FAQPage, and each guide as a BlogPosting.
Terminal window
pnpm dev # local site, editor at /keystatic
pnpm build # production build
pnpm map -- fetch # draw the map round map.config.json from OpenStreetMap
pnpm cms sanity schema|seed # move content to Sanity (see Content → Sanity)

In the EmDash variant: npm run dev, npm run deploy (Cloudflare) and npm run emdash:schema (after changing the content model).