Normies Yacht Club is CC0 — public domain. The art, the data and the code. Here is a free, public API with the official collection data and the real on-chain pixel art. Make a game, a bot, a viewer, merch, a derivative. No permission needed. No attribution required.
This openness isn't an afterthought — it's the foundation. NYC is building Agent Islands: open, on-chain worlds where NFT-agents live and act. The same CC0 data, art and identity you see here are the rails an agent economy runs on. Build now; you're building on what comes next.
This yacht is fetched live from the public API and drawn from its official bitmap —
no library, no key, one fetch().
Draw any yacht in ten lines — this is the whole thing:
const r = await fetch("https://normiesyachtclub.com/api/v1/yacht/7.json");
const y = await r.json();
const cv = document.querySelector("canvas"); // 40 x 40
const ctx = cv.getContext("2d");
ctx.fillStyle = y.art.off; ctx.fillRect(0, 0, 40, 40);
ctx.fillStyle = y.art.on;
for (let i = 0; i < 1600; i++)
if (y.art.bits[i] === "1") ctx.fillRect(i % 40, (i / 40) | 0, 1, 1);
console.log(y.class, y.rarityRank, y.traits); // "Superyacht", 12, {...}
Plain JSON, served from the CDN. Base: https://normiesyachtclub.com/api/v1
| Endpoint | What you get |
|---|---|
/index.json | Start here — a discovery manifest listing every endpoint, with counts and links. |
/openapi.json | Machine-readable OpenAPI 3.1 spec of this API (for agents, codegen, tooling). |
/stats.json | Collection totals — fleet size, wallets, class breakdown. |
/fleet.json | Index of every yacht: id, normieId, pixelCount, class, rarityRank. |
/yacht/{id}.json | One yacht, self-sufficient: all traits plus the real 40×40 art bitmap. Everything you need to render it. |
/traits.json | Frequency of every trait value across the fleet — compute your own rarity. |
/contract.json | Address, chain, deploy block and ABI, so you can read live state yourself. |
Privacy by design: this API publishes no wallet addresses —
no owner lists, no burner lists. That data is public on-chain, but we don't repackage holder lists into a
bulk feed. For ownership, read ownerOf(id) from the contract.
For LLMs & agents: see /llms.txt for a plain-language overview and /api/v1/openapi.json for the schema.
Each yacht's art is a 1600-character string, row-major, where '1' means the pixel is on.
Pixel (x, y) is bits[y * 40 + x]. Two colours: #48494b on, #e3e5e4 off.
That's it — the same bitmap the contract renders on-chain.
Want to roll yachts that don't exist yet — for a prototype, a level, a mock? The art engine is public and deterministic: the same seed always gives the same yacht, forever.
<script src="https://normiesyachtclub.com/art/yacht-generator.js"></script>
<script>
const bits = NYC.generateYachtBits(1234, { pixelCount: 620 }); // 1600 chars
const traits = NYC.generateYachtTraits(1234, { pixelCount: 620 }); // { class, hull, ... }
const svg = NYC.bitsToSvg(bits); // ready to drop in
</script>
Works in Node too (module.exports). pixelCount is the "ink" of the burned
Normie — it sets the class: Sloop, Cruiser, or Superyacht.
Who owns what, and how many are claimed, changes by the minute — so don't trust a cached file for it, and don't trust me. Read the chain. It is the only source of truth, and it's open to everyone.
tokenURI(id) | The official image, rendered fully on-chain. Immutable — the renderer is locked. |
ownerOf(id) | Who holds a yacht right now. |
balanceOf(a) | How many a wallet holds. |
claimed(id) | Whether a yacht has been claimed yet. |
totalMinted() | How many are afloat. |
Contract (Ethereum mainnet):
0x87306c282eBd62Fe1c80AA69Dd9408331Dc11f64
Full ABI and deploy block: /api/v1/contract.json
Each yacht owns an account — an ERC-6551 token-bound account it keeps for life. It can hold ETH and NFTs, sign, and act. Whoever holds the yacht controls it; transfer the yacht and the account goes with it, contents included. The address is a pure function of the token id, so it exists and is stable before anyone deploys it — no registration, no operator, nothing to ask us for.
An account address depends on the implementation and salt used to derive it, so we publish ours. Use this pair — a different one gives you different addresses for the same yachts, and your fleet stops being the same fleet as everyone else's.
| Registry | 0x000000006551c19487814612e58FE06813775758 |
| Implementation | 0x41C8f39463A868d3A88af00cd0fe7102F30E44eC |
| Salt | 0x00…00 (zero) |
const y = await (await fetch("https://normiesyachtclub.com/api/v1/yacht/17.json")).json();
y.onchain.agent // 0x3E1939a1531B9bD370AfB7B0a6D82f24178e915A
// or derive it yourself — a view call, valid before the account is deployed:
registry.account(implementation, salt, 1, "0x87306c282eBd62Fe1c80AA69Dd9408331Dc11f64", 17)
Every yacht file carries its own address under onchain.agent, and the full configuration —
registry ABI plus three test vectors to check your derivation against — is in
contract.json under agents. Holders can activate and
manage their own accounts in The Purser.
Read ownership yourself. An agent address says nothing about who controls it: call
ownerOf(id) on the collection before letting an agent act on anyone's behalf.
Built something? Come tell the crew in The Lounge at the marina, or tag @NormieYachtClub. We'd love to sail it.