You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In P5.js 2D mode, `(0, 0)` is the **top-left** corner of the canvas. The Y axis increases **downward**. This is the opposite of standard mathematical convention where Y increases upward, and it causes subtle bugs when reasoning about "height."
551
+
552
+
```text
553
+
Screen space (P5.js 2D): Mathematical convention:
554
+
555
+
(0,0) ───────► +X +Y ▲
556
+
│ │
557
+
│ │
558
+
▼ +Y (0,0) ───────► +X
559
+
```
560
+
561
+
**The trap:** A wave crest (visually the highest point on screen) has a **lower Y value** than a trough (visually the lowest point). If your code checks `yPosition > threshold` expecting to find crests, it actually finds troughs.
562
+
563
+
```typescript
564
+
// ❌ BUG: This finds troughs, not crests!
565
+
// A crest at y=100 is visually ABOVE a trough at y=300,
566
+
// but 300 > 100, so the trough passes the threshold check.
567
+
function isCrest(yPosition:number, threshold:number):boolean {
568
+
returnyPosition>threshold;
569
+
}
570
+
571
+
// ✅ OPTION A: Invert the comparison for screen-space values
572
+
function isCrest(yPosition:number, threshold:number):boolean {
573
+
returnyPosition<threshold; // Lower Y = higher on screen = crest
574
+
}
575
+
576
+
// ✅ OPTION B (preferred): Work in logical space, convert at render time
577
+
// In logical space, positive = up (like math convention)
578
+
function calculateWaveHeight(x:number, time:number, config:Config):number {
579
+
// Returns positive values for crests, negative for troughs
return (noiseVal-0.5) *2*config.amplitude; // Range: -amplitude to +amplitude
582
+
}
583
+
584
+
// Only flip to screen space when drawing
585
+
function logicalToScreenY(logicalY:number, baseline:number):number {
586
+
returnbaseline-logicalY; // Subtract because screen Y is inverted
587
+
}
588
+
```
589
+
590
+
**Option B is preferred** because it keeps all calculation logic in intuitive mathematical space (positive = up, crests are positive, troughs are negative). The inversion happens once at the rendering boundary, not scattered through calculation functions. This also makes unit tests more intuitive: you can assert that crests produce positive values without thinking about screen coordinates.
591
+
592
+
**Checklist for new animations:**
593
+
594
+
-[ ] Calculation functions work in logical space (positive = up)
595
+
-[ ] Screen-space conversion happens at render time, not in utility functions
596
+
-[ ] Threshold comparisons make sense in the coordinate space being used
597
+
-[ ] Test names and assertions use "crest" and "trough" to make intent clear
598
+
-[ ] JSDoc on functions states which coordinate space the return value is in
0 commit comments