For Artists — Writing for the Chain
This page is the whole picture from your side of the canvas. Read it once before you deploy and nothing that happens to your work will surprise you.
The short version
- Your script runs from Ethereum, forever. No server, no pinning service, no PD required.
- Every Output gets one hash, and your script turns that hash into the artwork. Same hash, same Output, every time, on every device.
- You pick one language: plain JavaScript, or p5.js, stored on-chain at an exact, frozen version.
- Nobody can pick their traits. Not collectors, not bots, not PD, not you. An Output's hash is decided by the block after its mint, so there is nothing to peek at and nothing to retry.
- For a few seconds after a mint the Output shows as "pending", then it reveals. That short pause is what keeps your rarities honest.
What your script receives
Before your first line runs, the page defines one object:
tokenData = {
hash: "0x3fa4…", // 64 hex characters: this piece's seed
tokenId: "17" // the piece's number in your edition
}
The page adds nothing else of its own. Its only global names are tokenData, your library's own (p5's functions) and, when you build on a library, the unzipper's PD_INFLATE. Give your own globals other names so you never overwrite one of them.
The hash is the only randomness your work should ever use. Turn it into numbers with a small seeded generator, for example:
// Seeded random from tokenData.hash: same hash, same sequence, always.
function rng(hash) {
let a = parseInt(hash.slice(2, 10), 16), b = parseInt(hash.slice(10, 18), 16),
c = parseInt(hash.slice(18, 26), 16), d = parseInt(hash.slice(26, 34), 16);
return function () { // sfc32
a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0;
let t = (a + b) | 0;
a = b ^ (b >>> 9);
b = (c + (c << 3)) | 0;
c = (c << 21) | (c >>> 11);
d = (d + 1) | 0;
t = (t + d) | 0;
c = (c + t) | 0;
return (t >>> 0) / 4294967296;
};
}
const R = rng(tokenData.hash);
const hue = R() * 360; // every call gives the next number in this piece's sequence
If you publish traits for collectors to filter by, set them from the same hash. See Subtraits.
Pick your language
The library below is stored on Ethereum once, compressed, and frozen at the exact version shown. A p5.js project binds to it when you deploy, and that binding never changes, so your work can never break because a library updated.
| Language | Exact version | What your script gets | Good to know |
|---|---|---|---|
| JavaScript | — | the browser, nothing added | No library, no extra weight. |
| p5.js | 1.11.13 | p5 in global mode: setup(), draw() |
The p5 most existing sketches and tutorials are written for. |
Your library is fully loaded before your first line runs, so you never wait for it or check whether it's ready. Write your script exactly as you would with a normal <script src> tag above it.
How an Output gets its hash
This is the part that protects the value of your rarest outputs.
- A collector mints. The Output is theirs from that moment, and payment has already reached you (95% of your price, inside the mint itself).
- The hash doesn't exist yet. It will be made from the fingerprint of the Ethereum block the mint landed in, and that fingerprint only exists once the block is finished. Nobody, not even a program minting on someone's behalf, can see the outcome during the mint and cancel if they don't like it.
- A few seconds later, the Output reveals. PD records the hash once the block is finished. Anyone can trigger this step, but it can't change the result: the hash was fixed the moment the block sealed. It is the same whoever reveals it and whenever they do.
- The preview image follows when gas is low. Once the Output's hash is final, PD draws a preview straight from your on-chain code and saves it permanently to Arweave for wallets and marketplaces. The storage fee pays for that, so PD waits until gas is low enough for the fee to cover it, however long that takes. The contract refuses a preview for an Output that isn't revealed yet. The artwork itself is always your live script.
Why this matters to you: on platforms where the hash is decided inside the mint, a bot can mint, check whether it got a rare output, and undo the mint if not, over and over, block after block. That drains your rare outputs into a few wallets. On PD there is nothing to check and nothing to undo.
What collectors see
- Right after minting: the Output shows a PRESERVING PREVIEW card and its Token Hash reads pending. Your script never runs on a placeholder hash, so no one ever sees a fake version of the Output.
- Moments later: the hash is in, and the Output renders as your art anywhere that runs its live code, forever. Wallets and marketplaces that show only the image keep the PRESERVING PREVIEW card until its preview is saved, which waits for low gas.
- If PD were ever down: anyone can reveal an Output themselves, directly on the contract. Even an Output left unrevealed for a long time can still be revealed; it just takes one extra block.
The first minute of your drop
Every drop on PD opens with the same 60-second entry minute, so being faster buys nothing and your drop can't be sniped. If more people want in than you have Outputs, a draw anyone can verify decides who mints, at your same fixed price. You don't set any of this up. See Fair Draw.
What can never change
Once you deploy, these are permanent, for you, for PD and for everyone:
- your script, supply, price and library
- the exact library version your project uses
- your artist address, which receives your mint proceeds and royalties
- how every Output's hash is made
Before you deploy: a checklist
- Randomness comes only from
tokenData.hash. NoMath.random(), no time or date, nothing about the viewer's device. With p5, seed it:randomSeed()andnoiseSeed()from numbers your hash gives you. - Same hash, same Output. Render a hash twice, on two devices, and compare. The Studio re-renders from stored hashes so drift has nowhere to hide.
- No network requests. No fonts, images or files fetched from anywhere. Everything your Output needs is in your script or your library.
- Any screen size. Your Output fills whatever window it's given. Size from
innerWidthandinnerHeightand handle a phone held upright. - Test the full edition in the Studio. Run your whole supply, look at the outliers, and make sure the rare outputs are as rare as you intend.
- Keep it lean. Your script is stored on-chain and loaded with every view. Smaller scripts load faster everywhere.
Further reading
- The Mint Flow: the exact on-chain steps
- Library Registry: how the libraries are stored and frozen
- Upload and Testing: proving your work before it goes live
- Royalties