Disclaimer
Below is a proof of concept for an idea that can be taken deeper or down alternative paths. No “firsts” are being claimed here and, quite frankly, the visual side sucks. The goal is to put something concrete on the table that sparks conversation about what “onchain” actually means on Bitcoin, and how far the existing script system can be pushed without protocol changes or offchain dependencies.
The following records a single execution of each proof of concept. The full parameter space contains 10 valid combinations (Part 1) or any number of possibilities (Part 2) and the remaining ones will be executed and inscribed to friends using parent-child (i.e. don’t ask me for one).
1. Background
The phrase “fully onchain” gets used loosely in crypto art. For Bitcoin, most of the time it means the image file or rendering code is stored in a blockchain transaction rather than on a server somewhere. That is a meaningful improvement over IPFS links or centralized hosting but it is not the same thing as the blockchain doing any work. For those interested, I wrote this thread a couple years back detailing why “onchain” is not a simple binary aspect of a work.
This project asks a different question from current standards: can the Bitcoin blockchain be used as a computational substrate for generative art, not just a storage medium? Can the parameters of a generative artwork be derived from actual Bitcoin Script execution, enforced by consensus, and verifiable by anyone with a node?
The answer, it turns out, is yes (with caveats!).
2. The Core Idea
Bitcoin Script is intentionally limited. It is stack-based, non-Turing-complete, has no loops, no persistent state, and no native randomness. This makes Bitcoin Script auditable and safe and, lucky for us, also makes it a strange environment for generative art.
Limited does not mean useless. Bitcoin Script can hash data, perform bitwise operations, do arithmetic, and branch conditionally. More importantly, Taproot (BIP341) introduced taptrees: a Merkle tree of script spending conditions where each leaf is a distinct script path. The collector spends a UTXO by satisfying one leaf, thereby revealing which path they chose.
The insight this project builds on is that the taptree structure itself can encode a generative parameter space. Each leaf represents a specific set of artwork parameters and spending a leaf is the generative act. The transaction graph is the execution trace and the spent leaves are the outputs.
This is not validation in the traditional Bitcoin Script sense. The artist encodes the entire valid parameter space at genesis, after which the collector navigates it and Bitcoin consensus enforces which path was taken. The result is provable from chain state alone, without trusting the artist, any indexer, or any offchain service.
3. The Generative Model: Cyclic Cellular Automata
The visual output is a cyclic cellular automaton running on a 2D grid. Three parameters fully define its behavior: N (number of states), T (neighbor threshold, a cell advances when at least T neighbors are in the next state), and R (neighborhood radius). A fourth parameter, the seed, is derived from the first 4 bytes of a transaction ID as a uint32 giving each piece a unique initial grid tied to the chain.
Ten parameter combinations were identified from the full valid space. These ten form the artwork’s parameter set, spanning two aesthetic families: an R=1 family producing tight geometric and crystalline forms, and an R=2 family producing fluid organic and wave-based patterns.
Like I said in the disclaimer, the visuals here are not particularly interesting and act as a simple medium to an end.
4. Part 1: Script-Path-Encodes-Choice
Part 1 encodes the parameter space in a two-stage taptree structure. The first transaction encodes the family choice and the second encodes the specific combination within that family (N and T).
Transaction 1 taptree — 2 leaves
Leaf A: OP_SHA256 SHA256("BTC_ART_V1:R1") OP_EQUALVERIFY OP_TRUE
Leaf B: OP_SHA256 SHA256("BTC_ART_V1:R2") OP_EQUALVERIFY OP_TRUE
Each leaf script is a hash preimage lock. The preimage is a human-readable ASCII string namespaced with a version prefix. Spending a leaf requires revealing the preimage in the witness. The preimage itself encodes which parameter choice was made and anyone inspecting the transaction graph sees the plaintext string and knows immediately what was chosen.
This is script-path-encodes-choice; the taptree structure is the parameter space. Spending a leaf is the choice and there is no validation logic nor witness manipulation possible. The structure enforces the parameter space at the consensus level.
One important property of OP_TRUE scripts is they are permissionless. Anyone who sees the preimage in the mempool can spend the UTXO, which is one of the points Part 2 tries to address.
5. The Inscription Architecture
The artwork lives in a three-inscription structure on Bitcoin mainnet, all inscribed as Ordinals using the standard commit/reveal protocol.
| Inscription | ID | Role |
|---|---|---|
| Renderer | f26aafb4897eb18b0e3b87822f4ae1260402b5e9b1635eb6f49b09634b09996di0 | Parent, the algorithm |
| Execution record | fb36abfcc51949edbee170f070715c4dea69d7f438be745281e4366708a8e7f8i0 | Child, parameter record |
| Piece | 12b6205e1ce9b379f35b53b5cbfb2efcc720ea714a1267aea3a56dbe2986abe8i0 | Child, displayable artwork |
The renderer is a self-contained HTML/JavaScript file that implements the cyclic CA visualization. It accepts a child inscription ID as a URL parameter, fetches the execution record JSON via Ordinals recursion, and renders from those parameters. This means there are no external network calls or dependencies outside the Bitcoin network.
The execution record is a JSON child inscription containing the complete parameter derivation record. The piece inscription is a minimal HTML redirect that navigates to the renderer with its own inscription ID as the child parameter.
Resolution chain
/content/12b6205e...i0 (piece - navigate here)
→ redirects to /content/f26aafb4...i0 (renderer)
→ ?child=fb36abfc...i0
→ fetches execution record JSON
→ parses N=3, T=3, R=1, seed=4177152512
→ renders cyclic CA
6. Part 1 Transaction Record
| TX | TXID | Role |
|---|---|---|
| Genesis / Reveal | f8fa4a0020b4dbc3b11cbbd0f5b2ee21af8bf52d6f3d18d0ee295ce4b18afee6 | Inscription + TX1 UTXO |
| TX1 spend | e724d0b492624eea779e433ff8ed3dd28f913577baff0b33dcc8dcea87ee4635 | R=1 (front-run) |
| TX2a funding | 4870b2538ae5f2b260e22647869f036bfa134c7fa4739153362f9eeef718968f | Refund TX2a taptree |
| TX2a spend | f8c60a296cad264d034c1bfcdec4a612537ce0509c71828e76b38e54880b3cf9 | N=3, T=3, R=1 (front-run) |
Derived parameters: N=3, T=3, R=1, seed=4177152512 (0xf8fa4a00, the first 4 bytes of the genesis TXID).
Canonical piece URL: ordinals.com/content/12b6205e...i0
7. The Front-Running Attacks
Both TX1 and TX2a spends were front-run in the mempool. This was anticipated as a known property of OP_TRUE scripts and is worth documenting in detail because it is as interesting as it is instructive.
OP_TRUE scripts are permissionless by design. The spending condition is satisfied by revealing a preimage. Anyone who sees that preimage in an unconfirmed transaction can construct a competing transaction using the same preimage, pay a higher fee, and have their transaction confirmed first. The original transaction gets replaced.
In both cases, an automated actor extracted the preimage from the witness of the unconfirmed transaction and broadcast a replacement that burned nearly all the UTXO value as miner fees. The replacements were confirmed and the original transactions were dropped.
What the front-runner could not do was corrupt the parameter commitments. The preimages BTC_ART_V1:R1 and BTC_ART_V1:N3_T3_R1 are permanently and correctly committed in the replacement transactions. The artwork’s parameters are intact and the front-runner captured the economic value but not the semantic value.
That distinction, while not ideal, is important. The artwork survived two adversarial interventions in the mempool and resolved correctly. The parameter commitments were inviolable once the preimages hit the chain meaning the architecture is working as designed, even if the execution was messier than intended.
8. Part 2: Witness-Encodes-Choice
Part 1 demonstrated that taptree topology can encode a generative parameter space that uses its structure as a choice and the leaf selection as a generative act. Part 2 takes a different approach in that the collector provides parameter values directly in the witness stack, and the script validates them against the constraints of the generative model itself.
The move from Part 1 to Part 2 is a move from navigation to validation. In Part 1, the parameter space was a map and spending a leaf was choosing a destination. In Part 2, a single Tapscript leaf enforces the rules of the cyclic CA model arithmetically: N must be in range, T must be in range, and critically, T must be less than or equal to N. That last constraint is not a curator’s approved list and, in this case, is the definition of a valid cyclic CA. The script encodes the model’s own rules.
The Script
# Witness stack at entry (top to bottom): N, T, R, sig
OP_DUP OP_3 OP_7 OP_WITHIN OP_VERIFY # N in [3,6]
OP_OVER OP_GREATERTHANOREQUAL OP_VERIFY # T <= N
OP_1 OP_GREATERTHANOREQUAL OP_VERIFY # T >= 1
OP_DUP OP_1 OP_3 OP_WITHIN OP_VERIFY # R in [1,2]
OP_2DROP OP_DROP # clean stack
<collector_pubkey> OP_CHECKSIG # authorize
The T <= N check is a relational validation between two witness-supplied values computed in script. This is Script doing arithmetic work with the parameters, not just looking them up in a list. A Schnorr signature from the collector’s key is required to authorize the spend, making the transaction impossible to front-run; the signature commits to the transaction, so an automated actor observing the mempool cannot reuse or redirect it.
Part 2 Transaction Record
| TX | TXID | Role |
|---|---|---|
| Fund taptree | 58b45295683a420f2bb4a7fb8b89dd908b907a590d53b09033b9a7e4c3c3e469 | 10,000 sats to taptree address |
| Taptree spend | 504988c88f56bc6bf167d688d6b24357a48009fa2bdb758571656fc737270fc0 | N=6, T=3, R=2, block 939627 |
| Inscribe execution record | 315745b9e0000d6c3c7e384dcf75db28dfc4bc16ae9bda647f0b62719d2c5fcf | Child of renderer |
| Inscribe piece | 9a12012d36e7073252034f448b3984c88277f71286d2ae040406ae9c935f87ca | Piece redirect, child of renderer |
Derived parameters: N=6, T=3, R=2, seed=1346996424 (0x504988c8 for first 4 bytes of the taptree spend TXID, not the inscription TXID like Part 1).
Part 2 Inscription Architecture
| Inscription | ID | Role |
|---|---|---|
| Renderer | f26aafb4897eb18b0e3b87822f4ae1260402b5e9b1635eb6f49b09634b09996di0 | Shared with Part 1, unchanged |
| Execution record | 315745b9e0000d6c3c7e384dcf75db28dfc4bc16ae9bda647f0b62719d2c5fcfi0 | Child, witness parameter record |
| Piece | 9a12012d36e7073252034f448b3984c88277f71286d2ae040406ae9c935f87cai0 | Child, displayable artwork |
Part 2 reuses the Part 1 renderer inscription unchanged. The renderer reads N, T, R, and seed from the execution record JSON via Ordinals recursion (the same four fields, the same field names, and the same rendering logic as Part 1). The execution record shape differs only in provenance metadata: no preimage fields, instead witness_N, witness_T, witness_R, and derivation_method set to “witness-encodes-choice”.
Resolution chain
/content/9a12012d...i0 (piece, navigate here)
→ redirects to /content/f26aafb4...i0 (renderer)
→ ?child=315745b9...i0
→ fetches execution record JSON
→ parses N=6, T=3, R=2, seed=1346996424
→ renders cyclic CA
Canonical piece URL: ordinals.com/content/9a12012d...i0
What Part 2 Adds
The front-running attacks on Part 1 were the direct motivation for Part 2’s design. A signature requirement alongside the preimage would have prevented both. But the more important contribution is architectural: Part 2 demonstrates that Script can perform arithmetic validation of collector-provided inputs rather than encoding the parameter space structurally. The parameter space in this instance is a set of constraints the collector’s choices must satisfy.
The two pieces together map a design space. Part 1 uses a taptree structure as a parameter space where spending a leaf is akin to navigation and Part 2 is a script enforcing the rules of the generative model and collectors supplying values that satisfy them. They have the same renderer and same generative model but different execution architectures. Most importantly, they are both permanently verifiable from chain state alone.
9. The Honest Limitation
Bitcoin Script is not doing heavy computation. It is not running the cellular automaton or hashing parameters into complex outputs. What it is doing is enforcing, at the consensus level, which parameter values were chosen and making that choice permanently provable from chain state alone, but the rendering still happens in JavaScript. The claim is about parameter provenance and onchain enforceability, not about Script as a compute environment (yet).
10. Where This Goes
The two approaches demonstrated here (script-path-encodes-choice and witness-encodes-choice) are primitives. What they establish is a way of thinking about Bitcoin Script as a parameter enforcement layer for generative work. Several directions follow naturally:
Generative series with collector agency
The most direct application is a generative series where each edition’s visual output is determined by the collector’s spend, not the artist’s predetermination. The artist defines the parameter space and the generative model while the collector navigates or populates it. No two collectors make the same choice and every choice is permanently attributable and provable. The artwork exists as a possibility space until it is claimed, at which point it becomes fixed by the chain.
Multi-party parameter determination
Nothing in either architecture requires a single collector. A taptree could require sequential spends from multiple parties, each contributing one parameter. The final output is a function of all their choices combined where no single party controls the result. This is collaborative generative art where the collaboration is enforced by consensus rather than trust.
Using script to define a model
Part 2’s T <= N constraint is the beginning of a more interesting idea: what if the script encoded more of the generative model’s rules, not just its parameter bounds? A richer validation layer could enforce relationships between parameters that correspond to meaningful aesthetic or behavioral properties of the output, constraining the collector to choices that remain within a defined visual or behavioral territory. The script becomes a partial specification of the artwork’s character.
Transaction graph acting as execution trace
Both pieces here use a linear transaction graph (genesis > spend > inscribe) but the graph could be more complex. A taptree could encode branching narrative structures where each spend opens new UTXOs with new taptrees, and the full graph of spends constitutes the execution trace of a larger generative process. The artwork is not a single output but the entire trajectory of a record of choices made across time, each visible to anyone on the network.
Beyond cellular automata
The generative model here is cyclic cellular automata but nothing about the architecture is specific to it. Any parameterized generative system whose parameters fit within Bitcoin Script’s arithmetic range could be used: L-systems, reaction-diffusion, strange attractors, noise functions, etc. The constraint is that the parameters must be expressible as small integers that Script can validate. Within that constraint, the model is arbitrary. The chain enforces the parameter space; the renderer does whatever it wants with them.
The deeper question these projects are circling is what it means for Bitcoin to participate in the creation of an artwork versus “just” recording it. Script-path-encodes-choice and witness-encodes-choice are two answers of many to that question.
11. Closing Note
Parent-child is still not a collection standard.