Add a pong animation
The video frame plays the paddle: it slides along the bottom of the screen and nowhere else, a square ball runs the diagonals off the walls, and every ball that gets past the frame puts one on a seven-segment counter in the top right. The frame is solid on all four sides, not just its face, so a ball that comes at its flank or up under it is turned away too. Which side a hit came in on is read from where the ball was before the step, with a shallowest-penetration fallback for the frame sliding into the ball rather than the other way round — without that the ball tunnels in and rattles inside the frame. The face keeps the original's angle rule, where the hit position sets the departure angle, so rallies develop instead of the ball retracing one line; the other three sides are plain reflections. The paddle steers by predictLanding, which unfolds the wall reflections analytically instead of simulating them. A paddle that outruns the ball never loses, so PONG_MISS_CHANCE of the time it aims a width wide and lets one through — otherwise the counter would sit on 00 all night. The digits are SVG polygons built from a segment map, so the era-correct display costs no font file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9v2Xoa6eoeGYpK6gp95k9
This commit is contained in:
@@ -152,6 +152,67 @@ body {
|
||||
transform: scale(0.82);
|
||||
}
|
||||
|
||||
/* --- pong --------------------------------------------------------------- */
|
||||
|
||||
/* Built and removed by the pong animation. Above the frame, so the ball is
|
||||
never hidden behind the paddle it is bouncing off. */
|
||||
#pong {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#pongBall {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
/* Square, and no smoothing: the original had no room for a round ball. */
|
||||
box-shadow: 0 0 18px rgba(255, 79, 195, 0.7);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* Out of play between a goal and the next serve. */
|
||||
#pongBall.out {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#pongScore {
|
||||
position: absolute;
|
||||
top: clamp(16px, 4vh, 56px);
|
||||
right: clamp(16px, 4vw, 72px);
|
||||
display: flex;
|
||||
gap: 0.35em;
|
||||
font-size: clamp(2.5rem, 7vh, 6rem);
|
||||
}
|
||||
|
||||
#pongScore .digit {
|
||||
display: block;
|
||||
height: 1em;
|
||||
/* The viewBox is 24 wide by 44 tall. */
|
||||
width: calc(1em * 24 / 44);
|
||||
}
|
||||
|
||||
/* An unlit segment stays visible, just barely — that faint ghost of the whole
|
||||
figure eight is what makes the display read as a seven-segment one. */
|
||||
#pongScore .segment {
|
||||
fill: rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
#pongScore .segment.lit {
|
||||
fill: #fff;
|
||||
filter: drop-shadow(0 0 10px rgba(255, 79, 195, 0.8));
|
||||
}
|
||||
|
||||
/* The paddle: a hard-edged slab, so the ball has something square to hit. */
|
||||
#frameMover.paddle #frameSkin {
|
||||
border-radius: 0;
|
||||
box-shadow:
|
||||
0 0 0 3px #fff,
|
||||
0 0 34px rgba(255, 79, 195, 0.6);
|
||||
}
|
||||
|
||||
.deck {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
Reference in New Issue
Block a user