---
title: "Contracts — PDLibraryRegistry"
description: "The append-only on-chain store for blessed JavaScript libraries (at launch, p5.js and the gzip inflater) that PD Projects bind and render from — frozen forever once finalized."
category: "contracts"
keywords: ["PDLibraryRegistry", "libraries", "p5.js", "SSTORE2", "append-only", "Language"]
last_updated: "2026-10-12"
---

# Contracts — PDLibraryRegistry

The registry is the platform's on-chain shelf of blessed JavaScript libraries — the p5.js a Project's script depends on, stored on Ethereum so the art's dependencies are as permanent as the art. Entries are written in chunks, finalized, and then **frozen forever: no edit, no delete, no overwrite, by any key, ever.** A mutable registry would be a back door into already-sold art; append-only is the hard rule. New versions are new entries.

## How an entry is stored

Each library is a named, versioned byte blob written across SSTORE2 chunks (each within the EVM's 24,575-byte data-contract ceiling) over multiple transactions, then finalized:

```solidity
function createLibrary(...) external onlyAdmin;                     // open an entry
function appendChunk(uint256 libraryId, bytes calldata data) external onlyAdmin;
function finalize(uint256 libraryId) external onlyAdmin;            // freeze forever
```

Library text is stored as the **base64 of its gzipped source** — artwork pages embed it verbatim and decode it client-side, which keeps write costs sane and reads free of on-chain re-encoding. The registry also stores the raw **inflater** tool (`setInflater`) that artwork documents inline to do that decoding — so even the decompressor the art depends on lives on-chain.

Every entry is one of two kinds, named when it is created. A `library` is that base64 text. A `tool` is raw JavaScript inlined as it is: the inflater, which defines `PD_INFLATE`. Only a finalized `tool` can be designated the inflater (`setInflater` reverts `NotFinalized` or `WrongKind` otherwise), and a Project binds only a `library` (its deployment reverts `WrongLibraryKind` otherwise).

## How Projects use it

A Project binds at most one library, fixed at `createProject` time; the factory enforces that only **finalized** entries can be bound. The Project also copies the registry's current inflater at deployment and keeps it forever, so designating a new inflater only changes Projects deployed after it (and `createProject` takes the inflater id the artist previewed with, reverting if it has changed since). At render time, `tokenURI` inlines that inflater, the library blob, and a bootstrap that decodes and injects the library as synchronous script text before the artist's first line runs. See [PDProject](/docs/contracts/pd-project).

The binding is also where every Output's **Language** attribute comes from: the entry's exact "name version" (`p5.js 1.11.13`) is copied into the Project at deployment and rides its metadata forever — the artist's tool, versioned and stored on Ethereum, not a label anyone typed. Vanilla Projects read `JavaScript`.

## The supported languages

PD launches with one blessed library, written to the registry as its own frozen entry:

| Library | For |
| --- | --- |
| **p5.js 1.11.13** | The lingua franca of creative coding, in the version most existing sketches target |

The entry is the library's official npm build, gzipped and base64'd, and it decodes back to the original byte for byte through the on-chain unzipper. What each gives your script is on [Writing for the Chain](/docs/for-artists/writing-for-the-chain#pick-your-language).

Vanilla **JavaScript** is always available and needs no registry entry at all. The vocabulary extends itself the day a new library is blessed — a new entry, finalized and frozen, with no list anywhere to maintain.

```solidity
function isFinalized(uint256 libraryId) external view returns (bool);
function readLibrary(uint256 libraryId) external view returns (bytes memory);
function libraryInfo(uint256 libraryId) external view returns (...);  // name, version, size
function chunkCount(uint256 libraryId) external view returns (uint256);
```

## Governance

Deliberately none of its own. Writes are gated by a live read of the factory's `admin()` — the registry adds no second governance surface. One wrinkle from deploy order: the factory takes the registry's address as a constructor immutable, so the registry deploys first and its deployer wires the factory address exactly once (`wireFactory`); after wiring, the deployer key holds no power at all. No pause, no upgrades.

## Further reading

- [PDProject](/docs/contracts/pd-project) — the render pipeline that reads this
- [PDFactory](/docs/contracts/pd-factory) — the admin whose key gates writes
- [Contracts Overview](/docs/contracts/overview)
