-
Notifications
You must be signed in to change notification settings - Fork 0
genart plugin api
Custom generative art algorithms can be installed at runtime in the Gen Art tab. A plugin is a single ES module file that exports one object conforming to the contract described below.
export default {
id: 'my-dots',
label: 'Random Dots',
params: [
{ id: 'count', label: 'Count', type: 'range', min: 10, max: 500, step: 10, default: 100 },
{ id: 'seed', label: 'Seed', type: 'number', min: 0, max: 99999, step: 1, default: 42 },
],
generate({ count, seed }) {
// Seeded PRNG
let s = seed | 0;
const rand = () => { s ^= s << 13; s ^= s >> 17; s ^= s << 5; return (s >>> 0) / 0xFFFFFFFF; };
// Return one short path per dot (a 4-point cross)
const paths = [];
for (let i = 0; i < count; i++) {
const x = rand() * 2 - 1; // NDC: [-1, +1]
const y = rand() * 2 - 1;
const r = 0.015;
paths.push([{ nx: x - r, ny: y }, { nx: x + r, ny: y }]); // horizontal bar
paths.push([{ nx: x, ny: y - r }, { nx: x, ny: y + r }]); // vertical bar
}
return paths;
},
};| Field | Type | Description |
|---|---|---|
id |
string |
Unique algorithm identifier. Must not conflict with built-in IDs. |
label |
string |
Display name shown in the algorithm dropdown. |
params |
GenArtParam[] |
Array of parameter descriptors (may be empty []). |
generate(params) |
function |
Produces the plot paths. See below. |
Receives a plain object whose keys are the id values of your params entries and whose values are the current user-selected values. Returns an array of polyline paths, where each path is an array of points in Normalized Device Coordinates (NDC):
-
x axis:
nxin[-1, +1];−1= left edge,+1= right edge -
y axis:
nyin[-1, +1];−1= bottom edge,+1= top edge (Y-up) - The app clips and maps NDC to the paper's plot area on export.
Each sub-array represents one continuous pen stroke. The pen lifts between paths.
// Two separate strokes
return [
[{ nx: -0.9, ny: -0.9 }, { nx: 0.9, ny: -0.9 }], // bottom line
[{ nx: -0.9, ny: 0.9 }, { nx: 0.9, ny: 0.9 }], // top line
];If exported, the app renders the returned paths as a dim dashed blue overlay before the main paths. Use this to visualise construction geometry (circles, axes, bounding boxes) that helps the user understand the current parameter state.
- Rendered on every param change (not just after Generate is pressed).
- Uses the same NDC coordinate system as
generate(). - See
src/lib/genart/spirograph.jsfor a full example (outer/inner circles + pen arm).
export function guide({ R, r }) {
// Draw a simple bounding circle
const N = 120;
return [Array.from({ length: N + 1 }, (_, i) => {
const t = (2 * Math.PI * i) / N;
return { nx: Math.cos(t) * 0.9, ny: Math.sin(t) * 0.9 };
})];
}A plain object mapping preset names to partial param values. When the user selects a preset from a select-type param, all matching param IDs in presets[value] are automatically populated in the UI.
export const presets = {
tight: { count: 200, spacing: 0.02 },
sparse: { count: 30, spacing: 0.15 },
};Pair this with a select param whose option values match the preset keys:
{ id: 'preset', label: 'Preset', type: 'select', default: 'tight',
options: [{ value: 'tight', label: 'Tight' }, { value: 'sparse', label: 'Sparse' }] }All four types are validated on install. Missing or mistyped fields cause an install error.
{ id: 'count', label: 'Count', type: 'range', min: 5, max: 200, step: 5, default: 40 }| Field | Required | Description |
|---|---|---|
id |
✅ | Unique key within this plugin |
label |
✅ | Sidebar display label |
type |
✅ | 'range' |
min |
✅ | Minimum value (inclusive) |
max |
✅ | Maximum value (inclusive) |
step |
✅ | Increment unit. Use decimals (e.g. 0.01) for float params |
default |
✅ | Initial value |
Same fields as range. Renders as a text input; user can type an exact value.
{ id: 'seed', label: 'Seed', type: 'number', min: 0, max: 99999, step: 1, default: 42 }{
id: 'mode', label: 'Mode', type: 'select', default: 'hex',
options: [
{ value: 'hex', label: 'Hexagonal' },
{ value: 'square', label: 'Square' },
{ value: 'random', label: 'Random' },
]
}| Field | Required | Description |
|---|---|---|
options |
✅ | Non-empty array of { value, label } objects |
{ id: 'fill', label: 'Fill cells', type: 'toggle', default: false }The value passed to generate() is a boolean (true/false).
ny = +1 (top)
│
nx = -1 ──┼── nx = +1
│
ny = -1 (bottom)
- Origin
(0, 0)is the centre of the canvas/paper. -
(±1, ±1)are the corners of the NDC square; the app inscribes the plot area inside these coordinates with 10 mm margins. - Y is up (unlike screen pixels where Y increases downward).
The export pipeline automatically deduplicates shared segments before sorting, so you don't need to manually deduplicate shared edges (e.g. adjacent Voronoi cell walls). However, deduplication works at the segment level (A→B and B→A treated as the same). If your algorithm produces many overlapping segments, prefer deduplicating before returning to avoid the O(n²) scan.
- Open the Gen Art tab → Plugins panel.
- Paste your ES module source into the text area (or click Load file).
- Click Install — the loader evaluates the module via a Blob URL, validates the contract, and adds it to the algorithm dropdown.
- The plugin is persisted in
localStorageand restored on page reload.
To uninstall: click the × next to the plugin name in the Plugins panel.
Plugin code executes in the main app context with full origin privileges (localStorage, network, DOM). This is intentional for a local-only developer tool where the user installs their own code. Never install plugin code from untrusted sources.
-
examples/voronoi-cells.genart.js— Voronoi cells with Lloyd relaxation and Sutherland-Hodgman clipping.