Repository navigation
[Fix] Date/time drop falls at the rain's own rate, on two lines - #119
Conversation
The clock fell over fifty seconds at a rate of its own, which read as a separate effect sitting on top of the rain. It now borrows the rain's motion: - js/clock.js: rainFallSpeed() mirrors rainPass.raindrop.frag.glsl (100 * raindropLength * fallSpeed * animationSpeed cells per second, each cell glyphVerticalSpacing/numColumns of the screen tall), and glyphCycleHz() turns the per-frame cycleSpeed into the same ~0.5s glyph re-roll the rain does. Each character also gets the rain's per-column 0.5x-1x speed variation, so the cascade is uneven like the rain instead of a clean diagonal. The whole effect is over in a few seconds and leaves nothing distinguishable from the background. - Split the text into two lines (date, then time), the time line peeling a beat after the date. - clockPhase() reports elapsed seconds instead of a 0..1 progress, since motion is now derived from real time and speed rather than a normalised clock.
🎬 PR Preview Deployed!Your changes are now available for testing: Preview URL: https://ap0ught.github.io/matrix/pr-119/ Test Links:The preview will be updated automatically when you push new commits. Preview deployed from commit 17b96f3 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 17b96f33ec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return { | ||
| phase: "fall", | ||
| progress: (secondsIntoMinute - CLOCK_HOLD_SECONDS) / CLOCK_FALL_SECONDS, | ||
| elapsed: secondsIntoMinute - CLOCK_HOLD_SECONDS, |
There was a problem hiding this comment.
Preserve subsecond precision in the fall elapsed time
secondsIntoMinute originates from Date#getSeconds(), so this elapsed value changes only once per second. During every fall, the 0.09-second stagger consequently releases roughly eleven characters at once, while both their positions and glyph rolls remain frozen between second boundaries, rather than moving and re-rolling at the rain's cadence. Derive elapsed time with millisecond precision before passing it to drawFall.
Useful? React with 👍 / 👎.
| export function glyphCycleHz(config) { | ||
| const { cycleSpeed = 0.03, animationSpeed = 1 } = config ?? {}; | ||
| return Math.max(0.5, animationSpeed * cycleSpeed * ASSUMED_FPS); |
There was a problem hiding this comment.
Derive glyph cadence without the fixed 60 Hz floor
This calculation cannot match the renderer outside the assumed default: the shader advances its glyph age on each animation tick, so a 120 Hz display cycles twice as quickly as this overlay, while animationSpeed=0 freezes the shader but the Math.max(0.5, ...) floor keeps the overlay changing. The cadence should track the renderer's actual updates and be allowed to reach zero instead of imposing a 60 Hz conversion and minimum rate.
Useful? React with 👍 / 👎.
| const y = headerY + age * rainFallSpeed(this.config, height, columnSpeedOffset(i)); | ||
| if (y - this.trailLength * step > height) { | ||
| continue; // Gone; the rain below takes over. |
There was a problem hiding this comment.
Keep slow rain presets from resetting the drop mid-screen
For slow supported configurations, the rate-based fall cannot finish before the minute rolls over, at which point clockPhase immediately redraws the next clock at the header and discards the in-flight glyphs. For example, the built-in paradise preset (fallSpeed=0.02, raindropLength=0.4, numColumns=40) moves its slowest columns only 10 px/s on a 1000 px viewport, so after the available 49 seconds their heads are still around mid-screen and their trails are far from clear. Preserve outstanding drops across the minute boundary or otherwise account for rates that require longer than one minute.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Whole-second animation timing and incorrect renderer-speed calculations prevent the overlay from reliably matching the background rain.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Refines #118’s date/time overlay so it uses two lines and visually blends into the digital rain while falling.
Changes:
- Splits date and time into separate lines.
- Derives fall speed and glyph cycling from renderer configuration.
- Updates clock tests and documentation.
| File | Description |
|---|---|
js/clock.js |
Implements two-line, rain-paced falling animation. |
tests/clock-phase.test.mjs |
Tests formatting, timing, speed, and glyph cadence. |
tests/matrix-clock.spec.js |
Updates browser fall-position assertions. |
README.md |
Documents the revised overlay behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const cellsPerSecond = 100 * raindropLength * fallSpeed * animationSpeed * columnSpeedOffset; | ||
| return cellsPerSecond * ((glyphVerticalSpacing / numColumns) * viewportHeight); |
| const y = headerY + eased * (height + fontSize * 2); | ||
| const head = scrambledGlyph(i, tick); | ||
| const step = fontSize * 1.05; | ||
| const y = headerY + age * rainFallSpeed(this.config, height, columnSpeedOffset(i)); |

Summary
Follow-up to #118, from watching it on the phone: the clock was reading as a separate effect sitting on top of the rain, and the user asked for two things —
Changes
js/clock.jsrainFallSpeed()mirrorsshaders/glsl/rainPass.raindrop.frag.glsl:100 * raindropLength * fallSpeed * animationSpeedcells per second, each cellglyphVerticalSpacing / numColumnsof the screen tall (the grid is square — seejs/webgl/rainPass.js), scaled bycolumnSpeedOffset. The whole fall now takes a few seconds instead of dragging on for fifty.glyphCycleHz()turns the per-framecycleSpeedinto the same ~0.5s glyph re-roll the rain does (1.8 rolls/s at the defaults), and each character also gets the rain's per-column 0.5x–1x speed variation, so the cascade is uneven like the rain rather than a clean diagonal.SCRAMBLE_CHARSET) for both the heads and the trails.THU 01 OCT 2026over21:39:00— with the time line peeling a beat after the date so they don't read as one block.clockPhase()reportselapsedseconds instead of a 0..1progress, since the motion is now derived from real time and the rain's speed.The effect is now: 10s hold, ~7s fall, then nothing distinguishable from the rain.
Testing
tests/clock-phase.test.mjs—clockLinesreturns the two lines (with zero padding);rainFallSpeedmatches the raindrop maths, scales with viewport/speed settings/column offset and lands in a rain-like range for a phone screen;glyphCycleHzmatches the symbol pass;clockPhaseboundaries and monotonic elapsed.tests/matrix-clock.spec.js— the fall test now samples three seconds in (the fall is fast), everything else unchanged.npm test— 21 passed, 2 skipped (WebGPU unavailable here)npx prettier --check --use-tabs --print-width 160Notes
npm testrun (its red/green assertion is timing sensitive under load) and passed on a rerun and in isolation.