SketchWave Sinusoid Class Reference

Mathematical modeling of sinusoidal behavior for animations and effects

Back to SWSinusoid Demo

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.

y = A × sin(B × (x - D)) + C

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
Note: SWSinusoid uses elapsed time (in seconds) rather than frameCount, making animations independent of frame rate.

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);