SEED 0x000000
Inspired by Heraldia

MANDALIA

Generative · Vector · 100% Onchain · Ethereum Mainnet

10,000 deterministic radial compositions. State-derived from a bytes32 seed plus a uint16 transfer counter. SVG is synthesized inside tokenURI() on every eth_call — no IPFS, no metadata server, no off-chain compute, no proxy. Renderer is upgradeable; storage is immutable.

Supply
10,000
Price
0.0001
Per Wallet
25
Chain
ETH L1
0 / 10,000 MINTED 0.00%
Max 25 per tx & per wallet · ERC-721 + ERC-2981 + ERC-4906 · 5% Royalties · CC0
* * *

Your wallet is the artisan.
Every transfer is a new ring.

Pure Solidity. No IPFS. No servers.
The code is the art.

Once deployed, immutable.
The mandala never stops growing.

— Mandalia, MMXXVI
* * *

Lineage

Built in the lineage of Heraldia.

Heraldia pioneered fully onchain SVG evolution on Ethereum mainnet — a 10,000-piece collection where each token mutates on every transfer. Mandalia is its spiritual successor. Same chain. Same standard. Same conviction in permanence.

Heraldia holders receive tiered free claims as recognition of the path they laid:

1–4 held → 1 free · 5–9 held → 3 free · 10+ held → 10 free

Proof verified via Merkle snapshot taken before launch. No live-balance gaming.

* * *

Live Preview

Click any cell to regenerate that seed. Output is identical to what the deployed renderer will produce — same PRNG, same palettes, same composition pipeline.

12 random samples
* * *

How It Works

Three states. One contract. Forever onchain.

01
Mint

A 32-byte seed is derived from keccak256(prevrandao, sender, tokenId) at mint. The seed is the genome — palette, symmetry, motif family, remate, bindu. All determined. All immutable.

02
Transfer

The contract increments a per-token counter on every transfer. EIP-4906 is emitted; marketplaces refresh the rendered image. No oracle. No off-chain trigger. Just the chain itself.

03
Evolve

Eight logarithmic stages. Density grows, accent bands appear, satellite constellations bloom between rings. The piece remembers every owner. At stage seven, it reaches its final form.

* * *

Architecture

Three-contract topology. Renderer is mutable on the NFT contract — enables visual patches without re-mint. Storage is single-purpose; reads from the renderer, writes only on transfer hook.

       ┌──────────────────────────────┐
       │  NFT.sol                     │  ERC-721 · ERC-2981 · ERC-4906
       │  mint() · transfer hook      │ ───┐
       │  tokenURI() → delegates      │   │  delegates to renderer (mutable address)
       └──────────────┬───────────────┘   │
                                        
                      │ writes           ┌──────────────────────────────┐
                      │ seed +           │  Renderer.sol                │
                      │ tx counter       │  render(seed, txCount)       │
                                        │  Solady DynamicBuffer        │
       ┌──────────────────────────────┐  │  asm hot paths · cos LUT     │
       │  Storage.sol                 │ ←─┤  returns full data:image URI │
       │  mapping seed   (bytes32)    │  └──────────────────────────────┘
       │  mapping txCount (uint16)    │
       │  ~34 bytes per token         │
       └──────────────────────────────┘
  

NFT Contract

Standard ERC-721 with _update() override emitting MetadataUpdate per EIP-4906 and incrementing the per-token transfer counter via the storage contract. Renderer address is settable post-deploy by owner only.

Renderer Contract

Pure view contract. Single entrypoint render(bytes32, uint16) returns (string). Stateless. Built with Solady's LibString, Base64, and DynamicBuffer to keep concatenation costs sub-linear. Critical paths inlined in assembly.

Storage Contract

Two mappings: seedOf(uint256) → bytes32 and transferCountOf(uint256) → uint16. Write authorization restricted to the NFT contract address (set at deploy, immutable). ~34 bytes per token; ~340 KB total for 10k supply.

Why Split?

Renderer is heavy (~20 KB bytecode). Bundling it in the NFT contract would push past the 24 KB EIP-170 limit. Splitting also enables future patches: redeploy a fixed renderer and call setRenderer(), no migration of existing tokens.

Rendering

Deterministic SVG synthesis from a 32-byte seed. No raster, no off-chain proxy. Output is data:application/json;base64,<…> with embedded data:image/svg+xml;base64,<…>. Marketplaces parse it inline.

// NFT.sol
function tokenURI(uint256 id) external view override returns (string memory) {
    bytes32 seed = storage_.seedOf(id);
    uint16  txc  = storage_.transferCountOf(id);
    return renderer.render(seed, txc);
}

// Renderer.sol — pseudo
function render(bytes32 seed, uint16 txc) external view returns (string memory) {
    DynamicBufferLib.DynamicBuffer memory svg;
    svg.append('<svg viewBox="0 0 380 380" xmlns="http://www.w3.org/2000/svg">');

    Composition c = decompose(seed, txc);   // → palette, symmetry, rings, remate, stage
    drawBackground(svg, c);
    drawInnerRings(svg, c);             // loops sym × rings, uses cosLUT
    drawRemate(svg, c);                 // scallop · pontos · liso
    drawBindu(svg, c);
    applyStageOverlays(svg, c);         // log curve, gated by txc

    svg.append('</svg>');
    return encodeMetadata(svg.data(), c);
}

PRNG

Mulberry32 ported to Solidity (uint32 arithmetic). Sub-seeded per ring via keccak256(seed, ringIdx) truncated to 32 bits. Bit-exact match with the JS reference implementation. Same seed → identical SVG bytes on every node, every call.

Trigonometry

256-entry cosine lookup table in SSTORE2-stored bytes, Q16.16 fixed point. sin derived by offset. Avoids per-call fixed-point series. ~600 gas amortized per angular position vs ~8k for a Taylor expansion.

SVG Construction

Direct byte concatenation via Solady's DynamicBuffer — preallocates 2 KB, doubles on demand, single mstore per write. Avoids the quadratic cost of native Solidity string concat. Final base64 encoding via inline assembly.

Determinism Guarantees

Pure functions only inside the renderer. No block.timestamp, blockhash, or external state reads. Identical bytes produced from genesis until heat death. SVG hash is provable: keccak256(render(seed, txc)) is constant per input.

Evolution

Transfer hook increments a per-token counter. Counter feeds back into the renderer's composition pipeline. Eight visual stages on a logarithmic curve — denser radial motifs, accent bands, satellite constellations, alternate-ring color reinforcement. State-derived art; no signing oracle, no metadata mutation, no API refresh.

// NFT.sol — transfer hook
function _update(address to, uint256 id, address auth)
    internal override returns (address)
{
    address from = super._update(to, id, auth);
    if (from != address(0)) {
        storage_.incrementTransferCount(id);
        emit MetadataUpdate(id);            // EIP-4906 → marketplace refresh
    }
    return from;
}
StageTransfersVisual Additions
00Base composition · genesis state
1–31–40Motif density × 2–4 · inner slot echo lines
441–80Saturated density · 4 echo lines per slot · 40% stroke weight
581–200+ thick inter-slot separators · accent reinforcement
6201–340+ satellite constellations between rings (sym × 4 micro-dots)
7341++ alternate-ring accent banding · final stroke peak · 70% bolder
* * *

Vision Simulator

Paste a wallet address (or any string). We seed a piece as if it were minted to that wallet, then render its three lives: at mint, after 50 transfers, and at the ancestral stage. This is exactly what the deployed contract will produce.

* * *

Traits

11 traits total — 8 DNA (immutable, set at mint) and 3 derived from chain state (mutable on transfer). Combinatorial space of DNA alone exceeds 600,000 unique configurations; with per-ring micro-decisions, visual variation is effectively unbounded.

Symmetry
DNA · 5 weighted
12 (25%) · 16 (30%) · 20 (25%) · 24 (15%) · 32 (5% legendary) axes
Palette
DNA · 12 curated
Tibet · Persia · Alhambra · Sumi-e · Stained Glass · Bauhaus · Onyx · Coral · Forest · Lapis · Crimson · Slate
Family
DNA · 6 values
Geometric · Organic · Calligraphic · Dotted · Linear · Interwoven
Bindu (center)
DNA · 8 values
Point · Star · Eye · Hexagram · Triple · Rays · Void · Lotus
Remate (outer)
DNA · 3 values
Scallop · Dots · Smooth
Stroke
DNA · 4 weighted
Hairline · Thin · Medium · Bold
Núcleo (halo)
DNA · 3 weighted
None · Halo · Double Halo
Modifier
DNA · 5 rare (20% total)
None · Golden · Prismatic · Inverse · Halo Glow
Era
Dynamic · 4 tiers
Genesis · Young · Mature · Ancestral
Stage
Dynamic · 8 tiers
0–7 (logarithmic on transfer count)
Transfers
Dynamic · uint16
0 — 65,535
* * *

Frequently Asked

If something isn't here, the answer is probably "read the contract."

Is this really 100% onchain?
Yes. The SVG is generated inside tokenURI() on every call. No IPFS, no Arweave, no proxy server. Pull the contract source from Etherscan, run eth_call against any node — the image is reproducible bit-for-bit forever.
What changes when I transfer?
The contract increments a per-token counter. The renderer reads that counter and adjusts the composition — denser motifs, accent bands, satellite dots, alternate-ring color reinforcement. Across 8 logarithmic stages (0 → 7), the piece grows from genesis to ancestral. Your wallet adds rings without ever knowing it.
Why are Heraldia holders special?
Heraldia laid the path for fully onchain SVG evolution on mainnet. We are downstream of that work. As recognition, holders get free claims tiered by holdings (1–4 → 1 free, 5–9 → 3 free, 10+ → 10 free), proven via Merkle snapshot taken before launch.
What does CC0 mean?
Public domain. Anyone can remix, sell merch, build derivative collections, fork the renderer, print and frame on their wall. We assert no rights over the art. The chain assigns ownership of the token; the work itself belongs to no one and everyone.
Will the renderer change after launch?
The renderer contract is upgradeable by the owner until lockRenderer() is called. The intent: launch with the renderer reviewed and tested, then lock irreversibly. Once locked, the rendering logic is immutable forever — same input always produces the same SVG bytes.
Can I be both a Heraldia claimant AND a public minter?
Yes. Free claim and paid mint share the same per-wallet cap of 25. A 10-Heraldia holder could claim 10 free and mint 15 paid, hitting the cap at 25 total.
What's the cost to mint?
0.0001 ETH per token (~$0.20). Plus network fees, which vary with congestion. Batch minting amortizes the fixed transaction overhead — minting 25 at once is significantly cheaper per token than 25 single mints.
Is there a wallet cap?
Yes — 25 per wallet, counting both paid mints and free claims combined. Per-transaction cap is also 25, so a wallet's entire allocation can be claimed in a single tx. Cap is enforced on the receiver, so airdrops don't bypass it.
What about royalties?
ERC-2981 standard. 5% on secondary sales, hardcoded to a single dev wallet. Not enforced via Operator Filter — marketplaces honor royalties at their discretion. We're not banning Blur.
What network?
Ethereum Mainnet. Layer 1. Where Heraldia lives. Where permanence is the most expensive — and the most credible.
Can I render this anywhere?
Yes. Any client that can call tokenURI(id) on the contract gets the full SVG as a data URI. Frame your piece in a hardware wallet display, print it on a tote bag, mount it in an LED wall. The renderer doesn't care.
When does mint open?
Stealth launch. No pre-announcement. No exclusive window. Public mint and Heraldia free claim open simultaneously when startTime passes. Watch the contract.
* * *