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:
- Body —
SWCloverwith 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. - Stem —
SWSpirewithhalfShape = trueand baserotationDeg = 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:
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 = π:
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:
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)
| Parameter | Type | Default | Description |
|---|---|---|---|
center | SWPoint | required | Center of the body in user (grid) coordinates |
bodyRadius | number | 3 | Distance from center to each of the 3 petal tips (grid units, min 0.1) |
stemLength | number | 2.5 | SWSpire radiusY: depth of the downward cusp below the body (grid units, min 0.1) |
stemWidth | number | 0.8 | SWSpire radiusX: half-width of the arch base (grid units, min 0.05) |
stemPower | number | 5 | SWSpire power exponent: higher = sharper cusp; 1 = smooth half-ellipse (min 1) |
fillColor | SWColor | undefined | Fill color for body and stem; undefined = no fill |
strokeColor | SWColor | undefined | Stroke color; undefined = no stroke |
thickness | number | 2 | Stroke weight in pixels |
rotationDeg | number | 0 | Static base rotation in CCW degrees; persists across reset() |
Properties
| Property | Type | Description |
|---|---|---|
center | SWPoint | Body center in user coordinates. Move by setting center.x, center.y. |
bodyRadius | number | Current petal-tip radius (grid units). |
stemLength | number | Current stem depth (SWSpire radiusY). |
stemWidth | number | Current stem half-width (SWSpire radiusX). |
stemPower | number | Current cusp sharpness exponent. |
fillColor | SWColor | Shared fill color applied to both body and stem. |
strokeColor | SWColor | Shared stroke color applied to both body and stem. |
thickness | number | Stroke weight in pixels. |
rotationDeg | number | Static base rotation (CCW degrees). Persists across reset(). |
rotation | number | Accumulated spin added by rotate(). Cleared by reset(). |
_body | SWClover | Internal. Do not access directly. |
_stem | SWSpire | Internal. Do not access directly. |
Methods
Drawing
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
rotate(deltaAngle) | Adds deltaAngle degrees (CCW+, CW−) to rotation. Call once per frame: club.rotate(speed * deltaT). |
Setters
| Method | Parameter | Description |
|---|---|---|
setBodyRadius(r) | number ≥ 0.1 | Sets the body petal-tip radius. |
setStemLength(l) | number ≥ 0.1 | Sets the stem cusp depth (SWSpire radiusY). |
setStemWidth(w) | number ≥ 0.05 | Sets the stem base half-width (SWSpire radiusX). |
setStemPower(p) | number ≥ 1 | Sets the cusp sharpness exponent. |
setRotation(deg) | number | Sets the static base rotation (CCW degrees). |
setFillColor(fc) | SWColor|undefined | Sets the fill color (deep copies the SWColor). |
setStrokeColor(sc) | SWColor|undefined | Sets the stroke color. |
setStrokeWeight(w) | number | Sets stroke thickness in pixels. |
setFillAlpha(alpha) | 0–100 | Sets fill opacity and rebuilds the p5 color object. |
setStrokeAlpha(alpha) | 0–100 | Sets stroke opacity and rebuilds the p5 color object. |
Reset & Utility
| Method | Description |
|---|---|
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...