@nexart/codemode-sdk
v1.9.0
Published
NexArt Code Mode SDK - Deterministic, reproducible, verifiable generative art runtime. Agent-first design for AI coding assistants.
Maintainers
Readme
@nexart/codemode-sdk
Version: 1.9.0 (Protocol v1.2.0)
A deterministic execution runtime for reproducible, verifiable computation.
Which API Should I Use?
Decision table for choosing the right entrypoint:
| Your Goal | Use This | Import Path |
|-----------|----------|-------------|
| Deterministic random/noise in any environment | createRuntime() ✅ DEFAULT | @nexart/codemode-sdk |
| AI agent integration | createRuntime() ✅ DEFAULT | @nexart/codemode-sdk |
| Browser/React/Vite app | createRuntime() ✅ DEFAULT | @nexart/codemode-sdk |
| Server-side image rendering | executeCodeMode() | @nexart/codemode-sdk/node |
| Full p5.js-style canvas execution | executeCodeMode() | @nexart/codemode-sdk/node |
createRuntime() is the default and recommended API:
- ✅ Works in browser and Node.js
- ✅ No canvas dependency
- ✅ Agent-first design
- ✅ Strict mode enforcement
- ✅ Lightweight
executeCodeMode() is the legacy / Node-only API:
- Requires Node.js with
canvaspackage - Full p5.js-style execution environment
- Returns rendered PNG/MP4
- Use only when you need actual image/video output
Quickstart: CLI Examples
The SDK includes ready-to-run example sketches. Use the @nexart/cli to render them via the canonical renderer.
Setup
# Set up authentication for remote rendering
export NEXART_RENDERER_ENDPOINT=https://nexart-canonical-renderer-production.up.railway.app
export NEXART_API_KEY=nx_live_your_key_hereRun Examples
# Run the main example sketch
npx @nexart/cli run ./examples/sketch.js --seed 12345 --include-code --out ./out.png
# Verify the output is deterministic
npx @nexart/cli verify ./out.snapshot.json
# Output: [nexart] Result: PASSExample Sketches
| File | Description |
|------|-------------|
| examples/sketch.js | Main example — VAR controls + random palette, protocol-safe |
| examples/sketch-minimal.js | Simple shapes, no randomness — identical every run |
| examples/sketch-vars.js | Uses VAR + random() — demonstrates determinism |
Canonical Size
The canonical renderer enforces a fixed canvas size of 1950x2400. Do not pass custom --width or --height to the canonical endpoint — the size is enforced server-side for consistent, verifiable output.
What This SDK Does
This SDK provides a deterministic runtime layer for executing code that must produce identical output given identical inputs — across environments, over time, and under verification.
Core guarantees:
- Same
seed+vars+code→ identical output (always) - Cross-environment stability (browser, Node.js, CI pipelines)
- Strict mode blocks non-deterministic APIs (
Math.random,Date.now, etc.) - Canonical state snapshots for replay and verification
- Stable digest for integrity verification
Who This Is For
Use this SDK if determinism is non-negotiable:
- On-chain generative art — NFTs, archival renders, mint verification
- Procedural games — Open-world generation, replay systems, save states
- Simulations — Physics, agent-based models, reproducible experiments
- Finance research — Backtesting, Monte Carlo, reproducible analysis
- Education labs — Repeatable demonstrations, grading consistency
Skip this SDK if you're building:
- CRUD apps
- Dashboards
- E-commerce
- Typical web applications without reproducibility requirements
For most applications, seeded randomness is unnecessary complexity.
For AI Coding Agents (Replit / Lovable / Claude Code)
Always start with createRuntime() — it is the default and recommended API.
Quick Rules for AI Agents
- Always use
createRuntime()— NOTexecuteCodeMode() - Never use
Math.random()orDate.now()— useruntime.random()instead - Always use
strict: true— unless you explicitly know why you aren't - See
examples/agent-quickstart.ts— copy-paste ready reference
Minimal Example
import { createRuntime } from "@nexart/codemode-sdk";
const runtime = createRuntime({
seed: "my-artwork-42",
vars: [50, 75, 25],
strict: true, // ALWAYS use strict: true — throws on non-deterministic APIs
mode: "static"
});
// Deterministic APIs (use these, not Math.random!)
const value = runtime.random(); // [0, 1)
const intVal = runtime.randomInt(0, 10); // integer in range
const n = runtime.noise(0.5, 0.5); // Perlin noise
// Execute with strict enforcement
const result = runtime.run(() => {
// Your deterministic code here
return runtime.random() * 100;
});
// Verification
console.log(runtime.digest()); // Stable hash for verification
console.log(runtime.getState()); // Canonical state snapshot for replayStrict Mode Explained
Strict mode protects determinism by intercepting non-deterministic APIs during runtime.run():
runtime.run(() => {
Math.random(); // Throws: NEXART_STRICT: Non-deterministic API used: Math.random. Use runtime.random() instead.
Date.now(); // Throws: NEXART_STRICT: Non-deterministic API used: Date.now. Pass time as an input or use deterministic counters.
});Why strict mode exists:
- Determinism is the core guarantee — same inputs must always produce same outputs
- AI agents often default to
Math.random()before reading documentation - Strict mode catches these mistakes immediately with actionable error messages
- Interception is scoped to
runtime.run()— it does NOT globally mutate your application - Globals are restored after execution
When to use strict: false:
- Almost never. Only if you're intentionally mixing deterministic and non-deterministic code.
- If you're not sure, use
strict: true.
Where This Fits
┌─────────────────────────────────────────────────────────┐
│ Your Application │
│ (React, Canvas, Three.js, game engine, simulation) │
└────────────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ @nexart/codemode-sdk │
│ Deterministic runtime layer │
│ - Seeded PRNG (Mulberry32) │
│ - Seeded noise (Perlin) │
│ - Strict mode enforcement │
│ - State snapshots + digest │
└────────────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Output │
│ - Deterministic result │
│ - Verification digest │
│ - Replay state │
└─────────────────────────────────────────────────────────┘The SDK sits between your UI/framework and your output. It does not render, does not manage state, does not touch the DOM. It provides deterministic primitives.
Why Not Roll Your Own?
What's easy:
- Seeded PRNG (dozens of implementations exist)
- Noise libraries (simplex, Perlin, available everywhere)
What's hard:
- Cross-environment stability — Same seed producing same sequence across browser versions, Node.js versions, bundlers, and platforms
- Strict enforcement — Actually blocking
Math.random()andDate.now()during execution, with actionable error messages - Replay and verification — Canonical state snapshots that can reconstruct execution
- Long-term drift resistance — Guaranteeing identical output years later, not just today
If you need a quick seeded random, use any PRNG. If you need guaranteed reproducibility across time, environments, and verification systems — that's what this SDK provides.
Determinism Contract
✅ Guaranteed:
- Same
sdkVersion+seed+vars→ identical output - Cross-environment stable digest (browser, Node.js, CI)
- Seeded PRNG via
runtime.random()(Mulberry32) - Seeded noise via
runtime.noise()(Perlin)
❌ Forbidden (blocked in strict mode):
Math.random()— useruntime.random()insteadDate.now()— pass time as input or use frame countersperformance.now()— use deterministic timing- External IO during deterministic runs
Feature Comparison
| Feature | Plain PRNG | This SDK |
|---------|-----------|----------|
| Seeded random | ✅ | ✅ |
| Seeded noise | ❌ (separate lib) | ✅ built-in |
| Strict mode (blocks entropy) | ❌ | ✅ |
| Canonical state snapshot | ❌ | ✅ getState() |
| Cross-env stable digest | ❌ | ✅ digest() |
| VAR protocol (0-100 inputs) | ❌ | ✅ |
| Replay/verification | Manual | Built-in |
| Error messages for agents | ❌ | ✅ actionable |
Environment Imports
| Environment | Import Path |
|-------------|-------------|
| Browser / Vite / Next.js / React | import { createRuntime } from "@nexart/codemode-sdk" |
| Node.js (general use) | import { createRuntime } from "@nexart/codemode-sdk" |
| Node.js server rendering (canvas) | import { executeCodeMode } from "@nexart/codemode-sdk/node" |
The default import is browser-safe. Node-only features require explicit /node import.
Used By
- NexArt — Generative art platform
- ByX — Curated collections
- Frontierra — External builder integration
These are examples — the SDK is designed for any system requiring deterministic execution.
Protocol Stability
| Property | Value | |----------|-------| | Protocol Version | v1.2.0 | | Status | STABLE | | SDK Version | 1.8.4 |
Core protocol surface is frozen. Breaking changes require v2.0.0.
The following are locked in v1.x:
- Execution model (Static and Loop modes)
- VAR[0..9] specification
- Determinism guarantee
- Time semantics (t, frameCount, time, tGlobal, totalFrames)
- Random and noise behavior
- Forbidden patterns list
Licensing
Free for personal projects, experiments, research, and open-source.
Commercial production deployments require a license.
See COMMERCIAL.md for details.
Installation
npm install @nexart/codemode-sdkRuntime API
createRuntime(options)
Create a deterministic runtime instance.
import { createRuntime } from "@nexart/codemode-sdk";
const runtime = createRuntime({
seed: "my-seed",
vars: [50, 75],
strict: true,
mode: "static",
metadata: { artist: "demo" }
});
runtime.random(); // Deterministic PRNG
runtime.randomInt(0, 100); // Deterministic integer
runtime.noise(x, y, z); // Deterministic Perlin noise
runtime.digest(); // Stable hash for verification
runtime.getState(); // Canonical state snapshot
runtime.run(() => { ... }); // Execute with strict enforcementStrict Mode
When strict: true, the runtime intercepts non-deterministic APIs during run():
runtime.run(() => {
Math.random(); // Throws: NEXART_STRICT: Non-deterministic API used
});Strict mode:
- Only applies during
runtime.run()— non-invasive - Does NOT globally mutate your application
- Provides actionable error messages
Browser Usage
For Vite, React, Next.js, or any browser environment:
import {
createRuntime,
runLoopMode,
cancelLoopMode,
createP5Runtime,
validateCodeModeSource,
} from '@nexart/codemode-sdk';What's included:
- Runtime API (createRuntime)
- P5 runtime (createP5Runtime, injectTimeVariables, injectProtocolVariables)
- Loop engine (runLoopMode, cancelLoopMode)
- Execution sandbox (FORBIDDEN_APIS, createSafeMath)
- Validation (validateCodeModeSource)
What's NOT included (Node.js only):
executeCodeMode— Requires Node.js canvasrunStaticMode— Requires Node.js canvas
Node.js Usage
For server-side rendering, oracles, or CLI tools:
import {
executeCodeMode,
runStaticMode,
runLoopMode,
validateCodeModeSource,
} from '@nexart/codemode-sdk/node';Requirements:
- Node.js 18+
canvaspackage for static mode
Canonical Execution API
executeCodeMode(input): Promise<Result>
For systems requiring p5.js-style execution with full protocol metadata:
import { executeCodeMode } from '@nexart/codemode-sdk/node';
const result = await executeCodeMode({
source: `
function setup() {
background(255);
fill(0);
let size = map(VAR[0], 0, 100, 50, 200);
ellipse(width/2, height/2, size);
}
`,
width: 1950,
height: 2400,
seed: 12345,
vars: [50, 75, 0, 0, 0, 0, 0, 0, 0, 0],
mode: 'static'
});
console.log(result.metadata.deterministic); // true
console.log(result.image); // PNG BlobExecution Rules
Static Mode
setup()executes oncedraw()is NOT executed- Canvas captured as PNG
- Time variables are 0
Loop Mode
setup()executes oncedraw()executes per frame- Canvas cleared before each
draw()
Time Variables:
| Variable | Type | Description |
|----------|------|-------------|
| frameCount | int | Current frame (0, 1, 2, ...) |
| t | float | Normalized time [0.0, 1.0) |
| time | float | Elapsed seconds |
| tGlobal | float | Alias for t |
| totalFrames | int | Total frames in loop |
Forbidden Patterns
The following are rejected with [Code Mode Protocol Error]:
| Pattern | Reason |
|---------|--------|
| Math.random() | Use seeded random() |
| Date.now() | Time-based entropy |
| new Date() | Time-based entropy |
| performance.now() | Timing entropy |
| crypto.getRandomValues() | Crypto randomness |
| fetch() | External IO |
| setTimeout | Async timing |
| setInterval | Async timing |
| requestAnimationFrame | Async timing |
| document.* | DOM access |
| window.* | DOM access |
| import | External imports |
| require() | External imports |
Attestation & Verification (v1.9.0)
Verification Reason Codes
Every verification function returns a CodeVerificationResult with a stable, machine-readable code:
import { CodeVerifyCode } from '@nexart/codemode-sdk';
// Stable string codes — safe to switch on, persist to storage, or compare:
// CodeVerifyCode.OK
// CodeVerifyCode.CERTIFICATE_HASH_MISMATCH
// CodeVerifyCode.SNAPSHOT_HASH_MISMATCH
// CodeVerifyCode.RENDER_HASH_MISMATCH
// CodeVerifyCode.INVALID_SHA256_FORMAT
// CodeVerifyCode.CANONICALIZATION_ERROR
// CodeVerifyCode.SCHEMA_ERROR
// CodeVerifyCode.NODE_RECEIPT_MISSING
// CodeVerifyCode.NODE_RECEIPT_KEY_NOT_FOUND
// CodeVerifyCode.NODE_RECEIPT_INVALID_SIGNATURE
// CodeVerifyCode.NODE_RECEIPT_KEY_FORMAT_UNSUPPORTED
// CodeVerifyCode.UNKNOWN_ERRORSigned Node Receipt Verification (offline)
Verify that a Code Mode snapshot bundle was attested by an authorised NexArt attestation node — entirely offline, browser and Node.js compatible:
import { verifyBundleAttestation } from '@nexart/codemode-sdk';
const res = await verifyBundleAttestation(bundle, { nodeUrl: 'https://node.nexart.dev' });
console.log(res.ok, res.code);
// true "OK"
// false "CERTIFICATE_HASH_MISMATCH" (receipt doesn't match bundle)
// false "NODE_RECEIPT_INVALID_SIGNATURE" (tampered receipt)verifyBundleAttestation performs these steps automatically:
- Extracts the signed receipt and signature from the bundle (top-level or nested layout).
- Cross-checks
receipt.certificateHash === bundle.certificateHashto prevent receipt-swapping attacks. - Fetches the node's public keys from
/.well-known/nexart-node.json. - Selects the appropriate key (by
kid,activeKid, or first available). - Verifies the Ed25519 signature over the canonical JSON bytes of the receipt.
Node Keys Endpoint
Public keys are discovered automatically from:
GET {nodeUrl}/.well-known/nexart-node.jsonYou can also fetch or inspect keys directly:
import { fetchNodeKeys, selectNodeKey } from '@nexart/codemode-sdk';
const doc = await fetchNodeKeys('https://node.nexart.dev');
const { key } = selectNodeKey(doc, 'kid-optional');Receipt Extraction Helpers
Inspect bundles without performing full verification:
import { getAttestationReceipt, hasAttestation } from '@nexart/codemode-sdk';
if (hasAttestation(bundle)) {
const receipt = getAttestationReceipt(bundle);
console.log(receipt?.attestationId, receipt?.nodeId);
}Both helpers recognise:
- Layout A —
bundle.receipt+bundle.signature(signed envelope) - Layout B —
bundle.attestation.receipt+bundle.attestation.signature(nested envelope) - Layout C — legacy flat fields (
bundle.attestationId,bundle.nodeRuntimeHash, …)
Examples
npm run example:agent # Agent quickstart (RECOMMENDED for AI agents)
npm run example:basic # Basic usage
npm run example:verify # Determinism verificationChangelog
See CHANGELOG.md for version history.
License
MIT License — Free for all use, including commercial.
NexArt monetizes optional hosted services (attestation, verification, compliance), not the SDK.
See Core vs Edges for details on what's free vs paid.
About
This SDK is a reference implementation of a deterministic execution protocol designed for replay, verification, and long-term stability.
It prioritizes correctness and reproducibility over features.
