Eye 8 added pupil constraints to SWEyeball — the pupil can no longer be dragged outside the sclera. Try it: drag a pupil all the way to the edge and beyond. It stays inside.
The compelling part is what didn’t change: the sketch is identical to Eye 7.
Same constructor calls, same drawOnGrid(), same handle* delegation. The sketch had no idea the constraint was even added.
Big Idea 1 — The Sketch Didn’t Change
Compare eye7Sketch.js and eye8Sketch.js side by side — they are the same file.
The behavior improved; the producer of that behavior (SWEyeball) changed; the consumer of that behavior (the sketch) did not.
This is encapsulation fulfilling its core promise.
Big Idea 2 — Where the Constraint Lives
The clamping logic lives inside SWEyeball.handleMouseDragged().
It converts the mouse position to user coordinates, computes the
offset from the eye center, and clamps the magnitude to
(eyeRadius - pupilRadius) so the pupil edge never crosses the sclera edge.
Both eyes get this behavior automatically because it is written once, in the class.
Big Idea 3 — What Stage 6 Would Have Required
In the procedural Stage 6, adding this constraint would have meant
writing clamping logic twice in the sketch — once for the left eye
and once for the right. Any future third or fourth eye would require
another copy. With the class, the fix is written once and every instance
inherits it immediately.
Big Idea 4 — Open/Closed in Practice
This is the Open/Closed Principle made visible:
SWEyeball was open for extension (new constraint behavior was added)
without being closed for modification to its consumers.
The sketch — the existing consumer — required zero changes.
Every professional codebase aims for exactly this kind of change:
new capability, no ripple.