Archive CLI
Start with one command
# Build a website indexnpx @whitehash/archive project v2:13944# Preserve one token offlinenpx @whitehash/archive \"https://www.fxhash.xyz/gentk/KT1KEa8z6vWXDJrVqtMrAeDVzsvxat3kHaCE-16333"
Choose your outcome
Start with the result you need. The index commands describe artwork for a hosted application; the archive commands collect the files needed to keep and replay it offline.
| If you need to… | Use | You get |
|---|---|---|
| Load artwork on a website | --json, project, or token | Portable JSON with normalized identities, metadata, and content-addressed URIs; not artwork bytes |
| Keep artwork available offline | An identity-bearing token URL or wallet | A self-contained archive with artwork assets, previews, integrity data, and offline replay support |
How the JSON formats align
Both index formats are designed for hosted applications, not offline preservation. They use the same normalized project and token shapes. A project index stores tokens in iterations[]; a token index stores one token at token. Missing chain metadata is written as null, never silently omitted.
For Tezos tokens, the CLI follows the gentk contract’s token_data.issuer_id back to the issuer project and loads its capture settings. For EVM tokens, the collection contract is the project ID, but capture settings remain null when the public collection/token metadata does not publish them.
| Field | Project index | Token index |
|---|---|---|
format | whitehash-project-index@1 | whitehash-token-index@1 |
generatedAt | ISO timestamp | ISO timestamp |
project | Normalized project metadata | The same normalized project metadata |
project.captureSettings | Normalized project capture configuration or null | The same configuration when discoverable from the parent project |
token data | iterations[].token | token |
raw | Original metadata on every token | Original metadata on the token |
pagination | order, complete, nextCursor | Not applicable |
Index a project
Tezos project IDs such as v2:13944 identify their chain automatically. For EVM projects, prefix the collection address with base: or ethereum:.
The CLI follows every discovery cursor and writes the versioned whitehash-project-index@1format. It includes normalized project data, display-ready iterations, and original token metadata for fields such as fx(params) that are not normalized yet. The project reader’s provider envelope is omitted.
Every iteration retains its canonical chain, contract, and tokenId. Use the static metadata immediately, or refresh that identity from chain when freshness matters.
npx @whitehash/archive project v2:13944 \--out ./public/monogrid.json
For a project’s market history, the market command writes listings, offers, sales, mints, and derived statistics into their own artifact. See the market history guide.
{"format": "whitehash-project-index@1","generatedAt": "2026-07-23T12:00:00.000Z","order": "oldest","project": {"chain": "tezos:mainnet","id": "v2:13944","name": "Monogrid 1.1","description": "…","displayUri": "ipfs://…","thumbnailUri": "ipfs://…","editions": 256,"minted": 256,"captureSettings": {"mode": "VIEWPORT","triggerMode": "DELAY","gpu": false,"resolution": { "x": 800, "y": 800 },"delay": 2000}},"iterations": [{"position": 1,"token": {"chain": "tezos:mainnet","contract": "KT1…","tokenId": "12345","name": "Monogrid 1.1 #0","description": "…","iterationHash": "oo…","artifactUri": "ipfs://…","displayUri": "ipfs://…","thumbnailUri": "ipfs://…","generatorUri": "ipfs://…","attributes": [{ "name": "Palette", "value": "Blue" }],"assigned": true,"metadataUri": null,"raw": { "original": "metadata remains available here" }}}],"complete": true,"nextCursor": null}
Display an indexed project
Validate imported or fetched JSON before using it. Lookup is a direct array access and returns the ordinary WhitehashToken shape expected by Artwork.
import {parseProjectIndex,} from "@whitehash/chain-reader"import { Artwork } from "@whitehash/ui"const projectJson = await fetch("/monogrid.json").then(response => response.json())const { iterations } = parseProjectIndex(projectJson)const token = iterations[24]?.tokenreturn token ? (<Artwork.Root token={token}><Artwork.Image /><Artwork.Live /><Artwork.PlayButton /></Artwork.Root>) : null
Build a website index for one token
Paste an identity-bearing token URL with --json to write the smaller whitehash-token-index@1 format for a hosted website. This normalized JSON retains content-addressed URIs; it does not contain the artwork bytes.
npx @whitehash/archive \"https://www.fxhash.xyz/gentk/KT1KEa8z6vWXDJrVqtMrAeDVzsvxat3kHaCE-16333" \--json \--out ./public/token.json# The existing coordinate form remains available:npx @whitehash/archive token \KT1U6EHmNxJTkvaWJ4ThczG4FSDaHC21ssvi 784640 \--out ./public/monogrid-1.json
{"format": "whitehash-token-index@1","generatedAt": "2026-07-23T12:00:00.000Z","project": {"chain": "tezos:mainnet","id": "v2:13944","name": "monogrid 1.1 CE","description": "…","displayUri": "ipfs://QmXC…","thumbnailUri": "ipfs://QmTz…","editions": 256,"minted": 256,"captureSettings": {"mode": "VIEWPORT","triggerMode": "DELAY","gpu": false,"resolution": { "x": 800, "y": 800 },"delay": 2000}},"token": {"chain": "tezos:mainnet","contract": "KT1U6EHmNxJTkvaWJ4ThczG4FSDaHC21ssvi","tokenId": "784640","name": "monogrid 1.1 CE #1","description": "…","iterationHash": "opas…","artifactUri": "ipfs://QmQt…","displayUri": "ipfs://QmfA…","thumbnailUri": "ipfs://QmaP…","generatorUri": "ipfs://QmQt…","attributes": [{ "name": "Style", "value": "Line" }],"assigned": true,"metadataUri": null,"raw": { "original": "metadata remains available here" }}}
Display an indexed token
Validate the token JSON, extract its normalized token, and pass it directly to Artwork.
import {parseTokenIndex,} from "@whitehash/chain-reader"import { Artwork } from "@whitehash/ui"const json = await fetch("/monogrid-1.json").then(response => response.json())const { project, token } = parseTokenIndex(json)return (<Artwork.Root token={token}><Artwork.Image /><Artwork.Live /><Artwork.PlayButton /></Artwork.Root>)
Refresh one token from chain
The index is an acceleration layer, not a new identity system. Resolve its token ref through the client when you need the latest reveal or metadata state.
import {createWhitehashClient,defaultChainReaderConfig,tokenRef,} from "@whitehash/chain-reader"const ref = token ? tokenRef(token) : nullconst current = ref? await createWhitehashClient(defaultChainReaderConfig()).getToken(ref): null
Discover EVM iterations without an indexer
RPC mode probes the deployed fxhash collection’s supply and token-ID boundaries, constructs the verified zero- or one-based range, and hydrates those identities through on-chain tokenURI calls. A mint-event scan handles non-sequential contracts. It bypasses Blockscout for iteration discovery and produces the same index format.
npx @whitehash/archive project \base:0x50c04A6B066d659Fe2F66F6388Cf8dD394036632 \--direct \--out ./public/dom2.json
Preserve artwork offline
Paste an identity-bearing fxhash token URL to download IPFS CAR files or read onchfs bytes from chain, write available preview assets, and produce integrity hashes plus an offline wrapper. The identity is parsed locally without an fxhash-hosted service.
npx @whitehash/archive \"https://www.fxhash.xyz/gentk/KT1KEa8z6vWXDJrVqtMrAeDVzsvxat3kHaCE-16333"npx @whitehash/archive verify ./whitehash-token-16333
The ordinary verify command is deterministic and offline: it checks hashes, required files, local references, and path safety. Add the explicit opt-in flag below to compare the recorded token snapshot with current public chain data.
npx @whitehash/archive verify ./whitehash-token-16333 --onchain
Slug-only iteration links do not contain an on-chain identity. While the fxhash website remains available, resolve one explicitly and then run the same archive pipeline:
npx @whitehash/archive \"https://fxhash.xyz/iteration/monogrid-1.1-ce-256" \--resolver fxhash
For collection-scale preservation, the existing wallet command uses the same archive writer and format:
npx @whitehash/archive wallet tz1… \--chains tezos \--out ./whitehash-archivenpx @whitehash/archive verify ./whitehash-archive