Project presentation and native reads
Select a project's marketplace content, freeze presentation choices, and read stored bytes from Solidity.
Project presentation controls animation_url, a content field commonly used by NFT marketplaces, for orgs created by a factory with
projectPresentation. It is separate from publishing: versions remain append-only,
and presentation changes do not rewrite stored content. Check deployment status
for the current generation and the original factories retained for older orgs.
Choose a delivery method
| Method | What the token renders | When to use it |
|---|---|---|
| ChainGateway | A chain-specific URL for the selected root and path | The on-chain default; websites, larger files and content with dependencies |
| Embedded | The selected file's bytes, embedded by ABX in metadata | Supported HTML, SVG, image, audio or video payloads with a suitable caller budget |
| IPFS | ipfs://<cid>/<path>, or an explicit subdomain gateway URL | An explicit creator choice, with pinning arranged separately |
auto is a CLI/SDK recommendation, not a fourth on-chain mode. Its configurable
tooling policy defaults to 100 KiB of inspected content; it writes Embedded for
suitable supported payloads with no detected dependencies, otherwise ChainGateway.
This is a recommendation, not a contract limit or a promise that every RPC can
render the complete metadata. The current presentation generation places no fixed
byte, chunk or gas policy on explicit Embedded. Natural caller gas and RPC response
limits still apply. The superseded presentation generation had an 8,192-byte/32-chunk
limit; older original factories have no presentation capability.
Raw storage and FastLZ storage decode natively. File-level codecs such as gzip need
off-chain decoding and cannot use Embedded. text/uri-list is reserved for locator
output, not embedded content. Relative/external references and detected network or
opaque dynamic code favor a gateway origin. Inline JavaScript can qualify, but
static inspection cannot prove arbitrary code self-contained: review
runtimeUncertain, residualDependencies, and readReach in the plan.
Auto never selects IPFS. On-chain IPFS derivation cannot decode file-level codecs,
including a known changed codec file elsewhere in the derived directory root. The
planner blocks these known incompatibilities and proven absent configured targets
before publication. A directory URL does not require index.html; MIME and Auto
size preferences do not restrict an explicit IPFS choice. Planning does not scan
all unchanged siblings or guarantee complete root derivation.
Choosing IPFS computes a CID; it does not pin anything or
promise availability. The creator must pin the content
and keep it available. An empty IPFS endpoint uses ipfs://; a base such as
https://dweb.link produces https://<cid>.ipfs.dweb.link/....
An empty chain endpoint uses the generation's default gateway; a custom chain base
must serve /g/cid/<chain>/<root>/<path>. Use HTTPS bases without a trailing slash.
A first publication uses Auto when its org supports presentation, including an
already-minted empty project. Tooling suggests index.html, otherwise the sole
file, otherwise the directory root. An explicit path, including "", takes
precedence. Deliberately preconfigured source and method choices are preserved
independently; setting endpoints alone does not disable initial Auto selection.
Later upload --project-id and update preserve the saved source, method and
endpoints unless --presentation or --presentation-path explicitly changes a
choice. They never silently downgrade an owner's method. After publication the CLI
checks complete tokenURI with a bounded read pinned to the final confirmed
settings transaction, or publication transaction when no settings changed, as well
as native preview on update.
A failure produces a warning and exact inspection/recovery commands; publication
remains successful and must not be repeated. See the CLI commands
and SDK planner.
Select the source
Choose Latest, a 1-based Version, or a named Tag, plus an optional path
inside that root. Latest follows new publishes; Tag follows tag movements; Version
selects one historical root. An empty path selects a file root or index.html in a
directory when reading Embedded content. A selected directory likewise reads its
index.html. Presentation paths are relative, without empty segments, ./..,
backslashes or control bytes, and fit 2,048 UTF-8 bytes, 32 segments and 255 bytes
per segment. Explicit invalid targets are blocked before publishing, regardless of
delivery method. If a suggested entrypoint exceeds these limits, Auto keeps the
directory root and chooses ChainGateway; this does not reject a valid deeper
content tree.
presentation inspect reports the exact selected root and path, method, endpoints
and locks. presentation preview adds the status, MIME type, payload and dependency
analysis without a signer. Native preview and payload analysis do not prove that
the full ABX metadata can be serialized within a caller budget. A 100 KiB payload
can require close to 50 million gas for complete tokenURI, depending on content
and metadata. A Ready URL preview does not check that its remote
endpoint is online. Semantic missing or unpublished targets and unsupported codec/MIME states return an
empty text/plain payload, encoded by ABX as the inert data:text/plain;base64,
animation URI. Actual native read or IPFS derivation failure is surfaced as a typed
render failure, and insufficient caller gas can fail the complete metadata read.
Inspect diagnostic preview to distinguish these cases; do not treat native preview
as a guarantee of complete metadata availability.
Browser and marketplace support for HTML, data URIs and IPFS varies. Preserved bytes and valid token metadata do not guarantee that every viewer can display or execute the content.
Freeze independent choices
Only the project token owner may configure or lock its presentation. Freezing the displayed content is one-way, including for future owners. Three permanent locks can be combined:
| Lock | Commitment |
|---|---|
| Content | The reviewed selected root and path, even if Latest or a Tag later moves |
| Method | ChainGateway, Embedded or IPFS |
| Endpoints | The configured chain and IPFS endpoint bases |
Every lock requires an explicit commitment to the reviewed state of its selected
dimensions. Dry-run the exact CLI lock command, review the output, then copy its
expectedCommitment into --expected-commitment for submission. The contract
checks it when the transaction executes; changed selected state requires a fresh
review. SDK callers read the commitment at the preview's block. Locks survive transfers and have no
force override. Publishing later versions remains possible. Freezing content alone
does not freeze its delivery method or the services an endpoint depends on.
external_url remains separate: it uses the org's link renderer and abxfs.view
override. A view override cannot bypass presentation locks or replace the new
animation_url. Legacy token links describes orgs
whose animation and external links both use that older renderer.
Native Solidity reads
ContentReader is a stateless companion with immutable file/directory store
addresses and no roles or ETH. It adds no mutable content registry and changes no
CIDs. Its view calls return MIME type and bytes:
(string memory mime, bytes memory data) = reader.readPath(root, "index.html", 8192, 32);
// Direct file or byte range:
(mime, data) = reader.readFile(fileCid, 8192, 32);
(mime, data) = reader.readFileRange(fileCid, 0, 128, 8192, 32);
// Latest project root; use a 1-based version OR a tag to select history:
bytes32 selected = reader.projectRoot(org, tokenId, 0, "");
(mime, data) = reader.readProject(org, tokenId, 0, "stable", "index.html", 8192, 32);Native reads support raw and FastLZ storage: FileStore.readChunk decompresses the
storage backend. They reject file-level codecs, including gzip, Brotli and Zstandard;
use the SDK or chain gateway to decode those. Whole-file reads check recorded byte
and chunk totals before allocating content. Range limits include the full decoded
sizes of touched boundary chunks, not just returned bytes. Limits bound bytes and
chunk reads, not backend gas; Solidity callers containing failures should also cap
call gas. projectRoot follows the org's own configure hook, including older orgs;
it is a content convenience, not proof of factory registration.
Use stored content in an ABX reader field
AbxContentReader adapts a fixed root/path to ABX's read(address) reader ABI.
Deploy one with the reader address, root, path and explicit limits, then encode the
adapter as both reader and pointer:
AbxContentReader adapter = new AbxContentReader(address(reader), root, "index.html", 8192, 32);
bytes memory readerValue = abi.encode(address(adapter), address(adapter));
bytes memory data = adapter.read(address(adapter));Use readerValue as the value of an ABX field configured with its on-chain reader
representation. The pointer identifies this fixed adapter; any other pointer is
rejected. Its source and limits cannot be redirected after deployment. File codecs
remain unsupported. This adapter supplies bytes to an ABX field; it does not give an
older ABX FS org the new presentation renderer.
Factory generations stay available
Presentation is a factory-generation capability. Resolve an existing org with
client.resolveOrg(org) first. An older generation without projectPresentation
reports PresentationCapabilityError rather than borrowing the current contract.
A native reader can still read old content using its matching stores; if the store
pair differs, use a reader deployed for that pair or ordinary SDK reads.
A replacement factory creates new orgs. Earlier factories, hooks, minters,
enumeration contracts and lenses remain registered together in previousGenerations
so their orgs can still be listed, read, minted into and published to. Those records
are permanent compatibility history, not temporary migration entries.