Overview
SWSinusoid is a SketchWave class for modeling sinusoidal (wave-like) behavior in p5.js applications. It implements the mathematical formula for a sinusoidal wave and provides convenient methods for creating smooth, periodic animations.
A = Amplitude (height of the wave from center)
B = Frequency (how quickly the wave oscillates)
C = Vertical shift (center line of the wave)
D = Phase shift (horizontal offset)
Period = (2π) / B (time for one complete cycle)
Common Use Cases
- "Breathing" effects (size pulsing)
- Smooth color cycling and transitions
- Position oscillation (bouncing, floating)
- Rotation animations
- Opacity/transparency fading
- Any periodic, smooth animation
Constructor
let wave = new SWSinusoid(A = 1, B = 1, C = 0, D = 0);
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
A |
number | 1 | Amplitude - controls the height/range of oscillation |
B |
number | 1 | Frequency - controls how fast the wave oscillates (larger = faster) |
C |
number | 0 | Vertical shift - moves the center line of the wave up or down |
D |
number | 0 | Phase shift - horizontal offset (where in the cycle to start) |
Examples
// Unit sinusoid: y = sin(x)
let unit = new SWSinusoid();
// Larger amplitude: y = 5 * sin(x)
let tall = new SWSinusoid(5);
// Faster oscillation: y = sin(2x)
let fast = new SWSinusoid(1, 2);
// Shifted up: y = sin(x) + 10
let raised = new SWSinusoid(1, 1, 10);
// Full custom: y = 3 * sin(0.5 * (x - 1)) + 5
let custom = new SWSinusoid(3, 0.5, 5, 1);
Properties
A
Type: number
Amplitude of the sinusoid. Controls the vertical range of oscillation from the center line. A larger amplitude creates a taller wave.
B
Type: number
Frequency coefficient. Controls the speed of oscillation. Larger values create faster oscillations with shorter periods.
C
Type: number
Vertical shift. Moves the center line of the wave up (positive) or down (negative).
D
Type: number
Phase shift (horizontal offset). Controls where in the cycle the wave starts.
period
Type: number (calculated)
The period of the sinusoid, calculated as (2π) / B. Represents the time for one complete cycle.
Methods
Configuration Methods
setPeriod(newPeriod)
Parameters: newPeriod (number) - desired period in seconds
Sets the period and automatically calculates the corresponding frequency (B). Useful when you know how long you want one complete cycle to take.
let wave = new SWSinusoid();
wave.setPeriod(2); // One cycle takes 2 seconds
// B is now π (approximately 3.14159)
adjustWaveUsingExtrema(minY, maxY)
Parameters: minY (number), maxY (number)
Automatically calculates and sets amplitude (A) and vertical shift (C) to make the wave oscillate between minY and maxY. Very useful for bounded animations.
let wave = new SWSinusoid();
wave.adjustWaveUsingExtrema(50, 150);
// Wave now oscillates between 50 and 150
// A = 50 (half the range)
// C = 100 (midpoint)
startACycleAtTime(tStart)
Parameters: tStart (number) - time value where cycle begins
Sets the phase shift (D) so that a new cycle starts at the specified time. Useful for synchronizing waves.
let wave = new SWSinusoid();
wave.startACycleAtTime(5);
// At time = 5, the wave will be at the start of a cycle
Value Methods
getValue(x)
Parameters: x (number) - input value (typically time)
Returns: number - the y-value at the given x
Evaluates the sinusoidal function at the given x-value. This is the primary method used in animations.
let wave = new SWSinusoid(100, 1, 200, 0);
function draw() {
let t = millis() / 1000; // Time in seconds
let y = wave.getValue(t);
circle(200, y, 50);
}
Utility Methods
toString()
Returns: string - human-readable representation
Returns a string representation of the sinusoid formula and period.
let wave = new SWSinusoid(2, 0.5, 10, 1);
console.log(wave.toString());
// Output: "y = 2 * sin(0.5 * (x - 1)) + 10 with period 12.566370614359172"
Static Methods
SWSinusoid.copy(sinusoid)
Parameters: sinusoid (SWSinusoid) - sinusoid to copy
Returns: SWSinusoid - new independent copy
Creates a deep copy of an existing SWSinusoid instance.
let original = new SWSinusoid(5, 2, 10, 0);
let copy = SWSinusoid.copy(original);
// copy is independent of original
Predefined Constants
SWSinusoid provides three predefined constants for convenience:
// Unit sinusoid: y = sin(x)
const UNIT_SINUSOID = new SWSinusoid(1, 1, 0, 0);
// Unit cosine: y = cos(x) = sin(x + π/2)
const UNIT_COSINE = new SWSinusoid(1, 1, 0, -Math.PI/2);
// Generic sinusoid (same as unit): y = sin(x)
const GENERIC_SINUSOID = new SWSinusoid(1, 1, 0, 0);
Understanding UNIT_COSINE: The cosine function is a sine wave shifted by 90 degrees (π/2 radians). At time t = 0:
UNIT_SINUSOID.getValue(0)returns 0 (starts at center)UNIT_COSINE.getValue(0)returns 1 (starts at maximum)
Use UNIT_COSINE when you want animations to start at their peak value instead of the center.
These can be used as templates:
// Create a sine-based wave
let myWave = SWSinusoid.copy(UNIT_SINUSOID);
myWave.adjustWaveUsingExtrema(0, 100);
// Create a cosine-based wave (starts at max)
let cosWave = SWSinusoid.copy(UNIT_COSINE);
cosWave.adjustWaveUsingExtrema(50, 150);
Usage Examples
Example 1: Bouncing Ball
let bounceWave;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
// Create wave that oscillates between y=100 and y=300
bounceWave = new SWSinusoid();
bounceWave.adjustWaveUsingExtrema(100, 300);
bounceWave.setPeriod(2); // 2 second period
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000; // Time in seconds
let y = bounceWave.getValue(t);
fill(0, 100, 100);
circle(200, y, 50);
}
Example 2: Breathing Effect (Size Pulsing)
let sizeWave;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
// Size oscillates between 30 and 100
sizeWave = new SWSinusoid();
sizeWave.adjustWaveUsingExtrema(30, 100);
sizeWave.setPeriod(3); // Breathe every 3 seconds
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000;
let size = sizeWave.getValue(t);
fill(210, 100, 100);
circle(200, 200, size);
}
Example 3: Color Cycling with SWColor
let hueWave;
let myColor;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors();
// Hue cycles through full spectrum (0-360)
hueWave = new SWSinusoid();
hueWave.adjustWaveUsingExtrema(0, 360);
hueWave.setPeriod(5); // Full cycle every 5 seconds
myColor = new SWColor(0, 100, 100);
}
function draw() {
let t = millis() / 1000;
myColor.h = hueWave.getValue(t);
background(myColor.col);
// Display current hue
fill(0);
text(`Hue: ${myColor.h.toFixed(1)}°`, 10, 20);
}
Example 4: Multiple Synchronized Waves
let wave1, wave2, wave3;
function setup() {
createCanvas(600, 400);
colorMode(HSB, 360, 100, 100, 100);
// All waves have same period but different amplitudes
wave1 = new SWSinusoid();
wave1.adjustWaveUsingExtrema(150, 250);
wave1.setPeriod(4);
wave2 = new SWSinusoid();
wave2.adjustWaveUsingExtrema(100, 300);
wave2.setPeriod(4);
wave3 = new SWSinusoid();
wave3.adjustWaveUsingExtrema(125, 275);
wave3.setPeriod(4);
// Phase shift wave3 by 90 degrees (π/2 radians)
wave3.D = Math.PI / 2;
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000;
fill(0, 100, 100);
circle(150, wave1.getValue(t), 40);
fill(120, 100, 100);
circle(300, wave2.getValue(t), 40);
fill(240, 100, 100);
circle(450, wave3.getValue(t), 40);
}
Example 5: Horizontal Movement
let xWave, yWave;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
// Horizontal oscillation
xWave = new SWSinusoid();
xWave.adjustWaveUsingExtrema(100, 300);
xWave.setPeriod(3);
// Vertical oscillation with different period
yWave = new SWSinusoid();
yWave.adjustWaveUsingExtrema(100, 300);
yWave.setPeriod(4);
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000;
let x = xWave.getValue(t);
let y = yWave.getValue(t);
// Draw path
stroke(0, 0, 78);
noFill();
beginShape();
for (let i = 0; i < 100; i++) {
let pastT = t - i * 0.05;
let px = xWave.getValue(pastT);
let py = yWave.getValue(pastT);
vertex(px, py);
}
endShape();
// Draw current position
fill(0, 100, 100);
noStroke();
circle(x, y, 20);
}
Example 6: Rotation Animation
let angleWave;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
// Oscillate angle between -45° and 45°
angleWave = new SWSinusoid();
angleWave.adjustWaveUsingExtrema(-PI/4, PI/4);
angleWave.setPeriod(2);
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000;
let angle = angleWave.getValue(t);
push();
translate(200, 200);
rotate(angle);
fill(220, 60, 100);
rect(-50, -100, 100, 200);
pop();
}
Example 7: Opacity Fading
let alphaWave;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
// Alpha oscillates between 0 (transparent) and 100 (opaque)
alphaWave = new SWSinusoid();
alphaWave.adjustWaveUsingExtrema(0, 100);
alphaWave.setPeriod(3);
}
function draw() {
background(0, 0, 86);
let t = millis() / 1000;
let alpha = alphaWave.getValue(t);
fill(0, 100, 100, alpha);
circle(200, 200, 150);
// Display alpha value
fill(0, 0, 0);
text(`Alpha: ${alpha.toFixed(0)}`, 10, 20);
}
Best Practices
- Use adjustWaveUsingExtrema(): Easier than calculating A and C manually when you know the range
- Use setPeriod(): More intuitive than setting frequency (B) directly
- Use millis() / 1000: Converts milliseconds to seconds for time-based animations
- Start simple: Begin with unit sinusoid and adjust as needed
- Synchronize waves: Use the same period for related animations
- Phase shift for variety: Use D parameter to offset identical waves
- Store in variables: Create SWSinusoid instances in setup(), not draw()
- Combine multiple waves: Create complex motions by combining different sinusoids
Common Patterns
// Pattern 1: Quick setup for bounded animation
let wave = new SWSinusoid();
wave.adjustWaveUsingExtrema(min, max);
wave.setPeriod(seconds);
// Pattern 2: Using with SWColor for color animation
let colorWave = new SWSinusoid();
colorWave.adjustWaveUsingExtrema(0, 360);
myColor.h = colorWave.getValue(time);
// Pattern 3: Phase-shifted copies
let wave1 = new SWSinusoid();
wave1.adjustWaveUsingExtrema(100, 300);
let wave2 = SWSinusoid.copy(wave1);
wave2.D = Math.PI / 2; // 90° phase shift
Integration with SketchWave
Loading Order
<script src="https://cdn.jsdelivr.net/npm/p5@1.6.0/lib/p5.js"></script>
<!-- SketchWave classes in dependency order -->
<script src="scripts/swColor.js"></script>
<script src="scripts/swSinusoid.js"></script>
<!-- Your sketch -->
<script src="scripts/yourSketch.js"></script>
Using with SWColor
SWSinusoid works seamlessly with SWColor for animating color properties:
let hueWave, satWave, brightWave;
let dynamicColor;
function setup() {
createCanvas(400, 400);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors();
hueWave = new SWSinusoid();
hueWave.adjustWaveUsingExtrema(0, 360);
satWave = new SWSinusoid();
satWave.adjustWaveUsingExtrema(50, 100);
dynamicColor = new SWColor(0, 100, 100);
}
function draw() {
let t = millis() / 1000;
dynamicColor.h = hueWave.getValue(t);
dynamicColor.s = satWave.getValue(t);
background(dynamicColor.col);
}
Using with SWPoint and SWBug
Animate positions, sizes, and other properties:
let posWave, sizeWave;
let myPoint;
function setup() {
createCanvas(400, 400);
posWave = new SWSinusoid();
posWave.adjustWaveUsingExtrema(100, 300);
sizeWave = new SWSinusoid();
sizeWave.adjustWaveUsingExtrema(5, 20);
myPoint = new SWPoint(200, 200, undefined, 10, swRed);
}
function draw() {
background(220);
let t = millis() / 1000;
myPoint.y = posWave.getValue(t);
myPoint.strokeWeight = sizeWave.getValue(t);
myPoint.draw();
}
Mathematical Details
Understanding the Parameters
| Parameter | Effect on Wave | Relationship |
|---|---|---|
| A (Amplitude) | Height from center | Range = 2A (from C-A to C+A) |
| B (Frequency) | Speed of oscillation | Period = 2π / B |
| C (Vertical Shift) | Center line position | C = (max + min) / 2 |
| D (Phase Shift) | Horizontal offset | Shifts graph right by D |
Key Relationships
// Given min and max values:
A = (max - min) / 2
C = (max + min) / 2
// Given desired period in seconds:
B = (2 * Math.PI) / period
// For a wave oscillating between minY and maxY:
wave.adjustWaveUsingExtrema(minY, maxY);
// Sets: A = (maxY - minY) / 2
// C = (maxY + minY) / 2
Source Code
Show/Hide Source Code
/*
File: swSinusoid.js
Author: klp
Description: SWSinusoid class for modeling sinusoidal behavior
Date: 2026-01-30
Notes:
- Models y = A * sin(B * (x - D)) + C
- A = Amplitude
- B = Frequency
- C = Vertical shift
- D = Phase shift
- Period = (2π) / B
*/
console.log("[swSinusoid.js] SWSinusoid class loaded");
class SWSinusoid {
constructor(A = 1, B = 1, C = 0, D = 0) {
this.A = A; // Amplitude
this.B = B; // Frequency
this.C = C; // Vertical shift
this.D = D; // Phase shift
this.period = (2 * Math.PI) / B;
}
setPeriod(newPeriod) {
this.period = newPeriod;
this.B = 2 * Math.PI / newPeriod;
}
adjustWaveUsingExtrema(minY, maxY) {
this.A = (maxY - minY) / 2;
this.C = (maxY + minY) / 2;
}
startACycleAtTime(tStart) {
this.D = tStart;
}
getValue(x) {
return this.A * Math.sin(this.B * (x - this.D)) + this.C;
}
toString() {
return `y = ${this.A} * sin(${this.B} * (x - ${this.D})) + ${this.C} with period ${this.period}`;
}
static copy(sinusoid) {
if (!(sinusoid instanceof SWSinusoid)) {
throw new Error('Argument must be an SWSinusoid instance');
}
return new SWSinusoid(sinusoid.A, sinusoid.B, sinusoid.C, sinusoid.D);
}
}
const UNIT_SINUSOID = new SWSinusoid(1, 1, 0, 0);
const UNIT_COSINE = new SWSinusoid(1, 1, 0, -Math.PI/2);
const GENERIC_SINUSOID = new SWSinusoid(1, 1, 0, 0);