📂 The Stage 4 Files
Stage 4 replaces every raw p5.js drawing call with a SketchWave object. The rocket looks identical to Stage 3 — same position, same colors, same scrolling stars — but its internal structure is completely different. Three files make up the Stage 4 build:
| File | What it does | Stage 4 changes |
|---|---|---|
rocketStg4.html |
HTML shell | Six new <script> tags load the SW class library |
rocketStg4Sketch.js |
The p5.js sketch | colorMode(HSB); SW objects built in setup();
sinusoid animations; draw() calls .draw() |
rocket4Styles.css |
Minimal CSS reset | Unchanged from Stages 2 & 3 |
SketchWave classes loaded for this stage:
| Class | File | Used for |
|---|---|---|
| SWColor | swColor.js |
All six named colors; HSB palette |
| SWPoint | swPoint.js |
Vertices and center positions for every shape |
| SWSinusoid | swSinusoid.js |
Flame flicker & porthole pulse animations |
| SWRectangle | swRectangle.js |
Rocket body |
| SWTriangle | swTriangle.js |
Nose cone, left fin, right fin, flame |
| SWDisk | swDisk.js |
Porthole (with breathe() animation) |
In
setup(), each rocket part is constructed as an SW
object and stored in a named variable (rocketBody,
noseCone, flame, …).
draw() shrinks to:drawBackground(); drawStars(); animateFlame(t); animatePorthole(t); drawRocket();And
drawRocket() is simply:leftFin.draw(); rightFin.draw(); rocketBody.draw(); …Each shape knows how to draw itself.
draw() is a
pure table of contents.
Flame:
flame.vC is the
SWPoint at the flame tip. Each frame:flame.vC.y = flameSin.getValue(t);One line. The sinusoid oscillates the tip between 325 px and 385 px below the canvas top (a 60 px range) at ~3 cycles per second.
SWTriangle.draw()
always reads the current vertex positions, so the
flame automatically draws at the right length every frame.Porthole:
porthole.breathe(portholeBreatheSin, t);SWDisk.breathe() sets this.radius
to the sinusoid value. The radius oscillates between 14 px and
16 px over 2.5 seconds — a slow, glowing pulse.
Stage 4 adds six
<script> tags and a longer
setup(). That is real cost.The payoff: every future animation is one sinusoid + one property update. Want the nose cone to wobble? Add a sinusoid, update
noseCone.vC.x in
draw(). Want the body to breathe?
Call rocketBody.breathe(s, t). No new drawing
functions. No restructuring.In software engineering, this principle is called Open/Closed: open for extension, closed for modification. SW objects make animation open for extension.
📊 Stage 3 vs Stage 4: Same Look, Different Structure
Both stages render an identical rocket on an identical scrolling star field. The difference is entirely in how the drawing code is organized.
| Aspect | Stage 3 — Raw p5.js | Stage 4 — SketchWave |
|---|---|---|
| Rocket body | rect(BODY_X, BODY_Y, BODY_W, BODY_H) |
rocketBody.draw() |
| Color definition | const CLR_ACCENT = [255, 100, 100] |
clrRocketRed = new SWColor(0, 61, 100, 100, "rocketRed") |
| Color mode | Default RGB (p5 auto-detects) | colorMode(HSB, 360, 100, 100, 100) — required for SWColor |
| Flame animation | Not possible without redesigning drawFlame() |
flame.vC.y = flameSin.getValue(t); — one line |
| Porthole animation | Not possible without a new radius variable and redraw logic | porthole.breathe(portholeBreatheSin, t); — one line |
draw() length |
Calls multiple drawing sub-functions directly | Calls 5 high-level functions; each part calls .draw() |
| Script tags | 2 (p5 + sketch) | 8 (p5 + 6 SW classes + sketch) |
| Stars | Identical plain JS objects — deliberately not converted to SW | |
SWDisk objects?Converting 100 plain JS star objects to
SWDisk instances would
create 100 SWColor objects, 100 SWPoint center
objects, plus all their internal copies — for dots that are 1–3 px wide
and completely opaque half the time. The visual result would be
identical but the memory and construction cost would be significant.
Stage 4 keeps stars as plain JS objects deliberately. This is a real engineering decision: use the right tool for the right job. SW classes shine for complex, named, animatable shapes. They are overkill for 100 tiny identical dots.
📜 Source Code
Loading rocketStg4.html…
Loading rocketStg4Sketch.js…
Loading rocket4Styles.css…
💪 Try It Yourself
Use the Copy buttons above to grab the files, then:
-
Copy the
shapeClasses/folder from the project (you needswColor.js,swPoint.js,swSinusoid.js,swRectangle.js,swTriangle.js, andswDisk.js). -
Open
rocketStg4.htmlfrom a web server (VS Code Live Server, or localhost) — the SW classconsole.logmessages confirm every file loaded. -
Flame speed challenge: change
FLAME_PERIODfrom0.35to1.5. How does the flicker feel different? What happens if you set it to0.1? -
Porthole glow challenge: change
PORT_R_MINandPORT_R_MAXto exaggerate the pulse (e.g., 8 and 30). Does it still look like a porthole? -
New animation challenge: add a sinusoid that makes
the nose cone wobble left and right. Store the original
noseCone.vC.x(=BODY_CX= 300) and add a sinusoid value to it each frame. What period and amplitude feel natural? -
Stars with depth challenge (from Stage 3): give each
star a
speedproperty ingenerateStars()scaled by its size so larger stars scroll faster. This creates a parallax depth effect.
⚠️ The Copy button requires a secure context
(https:// or localhost). If you’re viewing this file directly
from your file system (file://), right-click the
Open Full Size link above and choose “View Page Source” instead.