Ace Alley
Play: https://zerowing.in/games/ace-alley/
1v1 street tennis on public city courts, in a clay 3D diorama built with Three.js in a single HTML file. Fifth game in the street-sport family (Galli Cricket, Panna Cage, Block Hoops, Sand Spike).
Courts
- Paris clay: red clay between cream Haussmann buildings with balconies and zinc mansard roofs, a café terrace at the end of the court. Clay is slow and the ball sits up high. Every bounce leaves a ball mark, and on a close line call the umpire climbs down: MARK CHECK! A zoomed ring shows the mark and the mark decides the call.
- Queens, New York: green hard court under the elevated 7 train, chain-link fence, brick walk-ups, a hot-dog cart. Every so often the train rumbles overhead (camera shake, train on the tracks). The point played while it passes is a SUBWAY POINT worth double: win it and you score two points.
- Tokyo rooftop: blue court behind tall safety netting, neon signs, a water tower, the skyline. A ball hit over the netting is lost: the hitter loses the point and the next serve goes to the opponent (OFF THE ROOF!). A gust indicator (chip and windsock) shows the wind that pushes lobs.
Rules
Real tennis scoring, shortened: 0, 15, 30, 40, deuce, advantage; first to 3 games wins the match (points and games are on the scoreboard). Serve from alternating sides (deuce and ad court) into the diagonal service box; two serves per point (fault, double fault); a serve that clips the net cord and lands in is a let and is replayed. The ball must bounce once, in; in/out calls on the lines, ball into the net loses the point. The server alternates every game. A match runs about 4 to 6 minutes.
Controls
One main button plus a lob button.
- Move: WASD or arrows, or the floating left stick. Stand beside the ball.
- SWING (Space / Enter): press as the ball reaches you. Timing sets the shot, PERFECT / GOOD / LATE: early goes cross-court, late goes down the line, the stick nudges the aim (and depth, or a drop shot if you pull back). Hold briefly for a power drive, tap near the net for a volley; a high ball becomes a smash.
- LOB (Shift / Right Shift, or the small touch button): lob over a player at the net.
- Serve: hold SWING to toss and power up, let go just inside the line (the ring on the court shows where it lands), the stick aims wide, body or T. Too much power is a fault.
- 1 player: vs an AI that covers the court, mixes cross-court and down-the-line, comes to the net, lobs and is beatable. 2 players (one keyboard): P1 WASD + Space + Left Shift, P2 arrows + Enter + Right Shift.
- Phone (landscape): floating left stick, big SWING / SERVE / VOLLEY / SMASH button, LOB button, pause button. 2 players needs a keyboard.
- T cycles time of day (day, golden, night, rain), M mutes, P toggles the pixel look, Esc pauses, R returns to the menu.
Testing hooks
window.__ace exposes state, score, ball, players, setLocation, setTime, startGame, bot, aiBoth, speed, sim(seconds), step(n). Set __ace.bot = true to let a scripted player drive your side, or __ace.aiBoth = true to let the AI play both sides; sim() runs the game headless (no rendering, no sound).
Development
Edit game.html, then run ./build.sh to regenerate index.html.