SWClub Reference

Composite Shape (SWClover + SWSpire) — SketchWaveJS

♣ Composite Class Design

SWClub is a composite class. It does not draw directly to the canvas itself — instead it assembles and synchronises two internal SketchWaveJS shapes:

  • BodySWClover with numPetals = 3 (fixed) and a 90° CCW offset so the top lobe always points up. This 3-cusp epicycloid produces the classic playing-card club ♣ silhouette.
  • StemSWSpire with halfShape = true and base rotationDeg = 180, creating a downward-pointing cusp arch that emerges from the two lower cusps of the body.

The user interacts only with SWClub's own API. The internal SWClover and SWSpire are implementation details and are reconstructed/synchronised on every draw call via _syncInternals().

Draw order: stem is drawn first (behind), then body on top. This ensures the arch base is naturally concealed under the body fill.

Mathematical Foundation

Body: 3-Petal Epicycloid

The body is an epicycloid with n = 4 (numPetals + 1) and scale factor a = bodyRadius / 3:

n = 4,   a = bodyRadius / 3

x(t) = a · (4·cos(t) − cos(4t))
y(t) = a · (4·sin(t) − sin(4t))

t ∈ [0, 2π)

With the 90° CCW offset, the three cusp tips (at zero total rotation) land at:

  • Top: (0, +bodyRadius)
  • Lower-left: (−bodyRadius·√3/2, −bodyRadius/2)
  • Lower-right: (+bodyRadius·√3/2, −bodyRadius/2)

Stem: Half SWSpire Arch

The SWSpire half arch is traced from t = 0 to t = π:

x(t) = radiusX · |cos(t)|2/power · sign(cos(t))
y(t) = radiusY · |sin(t)|2/power · sign(sin(t))

t ∈ [0, π] (half arch only),  closed with CLOSE

With rotationDeg = 180 + total rotation, the arch curves downward from the base at (±radiusX, 0) to a cusp at (0, −radiusY). endShape(CLOSE) draws the flat base between the two arch endpoints.

Stem Placement (Rotation Math)

The stem is attached at local-space point (0, −bodyRadius/2) — the midpoint between the two lower cusps. After applying the total rotation angle θ (CCW), the stem centre in world space is:

stemX = center.x + (bodyRadius/2) · sin(θ)
stemY = center.y − (bodyRadius/2) · cos(θ)

This is a standard 2D rotation of the local offset vector (0, −r/2) by angle θ.

Constructor

new SWClub(center, bodyRadius, stemLength, stemWidth, stemPower,
           fillColor, strokeColor, thickness, rotationDeg)
ParameterTypeDefaultDescription
centerSWPointrequiredCenter of the body in user (grid) coordinates
bodyRadiusnumber3Distance from center to each of the 3 petal tips (grid units, min 0.1)
stemLengthnumber2.5SWSpire radiusY: depth of the downward cusp below the body (grid units, min 0.1)
stemWidthnumber0.8SWSpire radiusX: half-width of the arch base (grid units, min 0.05)
stemPowernumber5SWSpire power exponent: higher = sharper cusp; 1 = smooth half-ellipse (min 1)
fillColorSWColorundefinedFill color for body and stem; undefined = no fill
strokeColorSWColorundefinedStroke color; undefined = no stroke
thicknessnumber2Stroke weight in pixels
rotationDegnumber0Static base rotation in CCW degrees; persists across reset()

Properties

PropertyTypeDescription
centerSWPointBody center in user coordinates. Move by setting center.x, center.y.
bodyRadiusnumberCurrent petal-tip radius (grid units).
stemLengthnumberCurrent stem depth (SWSpire radiusY).
stemWidthnumberCurrent stem half-width (SWSpire radiusX).
stemPowernumberCurrent cusp sharpness exponent.
fillColorSWColorShared fill color applied to both body and stem.
strokeColorSWColorShared stroke color applied to both body and stem.
thicknessnumberStroke weight in pixels.
rotationDegnumberStatic base rotation (CCW degrees). Persists across reset().
rotationnumberAccumulated spin added by rotate(). Cleared by reset().
_bodySWCloverInternal. Do not access directly.
_stemSWSpireInternal. Do not access directly.

Methods

Drawing

MethodDescription
drawOnGrid(grid)Synchronises internals then draws stem + body through SWGrid. Preferred method.
draw()Synchronises internals then draws in raw screen (pixel) coordinates. Use only when no grid is present.

Animation

MethodDescription
rotate(deltaAngle)Adds deltaAngle degrees (CCW+, CW−) to rotation. Call once per frame: club.rotate(speed * deltaT).

Setters

MethodParameterDescription
setBodyRadius(r)number ≥ 0.1Sets the body petal-tip radius.
setStemLength(l)number ≥ 0.1Sets the stem cusp depth (SWSpire radiusY).
setStemWidth(w)number ≥ 0.05Sets the stem base half-width (SWSpire radiusX).
setStemPower(p)number ≥ 1Sets the cusp sharpness exponent.
setRotation(deg)numberSets the static base rotation (CCW degrees).
setFillColor(fc)SWColor|undefinedSets the fill color (deep copies the SWColor).
setStrokeColor(sc)SWColor|undefinedSets the stroke color.
setStrokeWeight(w)numberSets stroke thickness in pixels.
setFillAlpha(alpha)0–100Sets fill opacity and rebuilds the p5 color object.
setStrokeAlpha(alpha)0–100Sets stroke opacity and rebuilds the p5 color object.

Reset & Utility

MethodDescription
reset()Restores all parameters to constructor values. Clears rotation. Does not move center.
static copy(other)Returns a deep copy of the SWClub, preserving all current and original state.
toString()Returns a summary string of current parameter values.

Code Examples

Basic Setup

let club;
let grid;

function setup() {
    createCanvas(400, 400);
    colorMode(HSB, 360, 100, 100, 100);
    initializeSWColors();

    grid = new SWGrid({ UL: new SWPoint(-8, 8), LR: new SWPoint(8, -8) });

    const center   = new SWPoint(0, 0);
    const fillCol   = SWColor.fromHex('#2a5a2a', 100, 'fill');
    const strokeCol = SWColor.fromHex('#1a3a1a', 100, 'stroke');

    club = new SWClub(center, 3, 2.5, 0.8, 5, fillCol, strokeCol, 2, 0);
}

function draw() {
    background(0, 0, 93);
    grid.draw();
    club.drawOnGrid(grid);
}

Spin Animation

let prevT = 0;

function draw() {
    const t      = millis() / 1000;
    const deltaT = (prevT > 0) ? (t - prevT) : 0;
    prevT = t;

    background(0, 0, 93);
    grid.draw();
    club.rotate(45 * deltaT);  // 45 °/sec CCW
    club.drawOnGrid(grid);
}

Breathe Animation

let breatheBase = 3.0;   // base bodyRadius

function draw() {
    const t = millis() / 1000;

    background(0, 0, 93);
    grid.draw();

    // Oscillate bodyRadius ±1.0 at 0.5 Hz
    const r = breatheBase + 1.0 * Math.sin(2 * Math.PI * 0.5 * t);
    club.setBodyRadius(Math.max(0.5, r));

    club.drawOnGrid(grid);
}

Copy & Reset

// Deep copy
const club2 = SWClub.copy(club);
club2.center.x += 4;   // moved independently

// Restore factory values
club.reset();

// Inspect
console.log(club.toString());
// SWClub(bodyRadius=3.00, stemLength=2.50, stemWidth=0.80, stemPower=5.0, ...)

Source Code

📄 Toggle Source: swClub.js
Loading source...