Tokens · Variants

Variants — states gallery

Two collection-level surfaces: Variants — every variant across every token in the collection, browsable the same way tokens are (card grid or list, filters, pagination) — and Actions — the optional, reusable action-template library. The transition itself — which variant a holding is reached from, and what triggers the change — is configured per token, on the variant's own edit panel; it is not a separate graph-building page. A transition can use a shared, reusable template (when more than one token follows the same path with the same asset) or a one-off definition just for that variant — templates are a convenience, not a requirement.

Frames 15–20 cover variant profiles — a named, versioned, project-level variant set that can be applied to many tokens at once. A profile carries the set and never the topology, so applying one seeds the list and the author still declares each transition per token.

Frames 21–25 are new, and 15, 16 and 19 are revised. Variant identity is now a stable variant_id that never changes and is never reused (T10), separate from display order — so re-apply can update an uncustomised variant, a profile may place a variant anywhere in the order, and reordering is harmless. Apply, re-apply and detach are Draft only; the operation is offered from Review as one atomic step that returns the token to Draft. And the State Policy is resolved into the token's contract rather than snapshotted onto the token.

Frames 01–14 unchanged · 15, 16, 19 revised · 21–25 new
Source: Phase2/Composition Template System/token-contract-system-spec.md §4A (variant profiles) · token-variant-actions-spec.md (transitions, TVA1–TVA11) · state-policy-design.md — all ratified. Extends Phase1/token-system-design.md (the variant data model, T1–T10). Rulings R114–R131. Related: Token draft · My Tokens · Collection nav.
Setup · creator, on the token itself
01What a variant isDeveloper reference — not a screen. The model in four rules; every frame below follows them.
The model
A variant = a different version of the same token

It has a different name and a different asset. Everything else about the token stays the same.

The Original Token is always the default variant

The token's name and main asset are the Original Token — the default variant. There is never a time when the default isn't set, and only the default variant can be minted.

Every other variant declares its own transition

On the token itself, each variant's own edit panel says which variant it's reached from and what triggers the change — a shared, reusable action template, or a one-off action defined just for it. There's no separate graph-building page; the resulting chain or branch is just a preview, derived from what each variant declares.

Coming later (not in the launch candidate)

A future version will let an action require a payment or the burning of another token before it runs. Recorded in the design docs; not built for launch.

02Token · Supply — stack behaviourStack behaviour (Allow stacking / Always individual) is a per-token setting, and it does not gate variants — variants are available either way. With stacking on, each variant is its own separate stack; with it off, the variant just labels each individual copy. Locks when the token goes Live.
Studio/Collection: Paper Trail/Dollar Wallet/Token supply
Draft
Token · Supply

Token supply.

Per-token supply and stack behaviour. Variants (Variants tab) are available in either mode below.

For stackable tokens, each variant stacks separately. For always-individual tokens, the variant just labels each copy. Locks when this token goes Live.
03Token · Variants tab — no variants yetA tab on the token editor, so a creator who isn't using variants never sees the options. The tab opens with a plain explanation, shows the Original Token as the default, and — if there are no other variants — a short message and one button.

Edit token · Variants Draft

Variants are different versions of this token with a different name and asset. Each one you add here says which variant it's reached from and what triggers the change.
Dollar Wallet
Original Token · the default · the only one that mints
Default
This token does not have any variants. If you do not wish to add any, there is nothing more to do here.
04Add a variantAdding a variant needs just an asset and a name — enough to create it. Its transition (how it's reached, what triggers it) is set up straight after, from Edit (frame 06), so a variant is never left half-configured for more than a moment.

Add variant

05Token · Variants tab — with variantsEach row shows its asset, name, and — once configured — a plain summary of its transition ("Reached via Gild · from Original Token"). A variant added but not yet wired up reads "Not yet reachable." Below the list, a read-only preview of the resulting chain or branch — it's derived from what each variant declares, not authored here directly.

Edit token · Variants Draft

Dollar Wallet
Original Token · the default · the only one that mints
Default
Opened Wallet
Reached via Open · from Original Token
Golden Wallet
Reached via Gild · from Original Token — and Un-gild declared back to it
2-way
Original Token
OpenOpened Wallet
GildGolden Wallet
two-way — because Original Token also declares an incoming transition (Un-gild) from Golden Wallet. There is no reversible flag; a return path is a second declared transition, and cycles are legal.
06Edit a variant — name, asset, and its transitionThis is where a variant is actually configured: its asset and name, and its transition — the variant it's reached from, and what triggers the change into it. Triggering can reuse a shared action template (when other tokens follow the same path with the same asset) or be defined as a one-off just for this variant — templates are optional. A variant may declare more than one incoming transition, and the Original Token / default may declare them too — which is how a return path and a full cycle are expressed. (The default is edited from the token's Details & Assets tabs, like any token — it has no transition of its own to configure.)

Edit variant · Golden Wallet

Reusable — pick this again for any other token that reaches a variant the same way with the same asset.
A holding on Original Token will show a Gild button once this is saved. A holding on Golden Wallet shows a way back only because Original Token separately declares Un-gild from it — declare both directions and you have a two-way pair.
06 ·One-off trigger — no shared templateSame modal, "One-off for this variant" chosen instead. The template dropdown is replaced by the wording fields directly — nothing is added to the reusable Actions library. A good fit when only one token ever needs this exact path.

Edit variant · Sprout

What the holder taps.
Pins an exact version. Editing the template later never changes a token already Live.
Later, if another token needs this same path and asset, this can be promoted into a reusable template from the Actions tab.
06 ·A multi-step chain is just this same form, repeatedThere is no separate "build a chain" flow. A 4-link chain like Relic's (Unforged → Forged → Awakened → Ascended) is three of these single-transition edits, one per non-default variant — each one just points its Reached from at whichever variant comes before it. Here, editing Awakened Relic: its "Reached from" select lists every other variant on this token — Unforged Relic, Forged Relic, Ascended Relic — and Forged Relic is chosen, making this the second link in the chain. Editing Ascended Relic the same way, with "Reached from: Awakened Relic," adds the third. Branches work the same way — two variants both pointing "Reached from" at the same predecessor (frame 05's Dollar Wallet example) instead of at each other in sequence.

Edit variant · Awakened Relic

Every other variant on this token — pick whichever one this step follows.
Unforged RelicForge Forged RelicAwaken Awakened Relic
Ascended Relic has no transition configured yet.
07Topology integrity · deletion blocks, and reachability at go-LiveTwo rules keep the graph sound. Deletion is blocked while another variant is reached from this one — shown below. And at go-Live, every non-default variant must be reachable from the default by following declared transitions: orphans, and closed cycles the default cannot enter, fail with the unreachable variants named. Because cycles are legal, validation walks from the default with a visited set. Deleting from the Variants tab's row action. Blocked when another variant's transition is reached from this one — the exact dependency is named, with a way to jump straight to it.

Can't remove Forged Relic

Awakened Relic is reached from this variant. Change or clear that variant's transition first, then Forged Relic can be deleted.
Variants & Actions · collection-level, browse only
08Collection · Variants page — Actions tabOne collection-level page with two tabs (more may be added as variants grow): Variants (frame 10 — browse every variant) and Actions (here — the optional, reusable template library). Both stay reachable whatever the collection's own stage; nothing here is edited from this page — editing happens on the token (frames 04–07). A template locks the moment any variant using it belongs to a Live token: Open and Gild are locked because Dollar Wallet is Live; Forge / Awaken / Ascend stays editable because Relic (its only user) is still Draft.
Studio/Collection: Paper Trail/Variants
Live
Collection · Variants

Variants.

Every variant in this collection, and the optional action templates that trigger them.

Reusable wording you can apply to any variant's transition — optional, only useful when more than one token shares a path and asset.

TemplateButton wordingVersionUsed byActions
Open
Openv1 · frozenDollar Wallet Live · lockedLocked
Forge / Awaken / Ascend
variesv3 · editableRelic Draft
Gild
Gildv2 · frozenDollar Wallet Live · lockedLocked
Un-gild
Un-gildv1 · editableUnused
09Action template editorOpened from "+ New template" or a template's Edit icon. Purely reusable wording and behaviour — which variants it connects is chosen where the template is picked, on each variant's own edit panel (frame 06), not here.

Action template

Internal — how you'll find this template in the list.
What the holder taps.
A variant pins an exact template version. The template stays editable — each edit makes a new version future tokens may pin — and a version pinned by a Live token is frozen.
10Collection · Variants page — Variants tabEvery variant across every token in the collection, browsed the same way tokens are — card grid or list, search, filters, pagination. Read-only: this is a catalog for finding and reviewing variants, not for editing them (that's frames 04–07, on the token). The Original Token of each token is not listed here — it's the token itself, not a variant of it; this catalog only holds the additional variants layered on top.
Studio/Collection: Paper Trail/Variants
Live
Collection · Variants

Variants.

Every variant in this collection, and the optional action templates that trigger them.

Token

Status

Source

Opened Wallet
Dollar Wallet
Opened Wallet
Via Open
Golden Wallet
Dollar Wallet
Golden Wallet
Via Gild
Forged Relic
Relic
Forged Relic
Via Forge
Awakened Relic
Relic
Awakened Relic
Via Awaken
Ascended Relic
Relic
Ascended Relic
Via Ascend
Bloom
Seedling
Bloom
Not yet reachable
Showing 6 of 6
Holder · wallet
11In your walletA holding shows a button only when it's owned, active, not listed, and its current variant has an incoming... rather, an outgoing trigger declared by some other variant that names it as "from". The card shows the token's current name and asset — there's no variant-state label on it. Three points along the Relic chain.
Unforged Relic
Relics

Unforged Relic

#014
Limited edition
Forged Relic
Relics

Forged Relic

#014
Limited edition
Ascended Relic
Relics

Ascended Relic

#014
Limited edition

Same holding (#014), three points on its journey. Left: at the start, so Forge shows. Middle: mid-chain — the same holding after Forge ran, now showing the next step's button, Awaken. Right: at Ascended Relic, the end of the chain — no variant names it as "from," so no action button, same as any token with no variants.

12A branch, from the holder's sideTwo variants (Opened Wallet, Golden Wallet) both declare the Original Token as their "from" — so a holding on the Original Token shows both buttons. Both buttons show — the holder picks which action to run, same confirm-then-run flow either way (frame 13).
Dollar Wallet
Paper Trail

Dollar Wallet

#042
Limited edition

Running either one moves this holding off the Original Token — a holding only ever sits on one variant at a time, so taking one branch removes the other's button along with it.

13The prompt · in the creator's wordsBefore the action runs, the holder sees the creator's warning and confirms. Amber caution — this changes the token, it doesn't delete it. Two examples: a one-way step, and one whose target also declares a transition back. The holder is told which, in plain words — the mechanism (a second declared transition) is not their concern. A one-way step, and one whose target declares a transition back.

Open this token?

Warning — you're about to Open this token. This change is permanent and can't be undone.

Evolve this token?

Warning — you're about to Evolve this token. This change is reversible — you can change it back to the Original Token later.
14After the actionThe token now shows the variant's name and asset, plus whatever button that variant's own "from" declarations provide next. Left: a one-way step — the token simply is the new variant now. Right: where the source variant declares its own transition back, the holder simply sees a way back.
Opened Wallet
Paper Trail

Opened Wallet

#042
Limited edition
Evolved
Paper Trail

Evolved Seedling

#088
Limited edition
Variant profiles · applying a shared set
15Applying a profile — the rulesRevisedDeveloper reference — not a screen. A variant profile is a named, versioned, project-level variant set. Applying one to a token snapshot-copies the set; editing the profile afterwards never reaches a token that already applied it. Apply is additive: it adds variants and updates uncustomised ones, and it never removes, never re-keys, and never overwrites a local edit. See frame 21 for why it is no longer append-only.
Apply and re-apply — every case
CaseWhat happens
In the profile, not on the tokenAdded, with a fresh variant_id, at the profile's own place in the order — or at the end once the creator has reordered by hand
From the profile, not customisedName and asset updated to the new version. Its key and variant_id never change
From the profile, customised locallyPreserved, and reported as customised — the profile never reaches its content again
On the token, absent from a newer profile versionBlocker. Reported with what references it; never removed for you (frame 18)
Profile key collides with a locally authored variantWhole apply rejected, naming the key and both sources (frame 17)
Merged length would exceed 255Whole apply rejected (frame 17)
The default variantNever touched. A profile carries no default field and cannot set one
Re-apply matches on the key each variant was copied from — never on position, never on the name. So renaming Admitted to Scanned in the profile updates the same variant rather than looking like a new one, and reordering either side matches nothing differently (frame 21).
Where it came from · and two independent things that can be true of it
Shown asMeaning, and what it changes
Festival ticket v2From the profile, untouched. A re-apply updates its name and asset; a detach removes it
customisedIts name or asset was edited here. Re-apply never overwrites it, and detach leaves it behind
has transitionsA transition or action binding names it. This blocks detach only — its name and asset still update from the profile, because a profile carries the set and never the topology
Authored locallyNever came from a profile. Unaffected by anything a profile does
The middle two are independent, and a variant can carry both. Treating "has transitions" as a customisation would freeze a variant out of its profile the first time anyone wired it up — and wiring unused → admitted is the entire point of a ticket profile, so the profile would break on first use.
16Token · Variants tab — a profile appliedRevisedThe same tab as frame 05, after Seasonal reskin v3 was applied. Each row carries its stable variant_id and its source. Winter Wallet came from the profile untouched; Summer Wallet came from it and has since been renamed, so its content has gone local; Autumn Wallet is untouched but has a transition declared against it, which blocks detach without blocking updates; Golden Wallet was authored by hand. Topology is still declared per variant — a profile carries the set, never the transitions — so every row still needs its own "reached from" (frame 06). Apply, re-apply and detach are Draft only; from Review the same action is offered as one atomic step that returns the token to Draft (frame 22). Everything freezes at Live.

Edit token · Variants Draft

From Seasonal reskin · v3 — 2 of 3 from this profile
Dollar Wallet
id 0 · Original Token · the default · the only one that mints
Default
Winter Wallet
id 3 · Reached via Chill · from Original Token
Seasonal reskin v3has transitions
Summer Wallet
id 7 · Not yet reachable
Seasonal reskin v3customised
Golden Wallet
id 12 · Reached via Gild · from Original Token
Authored locallyhas transitions
Summer Wallet was renamed here, so re-applying will not change its name or asset, and detaching will leave it behind. Winter Wallet has a transition — that only blocks detach; its name and asset still update with the profile.
17Apply rejected — nothing partially appliedNewTwo rejections, and in both cases no variant is added at all — a partial apply is never performed. Left: a key already in use. The message names the key and both sources, because "duplicate key" alone leaves the creator guessing which of their variants collided. Right: the merged set would exceed the 255-variant ceiling. Both are the same rule the attribute templates already follow.

Can't apply Seasonal reskin

The key golden is already in use on this token.
It belongs to Golden Wallet, authored locally. Seasonal reskin v3 also defines golden. Rename one of them, then apply again.
Nothing was added — the whole profile was rejected, not just the clashing variant.

Can't apply Seasonal reskin

That would take this token to 258 variants.
A token can hold 255. It currently has 251, and this profile adds 7. Remove some variants, or apply a smaller profile.
18Re-apply — a variant the new version dropsNewThe dry-run always runs before anything is written, and it reports all four outcomes at once. Here v4 of the profile no longer contains Autumn Wallet — so re-apply stops and says what depends on it. It does not offer to remove it: deleting a variant is a deliberate act the creator performs themselves, never a side effect of accepting a template update.

Re-apply Seasonal reskin · v3 → v4

VariantSourceOutcome
Spring Wallet
New in v4Will be added
Winter Wallet
From profile, untouchedUnchanged
Summer Wallet
CustomisedSkipped — customised
Autumn Wallet
Not in v4Blocked
Autumn Wallet isn't in v4, and something still points at it.
Winter Wallet is reached from it, and it uses the Fall action template. Change or clear those first if you want it gone — nothing here will remove it for you.
19Detach a profile — what goes, what staysRevisedDetach removes only the variants that came from this profile and carry neither marker. Anything customised stays; anything authored by hand was never the profile's and stays; anything a transition or action binding names is a blocker; and the default variant is never touched. This is the reason the markers in frame 15 have to exist — without them, a creator cannot predict this screen before opening it.

Detach Seasonal reskin?

VariantSourceOn detach
Winter Wallet
From profile, untouchedRemoved
Summer Wallet
From profile · name edited hereKept
Golden Wallet
Authored locallyKept
Autumn Wallet
From profile · has transitionsBlocked
Autumn Wallet can't be removed. Winter Wallet is reached from it. Clear that transition first, or keep the profile attached.
Detach is Draft only — from Review it is offered as a return-to-Draft step first (frame 22). Once the token is Live the variant set is frozen and nothing here can change.
20Nothing to apply yet — two different empty statesNewThese say different things and must not be merged. Left: the project has no variant profiles at all, so the creator is pointed at the Templates library to make one. Right: a profile exists but its working copy has never been published — a Draft template is never appliable, so "nothing here" would be actively misleading to someone who has just authored one and is looking for it.

Apply a variant profile

This project doesn't have any variant profiles.
A profile is a named set of variants you can apply to many tokens at once — useful when several tokens share the same set. You can make one in the project's Templates library.

Apply a variant profile

Seasonal reskin hasn't been published yet.
Only published versions can be applied — a draft is still being edited. Publish it in the Templates library and it will appear here.
Variant identity · Draft-only apply · contract authority
21Variant identity — the id, not the positionNewDeveloper reference — not a screen. Every variant gets a variant_id when it is created, and keeps it for good. Holdings, the default variant, transition endpoints and policy endpoints all name that id. Where a variant sits in the list carries no meaning, which is what makes reordering safe and lets a profile place a variant anywhere rather than only at the end.
The four rules
Assigned once, never changed

A variant's id is set at creation and is immutable. Renaming it, moving it, or changing its asset never touches the id.

Never reused

Deleting a Draft variant retires its id permanently. Nothing later inherits it, so a stale reference can never quietly point at something else.

Ids are gappy, and that is normal

Because they are never reused, a token's ids are usually not consecutive. Never show an id as a position, a count, or an ordinal — it is a name that happens to be a number.

Order is presentation only

display_order is what the creator arranges. It can change at any stage, including after Live, because nothing reads meaning from it.

A festival ticket, after the creator inserted VIP and deleted two drafts along the way
Shown atStable idKeyWhat references it
1stid 0unusedThe default variant · 10,000 holdings · the source of unused → admitted
2ndid 9vipAdded last, placed second. Its position says nothing about when it arrived
3rdid 7admitted3,000 holdings · the target of unused → admitted
4thid 8souvenirThe target of admitted → souvenir
Ids 1–6 were allocated to drafts that were deleted, so they are retired and will never be issued again. If identity were the position instead, inserting VIP second would have silently turned 3,000 scanned-in ticket holders into VIPs — no error, nothing to notice.
Before reordering is switched on
Every positional lookup over the variants list has to be found and removed first — including anything that treats the first variant as the Original Token. The Original Token is whichever variant default_variant names, never whichever one sorts first.
22Applying from Review — one step, and it costs reservationsNewApply, re-apply and detach are Draft only: a token in Review is locked, and its only moves are going Live or returning to Draft. The action is still offered here, as a single atomic operation that returns the token to Draft and applies — never two separate steps, because returning to Draft releases the issue-number reservation and that cannot be undone. The tokens stay in Draft afterwards for re-submission: the definition that was approved has to be the definition that was reviewed.

Apply Festival ticket v2 500 tokens

This will return 500 tokens to Draft before applying the update.
37 active issue-number reservations will be released and may be claimed by other tokens. They will not be reserved again automatically — each token re-reserves when you resubmit it for Review.
The 37 numbers at risk
#0001#0002#0007#0012#0018#0023#0031#0044#0050+29 more
A count alone is not enough to decide with — the low numbers are usually the ones that matter.
Every token is checked before anything is released. A token that would fail the apply never leaves Review, and no reservation is given up for it.
23Batch preview — atomic per token, mixed outcomes expectedNewThe preview runs before anything is written and shows every outcome at once. A token either applies completely or not at all — but one blocked token never fails the others. This is the same discipline the state-policy batch tool already uses, so there is one rule rather than two.

Apply Festival ticket · v1 → v2

TokenStageOutcome
Day pass
DraftAdds 1 · updates 2
Weekend pass
DraftUpdates 2 · keeps 1 customised
VIP pass
Review · holds #0007Returns to Draft first
Camping add-on
DraftBlocked · key collision
Season ticket
LiveSkipped · frozen
Camping add-on will be skipped. Its locally authored variant already uses the key souvenir. The other four are unaffected — rename it and run this again to include it.
Nothing has been written yet. 3 tokens will change, 1 is blocked, 1 is frozen.
24Re-apply — what a new profile version actually changesNewDeveloper reference — not a screen. A newer version does update the variants that came from it and have not been customised here; that is the point of versioning a profile. It matches each one on the key it was copied from, so the id, the holdings and the transitions all survive a rename in the profile.
Festival ticket v1 → v2 · the profile renamed Admitted to Scanned and added VIP
VariantOn the token nowAfter re-applyWhy
id 0 unusedUnused · from v1Name and asset updatedFrom the profile and never edited here, so v2's content lands on it
id 7 admittedAdmitted · from v1Renamed to Scanned, id and holdings untouchedMatched on the key admitted, not on the old name — a rename in the profile is not a new variant
id 8 souvenirKeepsake · renamed hereLeft exactly as it isCustomised locally. The profile never overwrites a creator's own wording
id 3 earlybirdEarly bird · from v1Blocked — nothing is writtenv2 dropped it, and removing a variant is never something an update does on your behalf (frame 18)
—Not presentAdded as id 9VIP is new in v2. It takes the next free id, and can sit second in the order without disturbing anything
A transition declared against a variant does not stop it updating. unused → admitted being wired up is the normal state of a working ticket, not a customisation — it only blocks detach.
25Token · State tab — the rules come from the contractNewThe State Policy is resolved into the token's contract version when that contract is published. The token stores which contract it pins and nothing else, so there is no second copy to drift, edit or reconcile. That makes this tab read-only by construction rather than by restraint — there is no attach, re-apply or detach control here because there is no separate object to act on. Changing the rules means a new contract version and an explicit migration, which is a Draft-only batch operation.

Edit token · State Draft

Festival admission
State policy · v4 — resolved into Ticket contract v6
From the contract
FieldWho may writeRule
variantOwnerTransitionable · one-way
scanned_atApproved appOne-time write
gateApproved appOne-time write
To change these rules, publish a contract version carrying the newer policy and migrate this token to it. Migration is a Draft-only batch operation, and it is validated before it runs. Once the token is Live it does not migrate at all.
Runtime values still move after Live — a ticket can still be scanned. What freezes is the rulebook, not the memory.