Reflection · on-chain
Van Arman put the whole of it on the blockchain, and kept it there at a fidelity Ethereum was never built to carry. The two ambitions pull against each other, and most of what follows comes of resolving them.
A painting robot works in passes. It lays a ground, makes a mark, photographs what the mark did and answers it, and the loop between those steps is what Van Arman calls 'Reflective AI.' Ordinarily that loop leaves nothing behind. The canvas is photographed when it is finished, and everything that happened on the way to it is gone.
In Reflection the passes are themselves the artwork. Each piece names its own, in sequence, within the file:
9 background 15 circles 10 bytegan 20x20 16 touchups 11 ganStrokes 17 lighten 12 skull 18 darken 13 background binary 19 highlight 20 skull flourish
Twenty-one passes are numbered in all, the drawing ones above and the remainder establishing colour and clipping. Seven fade in across an eight-second loop, at two seconds, then at 3.2, 3.6, 4.0, 4.4, 5.2 and six. Each piece therefore rebuilds itself in the order the robot built it. No recording is being played back. The sequence is the file, and the file is what the contract holds.
Seven fades is not a diminished file. The artist's exhibition renders for the Francisco Carolinum carry twenty to twenty-six, added to the content layers with the minted seven left untouched, and only six of those renders exist. A minted piece carrying seven is the work as it was composed.
The second achievement is that the work committed to the chain is not a small one. A single piece is ninety-two kilobytes of pure vector, some nine hundred drawing elements of which eight hundred and seventy-three are paths, and it embeds no raster image at all. There is no bitmap within it to degrade: the piece is geometry, and renders as precisely on a gallery wall as on a telephone.
The difficulty follows from that. Ethereum limits any single contract to 24,576 bytes of code, and the limit is enforced by consensus. One Reflection comes to nearly four times it. A piece this size cannot be held in a contract at all.
It is therefore not held in one. Tracing what a call to tokenURI genuinely reads, across twelve pieces distributed through the collection, returns the same structure each time.
Thirteen contracts form the engine and are shared by all nine hundred and ninety-nine. The remaining eighteen hold that particular painting, drawn from a common bank. All of this apparatus exists for a single reason: it is what the detail costs once no contract may exceed twenty-four kilobytes.
The figure for the collection is a floor, not a count. Thirty-nine of the pooled contracts appeared only once across twelve samples, which happens when a population has not yet been fully sampled, and a wider run of twenty pieces put the total nearer 144. What can be said with confidence is the order of magnitude.
Bytecode read during a call comes to between 152 and 181 kilobytes, and the file returned is about ninety-two. Those quantities are close because nothing is being made at the moment of asking. Van Arman's process ran once, at mint, and what it produced was written across the bank, to be reassembled on every call.
That is what makes the works immutable. There is no seed to run again, no model to reload and no version that might drift. The mirrored copies this site serves are byte-identical to what the chain returns, and anyone can check it.
The obvious way to find the remaining contracts is to read the entry contract's bytecode and look for addresses in it. That method fails, and it looks convincing while it does. The bytecode runs to 7.3 kilobytes and holds sixteen twenty-byte values that could be addresses. None of the sixteen is a contract the call reads. The real addresses sit in storage arrays written after deployment, so they were never in the code to find, and only a trace of a live call will show them.
# the contracts one call reads — requires an endpoint allowing debug_traceCall
curl -s -X POST https://eth.merkle.io \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"debug_traceCall","params":[{
"to":"0x5137cfB461d24040F5ce6B85D860c47A24f85412",
"data":"0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000"
},"latest",{"tracer":"prestateTracer"}]}'
The contracts are the returned accounts carrying a code field. Accounts without one are touched in passing and hold nothing.
A call to tokenURI returns a data URI of base64 JSON, whose image field is a second data URI of base64 SVG. That is the artwork. No gateway is involved, and nothing outside Ethereum has to still exist.
# tokenURI(uint256) is 0xc87b56dd, followed by the token id in thirty-two bytes
curl -s -X POST https://ethereum-rpc.publicnode.com \
-H 'Content-Type: application/json' -H 'User-Agent: Mozilla/5.0' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{
"to":"0x5137cfB461d24040F5ce6B85D860c47A24f85412",
"data":"0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000"
},"latest"]}'
Two details spare an afternoon. A User-Agent must be sent, since certain endpoints refuse the default one, and cloudflare-eth should be avoided, as it returns an internal error on responses of this size while a small call such as eth_blockNumber succeeds there and reveals nothing.
Token ids run from 0 to 998 where the artist's list runs from 1 to 999, so a token id is the list number less one. Token 0 is 'cogito ergo sum.'