Seeded Randomness for Generative Art
Turn stable content identities into varied procedural graphics with a documented PRNG, namespaced decisions, grammar versions, and snapshot hashes.
Seeded randomness lets generative artwork vary across identities while remaining stable across builds, URLs, and revisions. This guide turns a seed into an explicit visual contract so a poster can be regenerated, tested, shared, and intentionally evolved instead of drifting whenever code runs.
The intended reader builds procedural graphics in JavaScript or another deterministic pipeline. You will leave with a small PRNG, canonical seed rules, snapshot hashes, and a mutation method that separates authored change from accidental entropy.
The operating vocabulary connects reproducible generative art, deterministic JavaScript PRNG, procedural design, and random seed as parts of one identity system.
- Canonical seed
- PRNG stream
- Design grammar
- Snapshot hash
Seeded randomness begins with identity
seeded randomness begins with choosing exactly which stable public value names an artwork and how that value is converted into canonical bytes. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision. The PCG paper describes the permutation-based generator family and its separation of state transition from output transformation.
Work through four explicit moves:
- Select a slug, token, or explicit seed
- Normalize case and Unicode deliberately
- Add a grammar version outside the seed
- Store the exact canonical string
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is seeding from the current time or array position. Its consequence is the same artwork cannot be regenerated after sorting, deployment, or cache loss.
Mitigate it with a content-derived canonical identity with documented normalization. The release receipt is seed text, grammar version, encoding, and initial state hash. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Choose a specified deterministic PRNG
A useful seeded randomness decision depends on using a small algorithm with documented integer operations and state instead of depending on implementation-defined Math.random output. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision. The ECMAScript Math.random specification leaves the random-number algorithm implementation-defined, which is why Math.random cannot provide a portable seeded visual contract.
Work through four explicit moves:
- Select a generator with adequate period
- Implement unsigned arithmetic explicitly
- Test known input-output vectors
- Expose state only through named helpers
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is calling Math.random inside the composition. Its consequence is browsers, runtimes, and repeated builds can produce unrelated results.
Mitigate it with one injected PRNG and a lintable ban on ambient randomness. The release receipt is known-answer tests for the first values from fixed seeds. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Design a stable consumption grammar
The worked seeded randomness fixture makes mapping random draws to named decisions such as palette, anchor, angle, density, and texture in a fixed sequence. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Name each design decision
- Consume a fixed count per decision
- Derive independent streams for variable loops
- Record ranges and transforms beside tokens
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is adding one random call near the beginning. Its consequence is every downstream choice changes although the new feature is local.
Mitigate it with namespaced substreams derived from seed and decision key. The release receipt is a parameter object whose keys and values reconstruct the composition. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
| Signal | Decision | Proof |
|---|---|---|
| Same seed + v1 | Identical | hash a19f…a19f |
| New seed + v1 | Varied identity | hash 74bc |
| Same seed + v2 | Authored mutation | versioned hash d802 |
Reproduce the snapshot hash
seeded randomness needs an explicit rule for serializing semantic parameters in stable key order and hashing them before rasterization introduces platform-dependent pixels. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Round floating values to declared precision
- Sort object keys recursively
- Exclude transient timestamps and paths
- Hash canonical UTF-8 JSON
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is hashing a PNG rendered by different graphics stacks. Its consequence is font and antialiasing differences look like composition drift.
Mitigate it with a semantic hash plus optional platform-specific pixel snapshots. The release receipt is a test proving same seed and version yield the same canonical hash. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Runnable artifact. Save this as seeded-randomness-generative-art.test.mjs and run node --test seeded-randomness-generative-art.test.mjs. Expected result: PASS: seed and grammar reproduce the same composition. The checked-in copy lives with this batch's evidence.
import assert from "node:assert/strict";
import test from "node:test";
function mulberry32(seed) {
return () => { seed |= 0; seed = seed + 0x6d2b79f5 | 0; let t = Math.imul(seed ^ seed >>> 15, 1 | seed); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; };
}
test("replays named composition decisions", () => {
const draw = () => { const random = mulberry32(42); return [random(), random(), random()].map((n) => n.toFixed(6)); };
assert.deepEqual(draw(), draw());
console.log("PASS: seed and grammar reproduce the same composition");
});
Turn constraints into art direction
In production, seeded randomness turns on using bounded palettes, spatial rhythms, collision rules, and focal hierarchies so random values express a recognizable authored system. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Define a small palette relationship
- Reserve a focal region and quiet region
- Quantize sizes and angles to rhythms
- Reject collisions with deterministic retries
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is mapping every random number directly to a visual property. Its consequence is variation becomes undirected noise rather than a coherent identity.
Mitigate it with a grammar that narrows possibility while preserving surprise. The release receipt is a contact sheet showing diverse seeds with consistent hierarchy. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Separate seed changes from grammar changes
Safe seeded randomness requires treating a new seed as a new identity and a new grammar version as an intentional redesign of every affected identity. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Keep seed stable for content identity
- Increment version for authored system changes
- Render old and new contact sheets
- Record migration and cache policy
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is silently changing code behind existing artwork. Its consequence is bookmarks, social cards, and historical exports no longer match.
Mitigate it with explicit grammar versions and preserved legacy rendering. The release receipt is before-and-after hashes with a written reason for every changed parameter. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
- NormalizeNormalize
Convert the public identifier into canonical bytes.
- InitializeInitialize
Hash bytes into the documented PRNG state.
- ComposeCompose
Consume named random decisions in stable order.
- ReceiptReceipt
Serialize parameters and store a snapshot hash.
Test distribution and accessibility
A seeded randomness rollout should preserve checking deterministic results in responsive layouts, social crops, print output, reduced motion, high contrast, and text-equivalent contexts. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Render extreme seeds at each target size
- Keep meaningful text outside random placement
- Provide authored alt and caption text
- Verify crop-safe focal regions
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is letting the generated image carry essential prose. Its consequence is assistive technology and social crops lose the message.
Mitigate it with semantic HTML meaning and decorative generated layers. The release receipt is viewport captures and accessible names tied to the same identity. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Publish the generative recipe
The evidence for seeded randomness is strongest when keeping seed, grammar version, PRNG name, parameters, source revision, and snapshot hash together as the provenance of the visual. This is the narrow boundary for this section; everything outside it belongs in a separate capacity, policy, or product decision.
Work through four explicit moves:
- Expose the seed in a URL or manifest
- Name the algorithm and version
- Store semantic parameters
- Retain a deterministic regeneration command
In a working review, I would put the first move beside the input fixture, use the second to expose the decision boundary, and make the third observable before polishing the interface. The fourth move is the release check. This order matters because a convincing happy path can still conceal incompatible state, unfair scheduling, inaccessible fallback, or ownership ambiguity. Keeping each move named also lets another engineer reproduce the result without inheriting private context.
The named failure mode is saving only the final raster. Its consequence is the visual cannot be audited, adapted, or intentionally reproduced.
Mitigate it with a compact machine-readable recipe beside the exported asset. The release receipt is one command that rebuilds the same parameter hash from the public identity. Those fields connect the implementation to the article's single question and make a later update comparable instead of anecdotal.
Put the decision into practice
Use seeded randomness as a visual identity contract: canonicalize the seed, choose a specified PRNG, isolate named decision streams, version the grammar, and hash semantic parameters. Determinism then supports creative variation without turning every build into an accidental redesign.
Start with the known-answer artifact, add five named composition decisions, and render a contact sheet of extreme seeds. Keep the recipe beside each export so future design changes can be compared and migrated intentionally rather than confused with random drift.
The method connects to four existing Journal notes: WebGPU generative art, SVG filter textures, React data-state animation, Content Credentials for AI artwork. Each link covers an adjacent boundary while this article stays focused on one outcome. Keep the fixture, visual evidence, command output, and release receipt together so the next review can test the claim against the same starting conditions.