📂 The Stage 2 Files
Stage 2 takes Jackson's original, working sketch and improves it without changing how it looks. The result is code that is cleaner, safer, and ready to grow. Two files carry all the drawing logic:
| File | What it does | Stage 2 changes |
|---|---|---|
jacksonOrbit1.html |
HTML shell — loads p5js, SWClasses, and the sketch files | Wrapped in the SW template; Bootstrap nav and hero added |
sketches/jacksonOrbit1Sketch.js |
All of Jackson's drawing logic — stars, Earth, Moon, Station | Magic numbers removed; canvas-relative sizing; push/pop orbits; organic land masses |
fetch(url).then(r => r.text()).
💡 Four Big Lessons
Jackson's Stage 1 code was already impressive for a novice — it worked! But four common beginner habits made it fragile. Here’s what we fixed and why it matters.
🔮 Lesson 1 — No More Magic Numbers
A magic number is a raw numeric literal that appears in code
without explanation — 800, 600,
0.3, 40. They are called “magic” because
nobody remembers where the number came from or what happens if
you change it.
Jackson's Stage 1 example:
| ❌ Stage 1 — magic numbers | ✅ Stage 2 — named constants |
|---|---|
createCanvas(800, 600);for (let i = 0; i < 500; i++) {…}translate(300, 0);fill(10, 40, 120);
|
// canvas size set by templatefor (let i = 0; i < 500; i++) {…} // 500 starstranslate(width * 0.4, 0); // 40% of canvasfill(swDeepBlue.col); // named SWColor
|
The rule: if a number appears more than once, or if changing it would require a hunt through the file, it should be a named constant or tied to a reference value. Future-you will be grateful.
📏 Lesson 2 — Tie Sizes to the Canvas
Jackson's Stage 1 sketch created a 800×600 canvas and drew
every object at fixed pixel coordinates. Resize the window and the
illusion breaks — the Moon orbit extends beyond the edge, the
station disappears, the Earth shrinks to a dot.
The fix: express every size as a fraction of canvas width/height.
| ❌ Fixed pixels | ✅ Canvas-relative |
|---|---|
drawEarth(200);translate(300, 0); // Moon orbitrect(0, 0, 30, 10); // station core
|
drawEarth(width * 0.25);translate(width * 0.4, 0);let coreW = width * 0.05;rect(0, 0, coreW, coreW * 0.33);
|
Now the whole scene scales proportionally: small canvas, small scene; large
canvas, large scene. The template’s resize handler calls
myResizeCanvas() automatically, so students get responsive
sketches for free.
🔄 Lesson 3 — push/pop, rotate & translate for Orbits
Jackson’s original sketch handled orbits by calculating
x = cx + r*cos(angle) and y = cy + r*sin(angle)
manually. That works for simple circular paths, but it makes
keeping things upright (like the space station) and
offsetting objects from an orbit center very complicated.
Stage 2 uses p5.js’s transformation stack instead. Here is how the Moon orbit and the station upright correction both work:
| Step | What it does |
|---|---|
push(); |
Save the current coordinate system so we can restore it later. Think of it as “bookmarking this spot.” |
translate(width/2, height/2); |
Move the origin (0,0) to the centre of the canvas — Earth’s orbital centre. |
rotate(angle * 0.3); |
Spin the coordinate system. Now “outward” means along the current angle. |
translate(width * 0.4, 0); |
Step outward along the (now-rotated) x-axis. This is the orbit radius. |
| draw the Moon here | Drawing at (0,0) now places the Moon at the right position in its orbit. |
pop(); |
Restore the saved coordinate system. The Moon’s transform vanishes; the next object starts fresh. |
Keeping the station upright adds one extra step:
after rotate(angle) places us on the orbit, we apply
rotate(-angle) to cancel that rotation for the
station’s own coordinate frame. The net rotation on the station is
zero — it always faces “up.” This trick is used in games,
satellites, and camera rigs everywhere.
The golden rule: every push() must
have a matching pop(). Missing one causes every subsequent
object to inherit the orphaned transform — a notoriously tricky bug.
🌍 Lesson 4 — Better Land Masses: Polar Jitter vs Hard-Coded Vertices
Stage 1 defined each landmass as a fixed list of vertex()
calls placed at hand-typed x, y pixel coordinates. Every continent
was the same shape every time, placed at the same spot
every time. Worse, the coordinates were relative to the screen,
not to the Earth’s rotating surface, so they didn’t rotate with it.
Stage 2 generates land masses algorithmically, in three steps:
-
Polar jitter blobs —
each landmass is a closed polygon whose vertices are placed around a
small circle at angle
j * TWO_PI / numPts, then nudged outward/inward by a random multiplier. The result is an organic, irregular blob that looks like a real continent outline. - Bounded placement — each blob’s centre is placed at a random distance from Earth’s centre, clamped so the farthest vertex cannot exceed Earth’s radius. No more landmasses spilling over the ocean edge.
-
Stored in an array, drawn with the rotating frame —
landmasses are generated once in
initLandMasses(r)and stored in thelandMassesarray. They are drawn inside therotate(earthRotation)block, so they orbit Earth’s axis naturally without any extra math.
The lesson: when a shape needs to be “random but constrained,” polar coordinates (angle + radius) are almost always the right tool. Cartesian (x, y) forces you to calculate boundaries manually; polar makes constraint trivial — just clamp the radius.
📜 Source Code
Loading jacksonOrbit1Sketch.js…
Loading jacksonOrbit1.html…
💪 Try It Yourself
Use the Copy buttons above to grab either file, then try these challenges:
-
Canvas resize test —
open
jacksonOrbit1.htmlin your browser, then resize the window. Notice how Earth, Moon, and the station all scale together. Now openorigHTML.html(Stage 1) and do the same. Can you see the difference? -
Change the orbit speed —
in
jacksonOrbit1Sketch.js, findangle += 0.01;indrawMyDesign(). Change0.01to0.05and reload. How does it affect the Moon too? Why? -
Adjust the Moon's orbit radius —
find
translate(width * 0.4, 0)indrawMoon(). Change0.4to0.6. What happens? What would happen if you used a fixed pixel value like300instead? -
Break and fix upright correction —
in
drawStation(), comment outrotate(+angle);and reload. Observe the station spinning. Now uncomment it. This is the “upright correction” from Lesson 3 — you just proved it works! -
Add more landmasses —
find
let numLands = 15;ininitLandMasses(). Try30or5. Notice you only need to change one number because of Lesson 1’s named variable.
⚠️ The Copy button requires a secure context
(https:// or localhost). Viewing from a local file:// URL?
Right-click the Run link and choose “View Page Source” instead.