Normies logoNORMIES
Documentation

DOCS

Bitmap encoding

A Normie is a monochrome bitmap at 1 bit per pixel, most significant bit first: bit 7 of the first byte is the top-left pixel. At mint every Normie is 40x40, 200 bytes for 1,600 pixels. After an enlargement a canvas is 50, 60, 70 or 80 per side (313, 450, 613 or 800 bytes), with the original art centred.

Pixel data is stored with SSTORE2, which writes data as contract bytecode rather than storage slots. Each token maps to a single SSTORE2 pointer.

SVG rendering

The renderer contract reads the bitmap and builds the SVG on chain. It scans each row and merges consecutive filled pixels into one run, which keeps the SVG small. The result is #48494b (off-black) on #e3e5e4 (off-white). Each Normie also has an animation_url that draws it on an HTML canvas, crisp at any size.

Minting

Encryption

Image data and traits were XOR-encrypted with a keccak256-derived keystream before being written to NormiesStorage, keyed by a secret revealHash and each token ID. Once the reveal hash was set, the storage contract decrypts on every read.

Signatures

Minting required a backend-signed message over (imageData, traits, minter, maxMints, deadline), an EIP-191 personal signature the minter contract verified on chain, so only pre-approved image data could be stored.

Cold wallets and phases

Both minters accepted delegate.xyz delegation from a cold wallet to a hot one (V2 reads both registries). Minting ran in three time-gated phases: Guaranteed, FCFS and Public, each with per-wallet limits.

Storage

Original bitmaps live in NormiesStorage, encrypted from the blind mint. Edit layers live separately, unencrypted, in NormiesCanvasStorageV2, which also holds wallet and per-Normie pixel balances. Keeping them apart preserves the original art untouched; writing plaintext layers into the encrypted storage would break its decryption.

Compositing

The image is the base bitmap XOR the edit layer:

  • A set bit in the layer flips that pixel: filled becomes empty, empty becomes filled.
  • Setting the same bit again restores the original pixel.
  • For a Zombie the base is the Zombie art, not the human original. For a blank canvas there is no base: every set bit is a painted pixel.

The on-chain SVG is always monochrome. The green and grey in the editor are a frontend reading aid.

Commit and reveal

  • Commit: commitBurn(tokenIds, receiverTokenId) burns the tokens at once and records their pixel counts; the caller must own the receiver. commitBurnToWallet(tokenIds) does the same with the wallet as the receiver.
  • Wait: 5 blocks, about a minute, for a future block hash to serve as entropy.
  • Reveal: revealBurn(commitId) rolls a percentage for each burned token and credits the pixels to the receiver Normie or the wallet.

The EVM keeps only 256 block hashes, so after about 261 blocks (about 50 minutes) the roll is gone and the minimum tier is paid instead. The reward is never lost, only the roll.

Painting

setTransformBitmap(tokenId, bitmap) takes a full layer sized to the Normie’s canvas. The contract checks that the number of set bits does not exceed the pixels on the Normie and never deducts them: pixels are a ceiling, not a currency.

Delegation

An owner can set one Canvas delegate per token, an address allowed to call setTransformBitmap. A delegation is tied to the owner who set it (delegateSetBy): it lapses when the token is transferred and works again if the token returns. A delegate.xyz delegate gets the same painting right. Neither can move or spend pixels; that takes the owner or an ERC20-style allowance on the storage contract.

Renderer traits

The current renderer adds Canvas traits to every token: Customized, Pixel Count (from the original art, unchanged by edits), Action Points (the on-chain name for the pixels on the Normie), Level, Canvas Size and Blank Canvas.

API

api.normies.art serves everything on chain, read straight from Ethereum mainnet. Token IDs run from 0 to 9,999. The full reference is on the API page, and an llms.txt is there for LLM integrations.

Rate limit: 60 requests per minute per IP (sliding window).

Contract addresses

ContractAddress
Normies0x9Eb6E2025B64f340691e424b7fe7022fFDE12438
NormiesStorage0x1B976bAf51cF51F0e369C070d47FBc47A706e602
NormiesRenderer0xBe57fC4D0c729b8e8d33b638Dd441F57365e4c25
NormiesRendererV20x7818f24d3239c945510e0a1a523dd9971812c6c0
NormiesRendererV30x1af01b902256d77cf9499a14ef4e494897380b05
NormiesRendererV40x8eC46Cc1f306652868a4dfbAAae87CBa2715A0eB
NormiesRendererV50x7c726f02C5e840e1656b522A5C22caaf87C1C35C
NormiesRendererV60xd6747533697878a6a3a29B5cCf815740BA23998D
NormiesMinter0xC74994dD70FFb621CC514cE18a4F6F52124e296d
NormiesMinterV20xc513272597d3022D77b3d7EEBA92cea5D7fb2808
NormiesCanvas0x64951d92e345C50381267380e2975f66810E869c
NormiesCanvasStorage0xC255BE0983776BAB027a156681b6925cde47B2D1
NormiesCanvasV20xF14f2852e1fD6A4108156054AF49B3915dc40E2e
NormiesCanvasStorageV20x96F2DA32Bb9D429d59ac13dB469f4950cBe02084
NormiesPixelMarket0x86156A8d6e4B9925F7fEca527ea5D71B0deeDB64
NormiesRevenuePool0x481384812e79bf0d11FC0b1704af445D5F06813c
NormiesRoyaltySplitter0xA68A225f62772E6158f2B5f8afC184AdB69c3282
NormiesZombie0x18533ad55a54c3847Da06A48b51aD7DcB2551202
NormiesZombieStorage0xA331bD22C90D1DA096934Db8bc6b69F0e1491E26
NormiesLegendaryCanvas0xfA55f6592522dA74224a67c7D3Fd1DF759c628e8
Adapter80040xde152AfB7db5373F34876E1499fbD893A82dD336
delegate.xyz V20x00000000000000447e69651d841bD8D104Bed493
delegate.xyz V10x00000000000076A84feF008CDAbe6409d2FE638B