How a Bouncing Screensaver Calculates Collisions

A convincing bouncing screensaver is a small physics problem. The object must travel at a consistent speed, touch the visible bounds cleanly, preserve excess movement after a collision, adapt to resizing, and count a corner only when horizontal and vertical walls are reached together. Tying movement to “pixels per frame” fails as soon as the refresh rate or browser workload changes.
The minimum state
For a rectangular object, store position (x, y), velocity (vx, vy), object width and height, and viewport width and height. If the top-left corner represents position, valid bounds are:
0 ≤ x ≤ viewportWidth - objectWidth
0 ≤ y ≤ viewportHeight - objectHeight
The badge must collide by its visible box, not by a single center point. Changing badge size therefore changes the maximum x and y values.
Use elapsed time, not an assumed frame rate
The browser supplies a high-resolution timestamp to a requestAnimationFrame callback. Subtract the previous timestamp to get elapsed milliseconds and convert it to seconds:
dt = min((now - previous) / 1000, maximumStep)
x = x + vx * dt
y = y + vy * dt
Velocity is expressed in pixels per second. A 60 Hz display and a 144 Hz display then cover approximately the same distance over the same real time. Clamping dt prevents a huge jump if execution resumes after debugging or a stalled foreground frame. The page also cancels its own loop when hidden rather than relying solely on browser throttling.
Reflect overshoot at a wall
A simple implementation sets x to the boundary and negates vx. That discards the distance traveled beyond the wall and makes motion slightly uneven. Reflecting the overshoot preserves it:
if (x < 0) {
x = -x
vx = abs(vx)
}
if (x > maxX) {
x = maxX - (x - maxX)
vx = -abs(vx)
}
Apply the equivalent logic vertically. With a sensible maximum time step, one reflection per axis is normally sufficient. A more general engine can loop while a very large overshoot remains outside the bounds.
What counts as a corner hit?
During one simulation step, record separate booleans for a horizontal collision and vertical collision. Increment the corner counter only when both become true in that same step. Do not test floating-point equality such as x === 0 && y === 0; the reflection step already knows a crossing occurred.
The probability of a corner hit depends on starting position, velocity ratio, and dimensions. A perfectly repeating discrete path can miss corners indefinitely. Resizing or changing object size alters the path, so a counter should reset or clearly preserve its semantics.
Details that make the implementation feel polished
- On resize, clamp position into the new bounds without teleporting to an unrelated random point.
- Change collision color only on an actual wall event, not continuously from x/y position.
- Keep custom-image aspect ratio and reject files beyond documented type and size limits.
- Keep visible Pause and Reset controls predictable, and let Escape leave fullscreen.
- Respect reduced motion and stop rendering in a hidden tab.
- Cap device pixel ratio for Canvas work so a high-density phone does not allocate an excessive surface.
Try the behavior in the Bouncing DVD Screensaver. Its default mark stays crisp while custom local images never leave the device.
Technical references
Choose a velocity vector
A speed slider normally represents magnitude, while direction comes from a normalized vector. For an angle θ and speed s:
vx = cos(θ) * s
vy = sin(θ) * s
A direction that is exactly horizontal or vertical never explores the full surface, so the initial angle should avoid values too close to multiples of 90 degrees. Randomizing x and y velocity independently can also produce an almost-flat path if one component is tiny. Generate an angle from an allowed range, then derive both components.
The ratio between horizontal and vertical velocity influences whether the path repeats. In ideal continuous geometry, a corner occurs when the travel times to an x boundary and a y boundary coincide. Finite dimensions and floating-point steps make exact position equality unreliable, which is why collision events, not coordinate equality, drive the counter.
Handle large time steps and multiple reflections
Clamping elapsed time protects ordinary animation, but a reusable engine can also handle an object crossing more than one wall during a large step. After moving, repeatedly reflect any out-of-range coordinate until it lies within bounds. The loop needs a strict iteration limit in case malformed state creates an impossible range.
function reflect(position, velocity, maximum) {
let hits = 0
while ((position < 0 || position > maximum) && hits < 8) {
if (position < 0) {
position = -position
velocity = Math.abs(velocity)
} else {
position = maximum - (position - maximum)
velocity = -Math.abs(velocity)
}
hits++
}
return { position: clamp(position, 0, maximum), velocity, hits }
}
The production screen uses a conservative maximum time step and pauses when hidden, so multi-wall jumps are exceptional. Defensive handling still makes reset, debugger pauses, and unusual browser scheduling safer.
Collision events power more than direction
Once the engine reports horizontal and vertical hits, the renderer can change badge color, increment total collisions, play an optional user-enabled sound, or update the corner count. These side effects should occur once per event. Deriving color continuously from position creates a rainbow movement effect and no longer communicates collision.
Sound remains off by default and requires an interaction because browser autoplay restrictions and user comfort matter. Rapid collisions at very high speed should be rate-limited so sound and status announcements do not become overwhelming.
Trails require a deliberate clearing model
A crisp frame clears the entire Canvas and draws one badge. A trail instead covers the previous frame with a translucent background before drawing the next badge. Lower alpha preserves marks longer. Because perceived trail length also depends on speed and frame rate, define it in a way that remains visually stable and disable it under reduced motion if the effect is distracting.
On DOM-based animation, a trail might be a bounded pool of fading elements. Do not append a new node forever; that leaks memory and eventually harms interaction performance.
Custom text and images alter collision bounds
Text width depends on font, content, weight, and device rendering. Measure after the font is available, add intentional padding, and recalculate maximum x/y. Limit text length so it cannot become wider than the viewport. If the badge is larger than a dimension, scale it down or center it rather than allowing negative bounds.
A local image must be decoded before its intrinsic dimensions are trusted. ScreenOrbit accepts only PNG, JPEG, and WebP within 5 MB and 4096 pixels per side, checks the decoded dimensions, preserves aspect ratio, and releases the temporary object URL. It rejects SVG and HTML rather than attempting to sanitize active or unexpectedly complex local content.
Resize without losing the object
When the viewport changes, calculate new bounds and preserve relative location where possible:
ratioX = oldMaxX > 0 ? x / oldMaxX : 0.5
ratioY = oldMaxY > 0 ? y / oldMaxY : 0.5
x = clamp(ratioX * newMaxX, 0, newMaxX)
y = clamp(ratioY * newMaxY, 0, newMaxY)
This is smoother than selecting a random position after every mobile address-bar change or orientation event. A resize is not a collision and should not increment counters or change color.
Canvas pixels and CSS geometry
CSS dimensions define movement bounds. The Canvas backing buffer can be larger for a high-density display: multiply by a capped device pixel ratio and scale the drawing context so coordinates remain in CSS units. Without the scale, physics and rendering use different units; without the cap, a 4× phone can allocate sixteen times the pixel area.
For an image or text object that can be represented as HTML, transform-based DOM animation is also possible. Canvas gives predictable scene composition and still export, while DOM may offer simpler semantics. The choice does not change the need for elapsed-time movement and lifecycle cleanup.
Pause, visibility, and fullscreen lifecycle
Maintain one animation-loop identifier. Starting while already running must not schedule a second loop. Pause cancels the pending callback and records the state; resume establishes a fresh previous timestamp so the hidden duration is not treated as movement. The visibility handler follows the same rule.
Fullscreen is a presentation state, not an animation requirement. A rejected or unsupported fullscreen request should leave the embedded preview working. On exit, recalculate bounds after the viewport settles. Wake Lock is requested separately and released when the page is hidden; failure never blocks the animation.
Test the engine, not just one attractive run
- Direct hits on left, right, top, and bottom walls
- Simultaneous x/y collision and one corner increment
- Near-corner impacts that occur in adjacent steps and do not count
- Overshoot reflection preserving distance and sign
- 60, 120, and 144 Hz timestamp sequences producing equal travel over equal time
- A long paused interval followed by resume without a teleport
- Resize to smaller than the current position and to smaller than the chosen object
- Local image rejection by type, byte size, decoded dimensions, and failed decode
- Repeated reset/start cycles with one active callback and no retained object URL
- Reduced-motion, keyboard pause, fullscreen denial, and hidden-tab behavior
Automated tests cover the arithmetic and state transitions; Playwright covers browser lifecycle and responsive geometry. A thirty-minute manual stability run checks that Canvas size, memory, and loop count remain stable.
Accessibility beyond reduced motion
Pause, Reset, and Fullscreen need visible keyboard focus and text labels in the normal page view. Collision counts should not be announced on every hit to a screen reader; that would create unusable chatter. Status announcements are reserved for meaningful control changes. Touch targets remain at least 44 by 44 CSS pixels, and the embedded preview does not steal keyboard operation from surrounding controls.
Why a corner can take so long
In a perfectly deterministic rectangle, position and velocity can produce a repeating orbit. Depending on the ratio of effective travel width to height and velocity components, that orbit may encounter a corner quickly, only after many bounces, or not at all within practical time. Pixel rounding, resizing, changing badge size, and speed adjustments alter the path.
The rarity is part of the appeal. The counter is an honest event record, not a timer designed to manufacture a corner. Reset makes the starting state known; it does not promise a hit.
Use this page for one clear task
Explain frame timing, wall collision, resizing, and corner-hit rules behind the bouncing scene. Web developers, students, streamers, and curious users use this guide to verify visible animation behavior. Write down the result you need before you follow a link or change a setting. A narrow goal saves time and keeps the final decision tied to evidence.
Read the full page once before acting when the task involves a display test, cleaning step, simulation, file right, privacy request, or support report. Then return to the exact section needed for the work. Keep the stated limits visible while you decide the next step. This route focuses on: Explain frame timing, wall collision, resizing, and corner-hit rules behind the bouncing scene.
Prepare a stable starting point
Choose a fixed viewport, badge size, speed, and starting point before comparing runs. Record the starting state before you change a control, move a device, submit a form, or rely on a policy statement. Use current source material and the current page version for any formal review.
Keep one issue per session or message. Separate a visual symptom from a hardware claim. Separate a browser simulation from a system event. Separate a generated file from third-party material placed inside the file. These boundaries make the evidence easier to assess. The main route risk is: Frame-count motion runs at different speeds on 60 Hz and 120 Hz displays.
Follow a practical four-part process
- Define the goal. Explain frame timing, wall collision, resizing, and corner-hit rules behind the bouncing scene. Stop if the task changes into a different problem.
- Capture the baseline. Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event. Use exact values and names where they exist.
- Check the main risk. Frame-count motion runs at different speeds on 60 Hz and 120 Hz displays. Correct the setup before repeating the step.
- Choose the next action. Open DVD Screensaver, change one control, and compare the live counter with the formulas in the guide. Keep the original record for comparison.
Build evidence another person understands
Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event. Add the date and the page URL. Remove passwords, addresses, serial numbers, payment data, private messages, and confidential logs before sharing a screenshot or report. A short written sequence often carries more value than one close photograph.
For a comparison, repeat the same order and keep every unrelated variable stable. For a policy or rights question, quote the exact file or clause in your own words and link the source. For a bug, include expected behavior, observed behavior, and the smallest reliable reproduction path. This route asks you to record: Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event.
Avoid weak evidence and unclear claims
- Frame-count motion runs at different speeds on 60 Hz and 120 Hz displays.
- A browser animation demonstrates geometry and timing. The page does not model physical friction or impact.
- Avoid several setting changes between the baseline and the result. Preparation for this route: Choose a fixed viewport, badge size, speed, and starting point before comparing runs.
- Avoid a private or model-specific claim without a current primary source. The page limit is: A browser animation demonstrates geometry and timing. The page does not model physical friction or impact.
- Avoid private data in public screenshots, links, examples, and support messages. The useful evidence is: Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event.
- Avoid treating a search result, camera image, or forum comment as final proof. The main risk is: Frame-count motion runs at different speeds on 60 Hz and 120 Hz displays.
Move to the next useful action
Open DVD Screensaver, change one control, and compare the live counter with the formulas in the guide. Keep the baseline and the page limit beside the result. Contact the relevant maker, seller, platform, specialist, rights holder, or ScreenOrbit editor when the decision falls outside the page scope.
Questions about How a Bouncing Screensaver Calculates Collisions
What is the main purpose of How a Bouncing Screensaver Calculates Collisions?
Explain frame timing, wall collision, resizing, and corner-hit rules behind the bouncing scene. The page keeps the task narrow so you reach a useful next action without mixing unrelated intent.
Who should use How a Bouncing Screensaver Calculates Collisions?
Web developers, students, streamers, and curious users use this guide to verify visible animation behavior. Start with the stated task and use the linked route or policy for the next decision.
What should you prepare before following How a Bouncing Screensaver Calculates Collisions?
Choose a fixed viewport, badge size, speed, and starting point before comparing runs. Keep the starting state stable and write down any change you make during the process.
What information should you record for How a Bouncing Screensaver Calculates Collisions?
Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event. Specific details help another person repeat the same check or review the same request.
What common error weakens the How a Bouncing Screensaver Calculates Collisions result?
Frame-count motion runs at different speeds on 60 Hz and 120 Hz displays. Pause when the context changes and restart from a known state rather than guessing.
What does How a Bouncing Screensaver Calculates Collisions exclude?
A browser animation demonstrates geometry and timing. The page does not model physical friction or impact. Use the stated limit when deciding whether you need a maker, specialist, platform, or legal contact.
Does ScreenOrbit store settings from How a Bouncing Screensaver Calculates Collisions?
Interactive tool settings stay in local browser storage where supported. Supported files stay in the tab. A contact message follows the separate contact and privacy process. Page scope: Explain frame timing, wall collision, resizing, and corner-hit rules behind the bouncing scene.
Does How a Bouncing Screensaver Calculates Collisions work on phones and computers?
The written steps work across screen sizes. Browser features differ by device. Fullscreen, downloads, Wake Lock, file access, and audio depend on current browser support. Preparation: Choose a fixed viewport, badge size, speed, and starting point before comparing runs.
How often should you repeat the How a Bouncing Screensaver Calculates Collisions process?
Repeat after a meaningful change such as a new device, display preset, browser, room condition, source, policy revision, or software release. Keep stable conditions for direct comparisons. Record: Record viewport size, device pixel ratio, elapsed time, position, velocity, collision count, and resize event.
What should you do after How a Bouncing Screensaver Calculates Collisions?
Open DVD Screensaver, change one control, and compare the live counter with the formulas in the guide. Follow the closest linked route and keep the original goal, evidence, and limits in view.