Beginner / Game loop
Move a Timing Target with a Sine Wave

Timing Tap moves its ring without storing a separate horizontal velocity or bouncing it off invisible walls. The position comes directly from elapsed time through a sine function. This makes the path easy to inspect and exposes useful parameters for difficulty.
What you'll build
We will break the actual ring equation into center, amplitude, and angular speed. Then we will calculate a few positions and describe how changing each term affects play. The live example uses the same equation discussed here.
Prerequisites
Know elapsed seconds and basic JavaScript arithmetic. You do not need to remember trigonometry identities. Read the update function in timing.js and the shared logical width in core.js.
Start with the normalized wave
Math.sin returns a value between minus one and one. Multiplying it by an amplitude creates a symmetric offset. Adding a center shifts that offset into the playfield.
const center = 960 / 2;
const amplitude = 960 / 2 - 80;
const angularSpeed = 1.8 + difficulty * 0.2;
const ringX = center + Math.sin(time * angularSpeed) * amplitude;
These are the terms used by the current engine, separated for explanation. At time zero the sine is zero, so the ring begins at the center. Its horizontal center ranges from 80 to 880, leaving room for the ring's 35-unit radius inside the 960-unit arena.
Understand angular speed
The argument to Math.sin is measured in radians. A full cycle spans 2 * Math.PI, so the approximate cycle duration is that value divided by angular speed. Increasing the difficulty term makes cycles shorter without changing their horizontal extent.
Calling the coefficient “pixels per second” would be inaccurate. The ring does not move at constant speed. It moves fastest near the center and slows near each end before reversing direction. That variation is part of what the player learns to anticipate.
A triangle wave or constant-velocity bounce would create a different timing challenge even if the endpoints were identical. The shape of motion is a gameplay choice, not merely an implementation detail.
Derive position from time rather than accumulating it
Because position is calculated from accumulated simulation time, the engine does not add a horizontal displacement to the old ring position. There is no gradual position drift from repeatedly reflecting a velocity at endpoints.
This does not make the entire game deterministic across devices. Input timing, delta clamping, and scheduling still matter. It simply means the ring's position is a direct function of the current model time and difficulty.
Pause preserves that time and stops updates, so the ring remains in place. Resume establishes a fresh scheduler origin and continues the wave from the preserved phase. Reset sets time back to zero and returns to the center.
Keep the hit rule separate
The ring's visible radius does not define a successful tap. Timing Tap checks whether the ring center lies within the highlighted zone's half-width. A ring edge overlapping the zone can therefore still be a miss.
This distinction is important when changing amplitude or drawing size. Making the ring visually larger does not currently widen the allowed center window. If you want edge overlap to count, change the hit rule explicitly and update the instructions.
The zone narrows as difficulty rises while angular speed increases. Those two adjustments compound: the center spends less time in a smaller acceptable region. Test their combined effect rather than judging each parameter alone.
Check known positions
At time zero, verify the center is 480. At a phase of Math.PI / 2, the sine reaches one and the center is 880. At a phase of 3 * Math.PI / 2, it is 80. Convert those phases back to time using the chosen angular speed for a repeatable test.
Also verify the ring never leaves its intended bounds during several cycles. A mistaken center or amplitude can still look plausible near the first crossing but move outside the canvas later.
Next steps
Open Timing Tap's source and plot a few positions before changing the equation. In a local extension, compare sine motion with a constant-speed bounce while leaving the same hit zone. Describe the resulting difference in timing opportunities rather than assuming that equal endpoints create equivalent difficulty.