modfield
v1.2.0
Published
A simple JavaScript library for creative coding that combines modulo operations, distance functions, and more to produce interesting, locally similar patterns.
Downloads
340
Readme
modfield.js
A standalone JavaScript library for creative coding that combines distance fields, modulators, and aggregators to produce interesting, locally similar patterns. Originally developed for p5.js artworks, it now works as a pure JavaScript library.
Explore the library features on GitHub pages.

Core Concepts
modfield.js combines three key components:
- Fields: Distance-based functions that calculate values at any point in 2D space
CircleField,LineField,SegmentField,RectField,OvalField,SineField,VortexField,RadialField,CrossField,CellularField
- Modulators: Transform distance values into interesting patterns
ConstantModulator,FlippingConstantModulator,FalloffModulator,BinaryModulator,DecayModulator,StepModulator,SquareWaveModulator, and more
- Aggregators: Combine values from multiple fields
aggregateWeightedAvg,aggregateWeightedMedian,aggregateWeightedRandom,aggregateAlternating,aggregateWeightedStdDev,aggregateSpread,aggregateMin,aggregateMax
The library applies these techniques in easy-to-implement ways, including:
- FieldGroups: Combines multiple fields with modulators and an aggregator
- FlipFieldGroups: Blends two FieldGroups based on a single threshold field
- Random generators: Create randomized modulators, fields, and field groups with configurable weights and ranges
Installation
npm install modfieldOr directly use the dist/ files:
dist/modfield.es.js- ES module builddist/modfield.umd.js- UMD build
Usage
Basic Example
import {
generateRandomFieldGroup
CircleField,
ConstantModulator,
FieldGroup,
aggregateWeightedAvg,
} from 'modfield';
// 1. Quick random field group generation
const random_group = generateRandomFieldGroup({w: width, h: height})
const value = random_group.mod([25, 75]);
const normalized = random_group.normalize(value);
console.log(normalized) // 0-1 normalized value
// 2. Manually building a field group
// Create fields with modulators
const mod1 = new ConstantModulator(20);
const field1 = new CircleField([100, 100], mod1);
field1.weight = 1;
const mod2 = new ConstantModulator(30);
const field2 = new CircleField([200, 150], mod2);
field2.weight = 1;
// Create a field group
const group = new FieldGroup([field1, field2], aggregateWeightedAvg);
// Sample at a point
const value2 = group.mod([150, 125]);
const normalized2 = group.normalize(value2);
console.log(normalized2); // 0-1 normalized value
With p5.js
import {
CircleField,
DecayModulator,
FieldGroup,
aggregateWeightedAvg
} from 'modfield';
function setup() {
createCanvas(800, 800);
const mod = new DecayModulator(50);
const field = new CircleField([400, 400], mod);
const group = new FieldGroup([field]);
}
function draw() {
loadPixels();
for (let i = 0; i < pixels.length; i += 4) {
const pixelIndex = i / 4;
const x = pixelIndex % width;
const y = floor(pixelIndex / width);
const value = group.mod([x, y]);
const normalized = group.normalize(value);
const c = floor(normalized * 255);
pixels[i] = c;
pixels[i + 1] = c;
pixels[i + 2] = c;
pixels[i + 3] = 255;
}
updatePixels();
}Random Generation
The package exports helpers for generating randomized fields and modulators.
import {
generateRandomFieldGroup,
} from 'modfield';
// Groups are the easiest way to get started using modfields; they use all types of components introduced in the library
// Generates a random group with 3-10 fields in the specified type set, with group values aggregated by the weighted median across fields
let group = generateRandomFieldGroup({
w: width, h: height // required
fieldCountRange: [3, 10],
fieldOptions: {
fieldTypes: ['circle', 'oval', 'sine'],
},
aggregatorOptions: {
aggregatorTypes: ['aggregateWeightedMedian'],
}
});
let samples = [];
for(let i = 0; i < 100; i += 1) {
let pos = [random()*width, random()*height];
samples.push({
pos: pos,
val: group.mod(pos);
});
}
// while modfield tries to return values on 0-1, there is chance values will be outside of that range. Groups will always track the minimum and maximum generated value, and the normalize() method will map a value from 0-1 between those extremes
samples = samples.map(s => s.val = group.normalize(s.val));
Available Classes and Functions
Fields
- CircleField: Distance expanding from a single point
- LineField: Distance from an infinite line
- SegmentField: Distance from a line segment
- RectField: Distance from a rectangle boundary
- OvalField: Distance from an oval/ellipse
- SineField: Distance from a sine wave
- VortexField: Spiral pattern field
- RadialField: Expanding radial band patterns, like sun rays
- CrossField: Distance from a cross shape
- CellularField: Voronoi-like cellular patterns
Modulators
- ConstantModulator: Saw-like repeating linear ramp
- FlippingConstantModulator: Triangle-like linear ramp that flips every interval
- FalloffModulator: Interval increases with distance
- BinaryModulator: On/off binary pattern
- StepModulator: Discrete stepped levels
- DecayModulator: Monotonic distance decay
- SquareWaveModulator: Hard on/off square wave with adjustable cycle width
Aggregators
- aggregateWeightedAvg: Weighted average
- aggregateWeightedMedian: Weighted median
- aggregateWeightedRandom: Weighted random selection
- aggregateAlternating: Alternating pattern based on odd/even weights
- aggregateWeightedStdDev: Standard deviation
- aggregateSpread: Spread/conflict measure
- aggregateMin: Minimum value
- aggregateMax: Maximum value
Random Generators
- generateRandomModulator: Creates a modulator using weighted or explicit type selection
- generateRandomField: Creates a field with a generated or supplied modulator
- generateRandomFields: Creates an array of random fields
- generateRandomFieldGroup: Creates a random FieldGroup with configurable fields and aggregator
- generateRandomFlipFieldGroup: Creates a random FieldFlipGroup with configurable branches and routing field
Building from Source
npm install
npm run buildOutput files:
dist/modfield.es.js- ES module builddist/modfield.umd.js- UMD build
Utility Functions
The library exports utility helpers for common workflow patterns:
TAU: mathematical constant for 2*PIradians(degrees): converts degrees to radiansdegrees(radians): converts radians to degreesdist(x1, y1, x2, y2): distance between two pointslerp(a, b, t): linear interpolation between two valuesconstrain(val, min, max): clamp a value between two limitsrandom(): random numbers, ranges, or array indices
License
MIT License (see LICENSE)
Acknowledgements
- Library created with help from Andrew Walpole's Vite library guide
- Website generates random colors for visualizations using Rampensau
