Overview
SWSnowFlake is a Core composite class that builds a snowflake around a center locator. The center can be either:
- SWPoint for static positioning
- SWBug for animated movement modes in demos/apps
The class supports two algorithm families:
- IterativeStellar Dendrite, Fern Dendrite, Plate Crystal, Needle Cluster
- RecursiveKoch Crystal, Recursive Dendrite
In addition to style selection, you can control radius, arm count, colors, border behavior, center marker display, recursion controls, and both static and animated rotation.
Constructor
let flake = new SWSnowFlake(center, maxRadius, armCount, flakeColor, borderColor, options);
let center = new SWPoint(0, 0);
let flakeColor = new SWColor(195, 20, 98, 100, "flakeColor");
let borderColor = new SWColor(210, 35, 60, 95, "flakeBorder");
let flake = new SWSnowFlake(center, 6, 6, flakeColor, borderColor, {
rotationDeg: 0,
recursionDepth: 3,
recursiveScale: 0.58,
recursiveBranchAngleDeg: 33
});
Notes: arm count is clamped to a valid range; recursive settings are clamped for stability/performance.
Properties
center
Center locator object (SWPoint or SWBug).
Center locator object (SWPoint or SWBug).
maxRadius
Maximum arm reach in user units.
Maximum arm reach in user units.
armCount
Number of radial arms used to generate the snowflake.
Number of radial arms used to generate the snowflake.
style
Current style key (iterative or recursive family).
Current style key (iterative or recursive family).
flakeColor / borderColor
Primary stroke/fill color and border color.
Primary stroke/fill color and border color.
borderEnabled / borderThickness
Outline toggle and thickness control.
Outline toggle and thickness control.
rotationDeg / totalRotationDeg
Static rotation and combined static+animated rotation readout.
Static rotation and combined static+animated rotation readout.
recursionDepth / recursiveScale / recursiveBranchAngleDeg
Fractal controls used by recursive styles.
Fractal controls used by recursive styles.
shouldShowCenter / centerMarkerSize
Center marker visibility and marker size.
Center marker visibility and marker size.
Methods
Shape + Style
setCenter(center)
Replace center object safely (supports SWPoint and SWBug).
Replace center object safely (supports SWPoint and SWBug).
setMaxRadius(r)
Update arm reach/radius.
Update arm reach/radius.
setArmCount(n)
Update arm count (clamped).
Update arm count (clamped).
setStyle(styleName)
Switch among allowed style names.
Switch among allowed style names.
setSeed(seed)
Set deterministic pseudo-random seed for style jitter/details.
Set deterministic pseudo-random seed for style jitter/details.
Fractal Controls
setRecursionDepth(n)
Set recursive level depth for Koch and recursive dendrite styles.
Set recursive level depth for Koch and recursive dendrite styles.
setRecursiveScale(scale)
Set branch length shrink factor for recursive dendrite.
Set branch length shrink factor for recursive dendrite.
setRecursiveBranchAngleDeg(angleDeg)
Set branch split angle in degrees.
Set branch split angle in degrees.
Color + Border
setFlakeColor(swColor)
Set main snowflake color.
Set main snowflake color.
setBorderColor(swColor)
Set border color.
Set border color.
setBorderEnabled(shouldEnable)
Show/hide border outline layer.
Show/hide border outline layer.
setBorderThickness(t)
Set border thickness.
Set border thickness.
Rotation + Center Marker
setRotationDeg(angleDeg)
Set static orientation angle.
Set static orientation angle.
rotateBy(angleDeltaDeg)
Add delta angle to static rotation.
Add delta angle to static rotation.
setAnimatedRotationDeg(angleDeg)
Set animated rotation contribution.
Set animated rotation contribution.
clearAnimatedRotation()
Reset animated contribution to 0.
Reset animated contribution to 0.
setShowCenter(show)
Show/hide center marker.
Show/hide center marker.
setCenterMarkerSize(sz)
Set center marker size.
Set center marker size.
Rendering
draw()
Draw using current screen coordinates.
Draw using current screen coordinates.
drawOnGrid(grid)
Draw in user coordinates using SWGrid transforms.
Draw in user coordinates using SWGrid transforms.
toString()
Debug summary string (style, arms, rotation, depth, border).
Debug summary string (style, arms, rotation, depth, border).
Allowed Styles
SWSnowFlake.allowedStyles();
// [
// "stellarDendrite",
// "fernDendrite",
// "plateCrystal",
// "needleCluster",
// "kochCrystal",
// "recursiveDendrite"
// ]
Usage Examples
Example 1: Basic Snowflake On Grid
let grid;
let snowflake;
function setup() {
createCanvas(540, 540);
colorMode(HSB, 360, 100, 100, 100);
initializeSWColors();
grid = new SWGrid({ UL: new SWPoint(-10, 10), LR: new SWPoint(10, -10) });
let center = new SWPoint(0, 0);
let flakeColor = new SWColor(198, 18, 98, 100, "flake");
let borderColor = new SWColor(210, 40, 60, 100, "border");
snowflake = new SWSnowFlake(center, 6, 6, flakeColor, borderColor, {
rotationDeg: 0,
recursionDepth: 2,
recursiveScale: 0.58,
recursiveBranchAngleDeg: 33
});
snowflake.setStyle("stellarDendrite");
snowflake.setBorderThickness(0.8);
snowflake.setShowCenter(true);
}
function draw() {
background(210, 30, 12, 100);
grid.draw();
snowflake.drawOnGrid(grid);
}
Example 2: Recursive Koch Crystal
// Switch to recursive Koch and increase depth
snowflake.setStyle("kochCrystal");
snowflake.setRecursionDepth(4);
snowflake.setRotationDeg(15);
Example 3: Animated Spin + Moving Center Bug
let bugCenter = new SWBug(0, 0, "p", 0.08, swWhite, {
noiseAmount: 0.01,
strokeWeight: 5
});
snowflake.setCenter(bugCenter);
function draw() {
background(210, 30, 12, 100);
grid.draw();
bugCenter.move(grid);
snowflake.setAnimatedRotationDeg(millis() * 0.03);
snowflake.drawOnGrid(grid);
}
Integration Notes
Load scripts in dependency order:
<script src="https://cdn.jsdelivr.net/npm/p5@1.6.0/lib/p5.js"></script>
<script src="../shapeClasses/swColor.js"></script>
<script src="../shapeClasses/swPoint.js"></script>
<script src="../shapeClasses/swGrid.js"></script>
<script src="../shapeClasses/swBug.js"></script>
<script src="../shapeClasses/swSnowFlake.js"></script>
<script src="../sketches/yourSketch.js"></script>
Source Code
The complete SWSnowFlake class implementation:
Show/Hide Source Code
/*
File: swSnowFlake.js
Date: 2026-05-28
Author: klp + Copilot
Purpose: SWSnowFlake class for SketchWaveJS
A composite procedural snowflake centered on an SWPoint (or SWBug), with
configurable radius, arm count, style, color, and optional border outlines.
Dependencies:
- p5.js
- SWColor
- SWPoint
- SWBug (optional center type)
*/
console.log("[swSnowFlake.js] SWSnowFlake class loaded.");
class SWSnowFlake {
constructor(center, maxRadius = 6, armCount = 6, flakeColor = undefined, borderColor = undefined, options = {}) {
if (typeof options === "number") {
options = { rotationDeg: options };
}
this.center = SWSnowFlake.copyCenter(center);
this.maxRadius = Math.max(0.2, Number(maxRadius) || 6);
this.armCount = SWSnowFlake.clampArmCount(armCount);
this.flakeColor = SWSnowFlake.copyColorOrDefault(flakeColor, new SWColor(200, 20, 100, 100, "flakeColor"));
this.borderColor = SWSnowFlake.copyColorOrDefault(borderColor, new SWColor(210, 35, 65, 100, "flakeBorder"));
this.borderEnabled = true;
this.borderThickness = 0.8;
this.style = "stellarDendrite";
this.seed = 1;
this.rotationDeg = Number(options.rotationDeg ?? options.rotation ?? 0) || 0;
this._animRotDeg = Number(options.animRotationDeg ?? options.animatedRotationDeg ?? 0) || 0;
this.recursionDepth = SWSnowFlake.clampRecursionDepth(options.recursionDepth ?? 3);
this.recursiveScale = SWSnowFlake.clampRecursiveScale(options.recursiveScale ?? 0.58);
this.recursiveBranchAngleDeg = SWSnowFlake.clampRecursiveBranchAngle(options.recursiveBranchAngleDeg ?? 33);
this.shouldShowCenter = false;
this.centerMarkerSize = 5;
}//end constructor
static allowedStyles() {
return ["stellarDendrite", "fernDendrite", "plateCrystal", "needleCluster", "kochCrystal", "recursiveDendrite"];
}//end allowedStyles
static clampArmCount(n) {
return Math.max(4, Math.min(16, Math.round(Number(n) || 6)));
}//end clampArmCount
static clampRecursionDepth(n) {
return Math.max(0, Math.min(6, Math.round(Number(n) || 0)));
}//end clampRecursionDepth
static clampRecursiveScale(n) {
const x = Number(n);
if (!Number.isFinite(x)) return 0.58;
return Math.max(0.35, Math.min(0.82, x));
}//end clampRecursiveScale
static clampRecursiveBranchAngle(n) {
const x = Number(n);
if (!Number.isFinite(x)) return 33;
return Math.max(8, Math.min(85, x));
}//end clampRecursiveBranchAngle
static copyCenter(center) {
if (!(center instanceof SWPoint)) {
throw new Error("SWSnowFlake expects center to be an SWPoint or SWBug.");
}
if (typeof SWBug !== "undefined" && center instanceof SWBug) {
const strokeColorCopy = center.strokeColor ? SWColor.copy(center.strokeColor) : undefined;
const bugCopy = new SWBug(center.x, center.y, center.mode, center.speed, strokeColorCopy, {
noiseAmount: center.noiseAmount,
strokeWeight: center.strokeWeight,
trailPersistence: center.trailPersistence,
shouldWrapAround: center.shouldWrapAround,
});
bugCopy.label = center.label;
bugCopy.showLabel = center.showLabel;
bugCopy.labelOffset = { x: center.labelOffset.x, y: center.labelOffset.y };
bugCopy.labelFontSize = center.labelFontSize;
bugCopy.isDraggable = center.isDraggable;
bugCopy.penOn = center.penOn;
bugCopy.maxTrailLength = center.maxTrailLength;
bugCopy.trail = center.trail.map(function (pt) {
return { x: pt.x, y: pt.y, z: pt.z };
});
bugCopy.setShouldShowTrails(!!center.shouldShowTrails);
return bugCopy;
}
return SWPoint.copy(center);
}//end copyCenter
static copyColorOrDefault(swColor, fallbackColor) {
if (swColor instanceof SWColor) {
return SWColor.copy(swColor);
}
return SWColor.copy(fallbackColor);
}//end copyColorOrDefault
static hash01(a, b = 0, c = 0) {
const x = Math.sin(a * 12.9898 + b * 78.233 + c * 37.719) * 43758.5453;
return x - Math.floor(x);
}//end hash01
setCenter(center) {
if (center instanceof SWPoint) {
this.center = SWSnowFlake.copyCenter(center);
}
}//end setCenter
setMaxRadius(r) {
this.maxRadius = Math.max(0.2, Number(r) || this.maxRadius);
}//end setMaxRadius
setArmCount(n) {
this.armCount = SWSnowFlake.clampArmCount(n);
}//end setArmCount
setFlakeColor(swColor) {
if (swColor instanceof SWColor) this.flakeColor = SWColor.copy(swColor);
}//end setFlakeColor
setBorderColor(swColor) {
if (swColor instanceof SWColor) this.borderColor = SWColor.copy(swColor);
}//end setBorderColor
setBorderEnabled(shouldEnable) {
this.borderEnabled = !!shouldEnable;
}//end setBorderEnabled
setBorderThickness(t) {
this.borderThickness = Math.max(0, Number(t) || 0);
}//end setBorderThickness
setStyle(styleName) {
if (SWSnowFlake.allowedStyles().includes(styleName)) this.style = styleName;
}//end setStyle
setSeed(seed) {
this.seed = Math.max(0, Math.round(Number(seed) || 0));
}//end setSeed
setRotationDeg(angleDeg) {
const n = Number(angleDeg);
this.rotationDeg = Number.isFinite(n) ? n : this.rotationDeg;
}//end setRotationDeg
setRecursionDepth(n) {
this.recursionDepth = SWSnowFlake.clampRecursionDepth(n);
}//end setRecursionDepth
setRecursiveScale(scale) {
this.recursiveScale = SWSnowFlake.clampRecursiveScale(scale);
}//end setRecursiveScale
setRecursiveBranchAngleDeg(angleDeg) {
this.recursiveBranchAngleDeg = SWSnowFlake.clampRecursiveBranchAngle(angleDeg);
}//end setRecursiveBranchAngleDeg
rotateBy(angleDeltaDeg) {
const n = Number(angleDeltaDeg);
if (Number.isFinite(n)) {
this.rotationDeg += n;
}
}//end rotateBy
setAnimatedRotationDeg(angleDeg) {
const n = Number(angleDeg);
this._animRotDeg = Number.isFinite(n) ? n : this._animRotDeg;
}//end setAnimatedRotationDeg
clearAnimatedRotation() {
this._animRotDeg = 0;
}//end clearAnimatedRotation
get totalRotationDeg() {
return this.rotationDeg + this._animRotDeg;
}//end totalRotationDeg
setShowCenter(show) {
this.shouldShowCenter = !!show;
}//end setShowCenter
setCenterMarkerSize(sz) {
this.centerMarkerSize = Math.max(1, Number(sz) || this.centerMarkerSize);
}//end setCenterMarkerSize
draw() {
this._drawAt(this.center.x, this.center.y, this.maxRadius);
}//end draw
drawOnGrid(grid) {
if (!grid || typeof grid.userToScreen !== "function") return;
const pos = grid.userToScreen(this.center.x, this.center.y);
const rx = this.maxRadius * grid.xScale;
const ry = this.maxRadius * grid.yScale;
const rScreen = (rx + ry) / 2;
this._drawAt(pos.x, pos.y, rScreen);
}//end drawOnGrid
// Full drawing helpers omitted here for page brevity.
// See shapeClasses/swSnowFlake.js for the full method set.
toString() {
return `SWSnowFlake(center: ${this.center.toString()}, maxRadius: ${this.maxRadius}, arms: ${this.armCount}, style: ${this.style}, rotation: ${this.totalRotationDeg.toFixed(1)}deg, depth: ${this.recursionDepth}, borderEnabled: ${this.borderEnabled})`;
}//end toString
}//end class SWSnowFlake