Onchain Art Composability: Artblocks pushing for permanency

December 15th, 2023

Onchain Art Composability: The Dependency Registry Revolution

Three years ago, I wrote about the permanency problem in NFTs. The biggest challenge wasn't storing the art, it was storing the dependencies. You could put the generative script onchain, but if it needed p5.js or three.js, you were still dependent on external CDNs that could disappear.

Art Blocks just solved this. They built the Art Blocks Dependency Registry and On-Chain Generator, and now 90% of their projects are truly fully onchain. This isn't just an improvement, it's a fundamental shift in how we think about digital art permanency.

The Composability Problem

The problem with onchain generative art was always composability. You could store your script onchain, but what about the libraries it depends on?

// This script is onchain, but...
function setup() {
    createCanvas(800, 600);
    background(220);
}

function draw() {
    // ... but p5.js is external
    ellipse(mouseX, mouseY, 50, 50);
}

If p5.js disappears from the CDN, your onchain script becomes useless. You own the code, but you can't run it. This was the fundamental flaw in most "onchain" art projects.

The Art Blocks Solution

Art Blocks solved this with two key innovations:

1. The Dependency Registry

Instead of relying on external CDNs, Art Blocks stores libraries directly onchain. Here are the key dependencies they've made available:

Core Graphics Libraries:

  • p5.js: The main creative coding library for generative art
  • three.js: 3D graphics library for WebGL-based art
  • Paper.js: Vector graphics scripting framework
  • D3.js: Data visualization library for data-driven art

Utility Libraries:

  • Lodash: Utility functions for data manipulation
  • Moment.js: Date and time manipulation
  • Crypto-js: Cryptographic functions for deterministic randomness

Specialized Art Libraries:

  • ml5.js: Machine learning library for AI-driven art
  • TensorFlow.js: Machine learning framework
  • OpenCV.js: Computer vision library
  • Fabric.js: Canvas library for interactive graphics

Key Technical Details:

  • Progressive Decentralization: Dependencies can be referenced via CDNs or stored fully on-chain
  • scripty.sol Integration: Uses the scripty.sol library to efficiently stitch large JavaScript tags together
  • Flexible Storage: Supports both on-chain and off-chain dependency management
  • Version Control: Each library version is immutable once stored on-chain
  • Gas Optimization: Large libraries can remain on CDN while core libraries are on-chain

Current Registry Status:

  • p5.js: Available on-chain for core generative art projects
  • three.js: On-chain for 3D graphics projects
  • Paper.js: On-chain for vector graphics projects
  • D3.js: Available for data visualization projects
  • Utility Libraries: Lodash, Moment.js, Crypto-js available on-chain
  • Specialized Libraries: ml5.js, TensorFlow.js available for AI-driven art
// Art Blocks Dependency Registry
contract DependencyRegistry {
    mapping(string => string) public dependencies;
    
    function storeDependency(string memory name, string memory version, string memory code) public {
        string memory key = string(abi.encodePacked(name, "@", version));
        dependencies[key] = code;
    }
    
    function getDependency(string memory name, string memory version) public view returns (string memory) {
        string memory key = string(abi.encodePacked(name, "@", version));
        return dependencies[key];
    }
}

How Artists Use These Libraries:

// Example: Using p5.js from the onchain registry
function setup() {
    createCanvas(800, 600);
    // p5.js functions work exactly as before
    // but the library is loaded from onchain storage
}

function draw() {
    background(220);
    // All p5.js functionality available
    ellipse(mouseX, mouseY, 50, 50);
}

// Example: Using three.js for 3D art
import * as THREE from 'onchain://dependency-registry/three@r150';

function create3DScene() {
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, 800/600, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer();
    // 3D graphics rendered from onchain code
}

// Example: Using ml5.js for AI-driven art
import * as ml5 from 'onchain://dependency-registry/ml5@0.19.0';

function setup() {
    // AI model loaded from onchain storage
    const classifier = ml5.imageClassifier('MobileNet', modelReady);
}

2. The On-Chain Generator

The On-Chain Generator assembles everything into complete HTML:

// Art Blocks On-Chain Generator Contract
contract ArtBlocksGenerator {
    // Contract: 0x953D288708bB771F969FCfD9BA0819eF506Ac718
    
    function getTokenHtml(
        address coreContract, 
        uint256 tokenId
    ) public view returns (string memory) {
        // Assembles complete HTML from:
        // - Artist's generative script (onchain)
        // - Dependencies from Dependency Registry (onchain)
        // - Token-specific data (onchain)
        // Returns HTML that renders the art in any browser
    }
    
    function getTokenHtmlBase64EncodedDataUri(
        address coreContract, 
        uint256 tokenId
    ) public view returns (string memory) {
        // Returns base64-encoded data URI
        // Can be pasted directly in browser address bar
    }
}

Real Example: Chromie Squiggle #0

To see this in action, let's view the first Art Blocks piece:

  1. Generator Contract: 0x953D288708bB771F969FCfD9BA0819eF506Ac718
  2. Project Contract: 0x059edd72cd353df5106d2b9cc5ab83a52287ac3a (Chromie Squiggle)
  3. Token ID: 0

Call getTokenHtmlBase64EncodedDataUri(0x059edd72cd353df5106d2b9cc5ab83a52287ac3a, 0) and paste the result in your browser, the art renders completely from blockchain data.

No external servers. No CDNs. No IPFS. Just pure blockchain data.

The Composability Revolution

This changes everything. Now you can build truly composable onchain art:

1. Shared Libraries

// Multiple projects can use the same onchain p5.js
// No duplication, no external dependencies
import { p5 } from "onchain://dependency-registry/p5@1.0.0";

2. Modular Art

// Art pieces can reference other onchain components
import { colorPalette } from "onchain://project/0x123.../palette";
import { geometry } from "onchain://project/0x456.../shapes";

3. Version Control

// Dependencies are versioned and immutable
import { p5 } from "onchain://dependency-registry/p5@1.0.0";
// This version will always be available

Current Status (2024)

  • 90% of Art Blocks projects are fully onchain
  • 10% use Engine Flex (IPFS/Arweave for larger assets)
  • All dependencies available through onchain registry
  • Complete independence from external servers

The Technical Implementation

The On-Chain Generator works by:

  1. Retrieving the artist script from the project contract
  2. Fetching dependencies from the Dependency Registry
  3. Assembling HTML with embedded JavaScript
  4. Returning complete renderable code

Library Storage Details:

// How libraries are stored in the registry
contract DependencyRegistry {
    // Libraries can be stored as complete JavaScript files on-chain
    // Or referenced via CDN URLs for progressive decentralization
    // Uses scripty.sol for efficient large JavaScript tag assembly
    
    function getDependency(string memory name, string memory version) public view returns (string memory) {
        // Returns either on-chain JavaScript code or CDN URL
        // Supports both fully on-chain and hybrid approaches
    }
    
    // Libraries are versioned and immutable when stored on-chain
    // CDN references provide flexibility for larger libraries
    // This ensures deterministic art generation while managing gas costs
}

Library Loading Process with scripty.sol:

// The On-Chain Generator uses scripty.sol for efficient assembly
contract ArtBlocksGenerator {
    using ScriptyBuilder for IScriptyBuilder;
    
    function getTokenHtml(address coreContract, uint256 tokenId) public view returns (string memory) {
        // 1. Retrieve artist script from project contract
        string memory artistScript = getArtistScript(coreContract);
        
        // 2. Get dependencies from registry (on-chain or CDN)
        string memory p5js = getDependency("p5", "1.0.0");
        string memory threejs = getDependency("three", "r150");
        
        // 3. Use scripty.sol to efficiently stitch JavaScript tags
        IScriptyBuilder htmlBuilder = IScriptyBuilder(scriptyStorage);
        
        htmlBuilder.addScriptTag("p5.js", p5js);
        htmlBuilder.addScriptTag("three.js", threejs);
        htmlBuilder.addScriptTag("artist-script", artistScript);
        
        // 4. Assemble complete HTML with embedded JavaScript
        return htmlBuilder.getHTML();
    }
}

Generated HTML Structure:

<!DOCTYPE html>
<html>
<head>
    <script>
        // p5.js library (on-chain or CDN reference)
        // three.js library (on-chain or CDN reference)
        // Artist's generative script
        // Token-specific data and initialization
    </script>
</head>
<body>
    <canvas id="artwork"></canvas>
</body>
</html>

Progressive Decentralization Approach:

Art Blocks uses a flexible approach that allows for gradual migration to full on-chain storage:

  1. CDN References: Libraries can be referenced via CDN URLs initially
  2. On-Chain Migration: Libraries can be moved to on-chain storage over time
  3. Hybrid Support: Projects can use both CDN and on-chain dependencies
  4. Gas Optimization: Larger libraries can remain on CDN while core libraries go on-chain

This approach balances permanency with practical considerations like gas costs and storage limitations.

New ideas around

This opens up possibilities we couldn't imagine before:

1. Collaborative Art

// Artists can build on each other's onchain components
import { basePattern } from "onchain://artist/0x123.../pattern";
import { colorSystem } from "onchain://artist/0x456.../colors";

2. Evolving Art

// Art can reference other onchain data
import { marketData } from "onchain://oracle/price-feed";
// Art changes based on real-world data

3. Interactive Art

// Art can interact with other onchain systems
import { userProfile } from "onchain://identity/user";
// Personalized art based on onchain identity

The dependency problem is solved. The permanency problem is solved. The composability problem is solved.

Let's see creative outcomes for this, eager.


This post builds on my earlier analysis from 2021: Onchain vs Offchain NFTs: Why Permanency Matters. The technology has evolved significantly since then.

Links and Resources