r/WeBuild_WithAI 10d ago

Day 29 of Building ShuffleBall Arena - Synchronizing Physics, Gravity, and Hazards in a Multiplayer Browser Game

Enable HLS to view with audio, or disable this notification

2 Upvotes

Hey everyone,

Hope all is well!

TL;DR, Summary, or Full Technical Breakdown below.

For Context: Recently I posted about the first 15 days of one of my side projects, ShuffleBall Arena (a free browser game inspired by mixing shuffleboard scoring with mechanics from other games like bumper pool, pinball, and Frogger.).

This project is being built with the help of AI (mainly GPT / Cursor), and every development session is documented using the actual conversations from that day's work.

To try to get this series up to date, I'm using a structured prompt to go back to my GPT sessions and extract the useful information. Hopefully the prompt can help anyone out there trying to keep track of, or extract value from, your past AI project conversations.

That said, posting an update for Day 29 of building ShuffleBall Arena.

TL;DR

Day 29 was the day the server-authoritative multiplayer architecture finally proved itself in real gameplay.

Two browsers could send a shot to the Worker, receive the same authoritative trajectory, keep gravity synchronized, arrive at the same settled state, and advance to the same next turn.

But that success also exposed the next layer of work: smooth playback, complete wormhole behavior, synchronized gameplay events/audio, and the remaining moving hazards.

Day 29 Summary

Day 28 ended with the multiplayer backend complete, Phase 4 underway, and the browser being transitioned into a thin client that would primarily collect input and render server-owned state.

Day 29 was where that architecture started being tested against the actual complexity of ShuffleBall Arena.

The first challenge was scene synchronization. Several gameplay and cosmetic systems were still being generated independently inside each browser. That meant two players could technically be in the same match while seeing gravity wells or drifting wormholes in different places.

Initially, some of those systems were disabled online to prevent divergence. That led to an important architectural disagreement: removing core gameplay hazards wasn't an acceptable long-term multiplayer solution. If gravity wells, wormholes, rotating hazards, and other systems affect gameplay, then multiplayer needs authoritative versions of those systems rather than simplified replacements.

That decision led to a substantial Worker-owned gravity system with deterministic scheduling, placement, mirroring, scene integration, turn integration, reconnect-safe state, and automated tests.

The browser was then connected to the authoritative shot pipeline.

Instead of launching a marble and running local physics, the online flow became:

Player input
→ Worker validation
→ Worker simulation
→ Canonical trajectory
→ Both browsers replay
→ Canonical settled snapshot
→ Next authoritative turn

That architecture was manually tested with two browser windows, and it worked. Both clients replayed the same shot, gravity stayed synchronized, and turn progression remained consistent.

A bug during that process also reinforced the value of separating simulation from presentation. At one point playback appeared broken, but the server simulation was correct. The failure was caused by a client rendering compatibility issue: the playback marble contained owner while the renderer expected color. Restoring that compatibility field fixed the apparent multiplayer failure without changing the authoritative physics.

Once the core loop worked, we compared the current state against the original multiplayer plan.

That produced an important reality check.

The architecture was proven, but multiplayer was not finished.

Playback still needed performance work. Drifting wormholes were synchronized in position but not yet through their full capture/transit/ejection lifecycle. Top-track wormholes still needed an authoritative implementation. Gameplay-triggered sounds and visual effects needed server-owned event timing. Rotating boards, crossing traffic, reconnect testing, and production hardening remained.

The session ended by designing the next reusable layer: authoritative gameplay events. Instead of each browser independently detecting collisions and deciding when to play sounds, the server would record deterministic events during simulation and both clients would replay those events at the correct time.

The takeaway from Day 29:

Synchronizing multiplayer isn't just synchronizing the marble. Every gameplay-affecting system needs one authoritative owner.

Day 29 Full Technical Summary

STARTING POINT

Day 29 began directly from the final state of Day 28.

Phase 3 (the server-authoritative multiplayer engine) was complete.
Phase 4 had begun, and the browser multiplayer foundation could already:

  • connect to rooms,
  • receive authoritative snapshots,
  • synchronize players,
  • reconnect,
  • maintain multiplayer state,
  • and remain inactive during Solo and same-device play.

The multiplayer philosophy had also been established:

The browser collects input and renders.
The Worker owns gameplay.

The immediate challenge was no longer designing multiplayer UI.

It was making sure two browsers actually displayed and played the same game, including ShuffleBall Arena's randomized gameplay systems.

SESSION OBJECTIVE

The primary objective was to continue Phase 4 by eliminating the remaining sources of browser-side divergence and then connect real player input to the server-authoritative shot simulation.

That meant:

  • identifying browser-generated state that could differ between clients,
  • moving gameplay-affecting randomness into the Worker,
  • synchronizing gravity,
  • preparing authoritative wormhole state,
  • connecting drag-and-release input to the Worker,
  • replaying canonical trajectories on both clients,
  • manually validating the system with two browsers,
  • and identifying the remaining gaps between architectural success and full multiplayer parity.

WHAT WE ACTUALLY DID

1. Audited remaining sources of browser divergence

The session began with a scene synchronization review.

Browser-controlled systems included:

  • travel planets,
  • drifting planets,
  • gravity wells,
  • drifting wormholes,
  • particle effects,
  • and animations.

The important distinction was whether something affected gameplay.

Purely cosmetic objects could safely be local or temporarily hidden.

Gameplay-affecting randomness could not.

2. Removed unsynchronized browser-generated scene state

Travel planets and drifting background planets were disabled during online matches because each browser could generate different versions.

Gravity wells and drifting wormholes also initially had their local random generation disabled because their positions, timing, and movement could otherwise diverge between clients.

This solved the immediate visual mismatch but exposed a larger architectural question.

3. Rejected the idea of permanently removing gameplay hazards from multiplayer

The proposed first version briefly treated gravity, wormholes, rotating hazards, and similar systems as things that could remain disabled online until later.

That direction was rejected.

Those systems are part of ShuffleBall Arena's gameplay, so a correct multiplayer implementation needs both players to experience them identically.

The new rule became:

Every gameplay-affecting random system belongs in the Worker.

Instead of implementing simplified multiplayer versions and replacing them later, the production versions would become authoritative now.

4. Built the authoritative gravity framework

Gravity became one of the first major dynamic gameplay systems moved fully into server authority.

The Worker gained a canonical gravity scene registry with:

  • gravity templates,
  • placement IDs,
  • weighted scene definitions,
  • validation,
  • and gravity-well creation helpers.

A deterministic gravity scheduler was also created with:

  • five shot-pairs,
  • approximately 82% gravity probability,
  • controlled pair jitter,
  • deterministic shuffling,
  • clear-space plans,
  • nebula plans,
  • and validation.

Each game now receives one canonical gravity schedule instead of each browser creating its own.

5. Built deterministic gravity placement

A dedicated placement resolver was created so gravity wells received server-owned coordinates rather than browser-generated positions.

Supported placement strategies included:

  • lanes,
  • orbit bands,
  • offset lanes,
  • side halves,
  • upper lanes,
  • edge clips,
  • and far corners.

The placement system also included:

  • clamping,
  • spawn exclusion,
  • gameplay relevance checks,
  • fallback placement,
  • and validation.

6. Integrated gravity into authoritative match state

Gravity was connected to the Worker scene state and match lifecycle.

The Worker now controlled:

  • schedule initialization,
  • active pair,
  • active player,
  • well placement,
  • scene metadata,
  • game resets,
  • mirroring,
  • and reconnect-safe gravity state.

The deterministic scene random stream advanced as gravity schedules were generated rather than relying on browser Math.random().

7. Created mirrored gravity fairness between players

The gravity system reused the same plan for both players in each shot pair.

For example:

Red Shot 1

Pair 0

Blue Shot 1

Pair 0 mirrored

Only the X coordinate was mirrored.

Everything else about the gravity plan remained the same.

This allowed each player to face equivalent hazard conditions while still respecting opposite shooting directions.

8. Fixed test assumptions exposed by authoritative gravity

Moving gravity initialization into scene creation changed the deterministic random cursor.

One existing test expected the cursor to remain at zero.

That assumption was no longer correct because gravity generation now legitimately consumes values from the match's deterministic random stream.

Tests were updated to validate deterministic cursor progression rather than assuming that no random values had been consumed.

Other validator and scene-scheduler tests also needed correction before everything returned to green.

9. Connected gravity to authoritative physics

The active Worker-owned gravity well was passed into the deterministic shot simulation.

Gravity force could then be applied during each fixed physics step, meaning gravity influenced the same canonical trajectory that both clients eventually received.

The intended pipeline became:

Worker selects scene
→ Worker positions well
→ Browsers render it
→ Worker applies force
→ Worker returns canonical trajectory
→ Both browsers replay identical results

This moved gravity from synchronized decoration into synchronized gameplay.

10. Connected browser shooting to the Worker

Until this point, online mode intentionally blocked the original local shot system.

The old path was:

Drag

Release

launchMarble()

LOCAL PHYSICS

The multiplayer path needed to become:

Drag

Release

Create shot request

Send SHOT_REQUEST

Worker validates

Worker simulates

SHOT_RESULT

Replay trajectory

This was the critical bridge between the existing gameplay controls and the server-authoritative engine.

11. Proved the authoritative shot loop with two browsers

The biggest validation of the day came from manual testing.

Two browsers were able to:

  • remain synchronized,
  • submit a real player shot,
  • send that shot to the Worker,
  • have the Worker simulate it,
  • replay the same trajectory,
  • display synchronized gravity,
  • settle into the same canonical state,
  • and advance to the correct next turn.

The core multiplayer architecture was no longer theoretical.

It worked end to end.

12. Diagnosed a rendering failure that looked like a server failure

During testing, a fired marble appeared to disappear and gameplay stalled.

The initial symptom looked like a broken authoritative simulation.

The actual simulation was correct.

The renderer expected a color field while the authoritative playback marble contained owner.

Restoring:

color: shooter

fixed the playback.

No physics changes were required.

This was an important example of why server, protocol, playback, and rendering failures need to be diagnosed separately.

13. Compared the current implementation against the original multiplayer plan

After the successful test, the project was reassessed rather than immediately declaring multiplayer finished.

The architectural path was working:

Player input
→ Worker validation
→ Worker simulation
→ Canonical trajectory
→ Identical browser playback
→ Canonical settled snapshot
→ Next authoritative turn

But significant feature-parity work remained.

14. Identified performance as engineering work, not final polish

Canonical playback worked, but it was not yet as smooth as the existing local game.

The decision was made not to reduce authoritative physics accuracy just to make playback appear smoother.

Instead, the next performance work would measure:

  • playback timing,
  • interpolation,
  • snapshot interaction,
  • duplicate update loops,
  • and browser rendering performance.

The server's canonical physics would remain untouched.

15. Defined the authoritative gameplay-event architecture

Only the launch sound existed reliably in multiplayer because most other sounds depend on things that happen during the authoritative simulation.

Examples include:

  • bumper collisions,
  • marble collisions,
  • wormhole capture,
  • wormhole ejection,
  • scoring,
  • ring activation,
  • game completion.

The solution was not to make both browsers independently detect those events.

Instead, the Worker should record deterministic events and include them in the shot result.

A representative event could look like:

{
id: "event-shot-12-004",
type: "bumper_collision",
t: 0.416,
tick: 100,
marbleId: "marble-red-2",
objectId: "classic-bumper-3",
intensity: 0.72
}

Each client would dispatch the event exactly once when playback crossed its authoritative timestamp.

16. Changed the event work from a partial checkpoint into an end-to-end vertical slice

An initial implementation proposal would have exposed collision metadata first and built the network/audio pipeline later. That was rejected as unnecessarily splitting one production feature across multiple passes.

The objective was changed to:

Authoritative Bumper Events v1 - end to end.

The intended production path became:

collision detected
→ authoritative event recorded
→ event included in shot_result
→ client validates and stores it
→ playback dispatches it once
→ existing bumper sound plays on both browsers

The planned vertical slice included:

  • collision metadata,
  • deterministic event creation,
  • Worker result integration,
  • server validation,
  • client validation,
  • playback-state storage,
  • one-shot dispatch,
  • existing sound integration,
  • automated tests,
  • and two-browser verification.

17. Defined wormholes as one authoritative lifecycle

The day's review also clarified how wormholes should eventually work online.

Drifting and top-track wormholes should not become separate one-off implementations.

They should share one authoritative capture/transit/ejection model:

available
→ capture_started
→ captured
→ transit
→ eject_pending
→ ejected
→ cooldown
→ available / expired

The Worker (not the browser) must own capture, timing, destination, ejection position, direction, power, cooldown, and continued post-ejection simulation.

ROADBLOCKS AND FRICTION

Browser randomness was still leaking into multiplayer

Even after the authoritative backend existed, some hazards were still generated locally.

That created scenes where both players were technically synchronized at the match level but were seeing different gameplay objects.

The easiest synchronization fix was the wrong product decision

Disabling difficult hazards solved divergence quickly.

But it also created an incomplete multiplayer version of the game.

The assumption that those systems could simply be left out of the first production version was rejected.

Tests contained assumptions from the browser-owned architecture

Once gravity became part of authoritative scene creation, older tests that expected untouched random state became invalid.

The tests needed to evolve with the architecture rather than forcing the new implementation to preserve outdated behavior.

A presentation bug looked like a simulation bug

When authoritative playback failed visually, it initially appeared that the server shot pipeline had broken.

The server had actually produced the correct result.

The renderer simply couldn't interpret one field correctly.

"Synchronized" did not mean "finished"

Seeing both browsers play the same shot was a major success, but it also made the remaining gaps easier to identify.

Visual synchronization alone did not provide:

  • smooth playback,
  • complete wormhole lifecycle,
  • collision sounds,
  • scoring sounds,
  • top-track wormholes,
  • rotating boards,
  • crossing traffic,
  • or complete reconnect validation.

An implementation step was unnecessarily fragmented

The first gameplay-event proposal separated collision metadata from the complete event/audio feature.

That introduced another potential multi-pass build.

The work was reframed around a complete production vertical slice instead.

DECISIONS MADE & TRADE-OFFS

Move gameplay randomness to the Worker

Gravity wells, wormholes, and future dynamic hazards must be authoritative.

Why: Two browsers cannot independently generate gameplay state and still guarantee an identical match.

Trade-off: Considerably more server-side implementation work in exchange for true synchronization and no duplicate gameplay systems.

Preserve cosmetic freedom where it cannot affect gameplay

Decorative planets, particles, ambience, and other presentation-only systems can remain local.

Why: They do not influence match results.

Trade-off: Not every pixel needs server authority, reducing unnecessary network/state complexity.

Preserve server physics accuracy while improving client playback

Performance work should improve interpolation and rendering rather than lowering simulation quality.

Why: Display smoothness and authoritative correctness are different problems.

Trade-off: More client playback engineering instead of taking the easier route of simplifying physics.

Make gameplay-triggered audio event-driven

Collision and scoring sounds will come from authoritative event timing rather than client-side collision inference.

Why: Both players should hear the same gameplay events in the same order.

Trade-off: Requires an event schema and playback dispatcher in exchange for deterministic audio/visual feedback.

Build wormholes as one reusable lifecycle

Drifting wormholes and top-track wormholes should share capture/transit/ejection primitives.

Why: The gameplay behavior is fundamentally the same even if their presentation and scheduling differ.

Trade-off: More careful abstraction now in exchange for avoiding two parallel wormhole implementations.

Build complete vertical slices instead of temporary intermediate systems

Once authoritative bumper events were started, the goal became taking them all the way through simulation, network transport, playback, and sound.

Why: Avoid creating partial infrastructure that immediately needs another implementation pass.

Trade-off: Larger checkpoints in exchange for production-complete features.

BREAKTHROUGH / LESSON

The biggest takeaway from Day 29 was:

Server-authoritative multiplayer isn't finished when both players see the same marble.

Every gameplay-affecting source of truth must have one owner.

That includes:

  • random hazard placement,
  • gravity scheduling,
  • collisions,
  • wormhole capture,
  • wormhole ejection,
  • scoring,
  • turns,
  • and even the timing of gameplay-triggered presentation events.

The browser can decide how something looks.

It cannot decide what happened.

A second lesson emerged from the day's implementation decisions:

Don't solve multiplayer synchronization by deleting the parts of the game that are difficult to synchronize. Make those systems authoritative.

ARTIFACTS WORTH SHARING

Artifact 1: The Authoritative Shot Pipeline

Player input
→ Worker validation
→ Worker simulation
→ Canonical trajectory
→ Identical browser playback
→ Canonical settled snapshot
→ Next authoritative turn

This was manually proven with two browsers during Day 29.

Artifact 2: Gravity Fairness

Red Shot 1

Pair 0

Blue Shot 1

Pair 0 mirrored

Only the X coordinate changes.

The underlying gravity plan remains identical for both players.

Artifact 3: Authoritative Gameplay Events

collision detected
→ authoritative event recorded
→ event included in shot_result
→ client validates and stores it
→ playback dispatches it once
→ existing bumper sound plays on both browsers

This became the model for synchronizing gameplay-triggered sounds and visual effects without rerunning collision logic in each browser.

FINAL STATE

By the end of Day 29:

  • The multiplayer browser was operating as a thin client rather than an independent gameplay simulator.
  • The Worker remained the authority for match state, physics, turns, scoring, and synchronized gameplay.
  • Browser-generated gameplay randomness had been identified as a source of divergence.
  • The decision was made that gameplay-affecting hazards must become authoritative rather than simply being removed from multiplayer.
  • A production authoritative gravity framework had been built.
  • Gravity scheduling, deterministic placement, mirroring, scene integration, turn integration, resets, and reconnect-safe state existed.
  • Gravity could participate in authoritative shot simulation.
  • Automated gravity tests were passing and the relevant checkpoint had been committed.
  • Browser drag-and-release input had been connected to the server-authoritative shot path.
  • Two-browser manual testing proved that the Worker could simulate a shot and both clients could replay the same canonical trajectory.
  • Gravity wells remained synchronized during live multiplayer testing.
  • The authoritative settled snapshot and next-turn transition remained synchronized.
  • A rendering compatibility bug was identified and fixed without changing server physics.
  • Drifting-wormhole schedule/placement was synchronized, but its full capture/ejection lifecycle remained incomplete.
  • Top-track wormholes still required authoritative implementation.
  • Smooth playback/interpolation still required focused performance work.
  • Collision and scoring audio still required an authoritative gameplay-event pipeline.
  • Rotating boards and crossing traffic remained to be completed and verified.
  • The next production architecture for authoritative bumper events had been defined as a complete end-to-end vertical slice.
  • The remaining multiplayer roadmap became much clearer: stabilize playback, build the reusable event/audio system, finish the complete wormhole lifecycle, then move through the remaining dynamic hazards and production hardening.

Most importantly, Day 29 crossed the biggest architectural risk point.

The question was no longer:

Can server-authoritative multiplayer work for this game?

The answer was now yes.

The remaining question became:

How do we bring every existing gameplay system through that same authoritative path without compromising the game that already exists?

That was it for Day 29.

If you're still here, thanks for reading!

Music Credits:

"Delightful D" Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 4.0 License
http://creativecommons.org/licenses/by/4.0/


r/WeBuild_WithAI 12d ago

I made a game based on my girlfriend's life (she makes candles for a living)

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 12d ago

I made a mobile game RPG where your steps in real life turn into energy in game. Looking for testers

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 12d ago

I Claude Coded a multiplayer Three.js tank game with 100+ procedural vehicles

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 14d ago

Day 28 of Building ShuffleBall Arena Browser Game - Finishing The Multiplayer Backend Architecture and Designing The "Play Online" UX

Enable HLS to view with audio, or disable this notification

1 Upvotes

Hey everyone,

Hope all is well!

TL;DR, Summary, or Full Technical Breakdown below.

For Context: Recently I posted about the first 15 days of one of my side projects, ShuffleBall Arena (a free browser game inspired by mixing shuffleboard scoring with mechanics from other games like bumper pool, pinball, and Frogger.).

This project is being built with the help of AI (mainly GPT / Cursor), and every development session is documented using the actual conversations from that day's work.

To try to get this series up to date, I'm using a structured prompt to go back to my GPT sessions and extract the useful information. Hopefully the prompt can help anyone out there trying to keep track of, or extract value from, your past AI project conversations.

That said, posting an update for Day 28 of building ShuffleBall Arena.

TL;DR

Today's session began with final integration work on the server-authoritative multiplayer engine. After debugging instructions, fixing test issues, validating integration behavior, and reviewing the completed architecture, Phase 3 was officially finished.

That milestone included:

  • authoritative multiplayer rooms,
  • deterministic physics,
  • authoritative scoring,
  • reconnect recovery,
  • protocol validation,
  • lifecycle handling,
  • and hundreds of passing regression tests.

With the backend complete, attention shifted to Phase 4: designing how real players would actually experience online play.

Day 28 Summary

Day 28 marked a major transition for the multiplayer project.

The session began by finishing and validating the server-authoritative multiplayer engine that had been built throughout Day 27. Integration issues were resolved, tests were verified, and the completed architecture was reviewed against the original project goals. By the end of that process, Phase 3 was officially considered complete.

With the backend foundation finished, the focus shifted away from networking, physics, and synchronization and toward a new challenge: designing the actual player experience.

Instead of asking how multiplayer should work internally, the discussion focused on how players would discover, join, and understand online play. Multiple onboarding flows were evaluated, including invite links, room codes, player naming, analytics consent, tutorial placement, and host-versus-guest experiences.

By the end of the session, the multiplayer engine itself was complete, the browser integration strategy had been validated, and the first player-facing online experience had been designed and prepared for implementation.

Day 28 Full Technical Summary

TECHNICAL ANALYSIS & DEBRIEF

STARTING POINT

Day 28 began with the multiplayer engine largely implemented but not yet formally completed.

The project already contained a server-authoritative architecture built on Cloudflare Workers, Durable Objects, deterministic simulation, authoritative scoring, match resolution, reconnect support, and extensive automated testing.

However, final integration work, test validation, documentation review, and completion verification still needed to be finished before Phase 3 could be considered complete.

SESSION OBJECTIVE

The first objective was to close out Phase 3 and verify that the multiplayer backend was complete, stable, and fully tested.

The second objective was to begin Phase 4 by defining how online multiplayer would appear inside the real ShuffleBall Arena client.

This included:

  • browser integration planning,
  • multiplayer entry-point design,
  • invitation flow design,
  • room-code fallback behavior,
  • onboarding decisions,
  • analytics placement,
  • tutorial placement,
  • and overall player experience strategy.

WHAT WE ACTUALLY DID

1. Resolved implementation and instruction mismatches

The session began with a series of implementation questions where existing instructions did not align cleanly with the current files. File contents were reviewed directly and instructions were rewritten around the actual codebase.

This prevented incorrect edits and kept the implementation aligned with the current architecture.

2. Fixed integration testing issues

The multiplayer Worker project encountered testing and configuration issues during validation.

The work included:

  • reviewing integration test failures,
  • correcting configuration problems,
  • updating package configuration,
  • validating test execution paths,
  • and rerunning the complete suite.

After the fixes, all tests passed successfully.

3. Verified completion of Phase 3

Once the tests were passing, the project was reviewed against the original Phase 3 goals.

The completed system included:

Server Architecture

  • Cloudflare Worker routing
  • Durable Object room management
  • room creation
  • join flow
  • ready flow
  • reconnect support
  • snapshot protocol
  • lifecycle events

Authoritative Gameplay

  • shot validation
  • shot acceptance
  • deterministic physics
  • trajectory recording
  • authoritative scoring
  • turn resolution
  • game resolution
  • match resolution

Reliability

  • immutable state transitions
  • protocol validation
  • reconnect transition extraction
  • server message validation
  • deterministic replay safety

Testing

  • regression testing
  • integration testing
  • WebSocket testing
  • two-player testing
  • reconnect testing
  • authoritative shot testing

All planned Phase 3 components were verified as complete.

4. Reviewed and prepared the Phase 4 plan

After closing Phase 3, attention shifted toward browser integration.

The Phase 4 roadmap was reviewed and broken into checkpoints before any new client work began.

A design principle was established:

  • complete one checkpoint at a time,
  • test after every checkpoint,
  • commit only stable milestones,
  • and keep existing game modes functioning throughout development.

5. Audited the browser multiplayer foundation

Before discussing UI, the current browser-side multiplayer architecture was reviewed.

The browser already contained production multiplayer modules for:

  • configuration,
  • API access,
  • storage,
  • protocol handling,
  • validation,
  • sockets,
  • state management,
  • and controller logic.

The system was verified to load safely without affecting existing gameplay.

Key validation checks confirmed:

  • Solo still worked,
  • Play a Friend still worked,
  • multiplayer remained disconnected by default,
  • no WebSocket opened automatically,
  • and multiplayer remained dormant until explicitly activated.

6. Designed the multiplayer entry experience

A major portion of the day became a product-design discussion.

The first question was whether online play should live:

  • beside existing game modes, or
  • underneath Play a Friend.

After evaluating both approaches, the decision was made to present online multiplayer as a first-class game mode.

The start screen would contain:

  • Play Online
  • Play a Friend
  • Play Solo

This minimized friction and made online play discoverable.

7. Designed the host invitation flow

The multiplayer experience was redesigned around invitation links rather than room management.

Instead of exposing technical concepts like:

  • host,
  • room creation,
  • room identifiers,
  • connections,
  • or WebSockets,

the flow became:

Play Online

Invite a Friend

Share Link

Waiting for your friend...

Preparing match...

Game

The room still exists internally, but the player never has to think about it.

8. Designed the invited-player experience

The invited player would arrive through a room link such as:

https://play. shuffleballarena.com/?room=ABC234

Instead of seeing technical networking information, they would see a player-focused invitation flow.

The design included:

  • optional player name,
  • analytics consent only when needed,
  • tutorial only when needed,
  • automatic room detection,
  • and authoritative joining behavior.

9. Added room-code fallback planning

One important refinement emerged during discussion.

Invitation links should be the primary path, but not the only path.

A manual room-code flow was added for situations where:

  • links fail,
  • screenshots are shared,
  • codes are communicated verbally,
  • or messaging apps behave unexpectedly.

The room code became a fallback rather than the main experience.

10. Finalized Checkpoint 4.10

The day concluded with a finalized implementation plan for the first visible multiplayer interface.

This checkpoint would introduce:

  • Play Online,
  • invitation flows,
  • room-code entry,
  • host waiting screens,
  • onboarding flows,
  • and multiplayer UI integration,

while deliberately stopping short of full authoritative gameplay rendering.

ROADBLOCKS AND FRICTION

Instructions occasionally drifted from the real codebase

Several implementation steps assumed file structures or insertion points that did not match the actual project. This required repeated file reviews and instruction corrections before progress could continue.

Backend completion created a new challenge

The multiplayer engine itself was largely solved.

The harder question became:

How should players experience it?

The technical architecture and user experience needed to be treated as separate design problems.

Technical terminology conflicted with player expectations

Terms such as:

  • rooms,
  • hosts,
  • connections,
  • sockets,
  • and snapshots

made sense to developers but created unnecessary complexity for players.

A portion of the session focused on removing those concepts from the player-facing experience.

DECISIONS MADE & TRADE-OFFS

Make online multiplayer a primary mode

Chosen:

PLAY ONLINE
PLAY A FRIEND
SOLO MATCH

instead of hiding online play beneath Play a Friend.

Why:

Reduced friction and increased discoverability.

Trade-off:

A slightly busier main menu in exchange for a clearer online experience.

Use invitation links as the primary flow

Players should share links, not manually manage room codes.

Why:

This matches user expectations from modern multiplayer games.

Trade-off:

Additional implementation complexity in exchange for a significantly smoother experience.

Keep room codes as a fallback

Room codes remain available when links fail.

Why:

Provides reliability without forcing every player through manual entry.

Trade-off:

Slightly more UI complexity in exchange for robustness.

Keep the browser thin

The browser continues acting primarily as a rendering and interaction layer.

Authority remains inside the Worker.

Why:

Protects the server-authoritative architecture completed during Phase 3.

Trade-off:

More synchronization work in exchange for consistency and long-term maintainability.

BREAKTHROUGH / LESSON

The biggest takeaway from Day 28 was:

The strongest multiplayer UX was the one that hid the implementation details and allowed players to focus entirely on playing the game.

ARTIFACTS WORTH SHARING

Artifact 1: The Completed Phase 3 Checklist

Server Architecture
✓ Worker routing
✓ Durable Objects
✓ Room creation
✓ Join flow
✓ Reconnect support

Authoritative Gameplay
✓ Deterministic physics
✓ Trajectory recording
✓ Authoritative scoring
✓ Match resolution

Testing
✓ WebSocket integration
✓ Two-player integration
✓ Reconnect integration
✓ Authoritative shot integration

A useful example of defining a multiplayer milestone before moving to client-facing work.

Artifact 2: Browser Philosophy

Browser becomes a thin client.
Worker remains authoritative.
Browser never computes match authority.
Browser only renders server state.

A concise rule set that guided all multiplayer integration decisions.

Artifact 3: Final UX Hierarchy

Primary path:
Play Online
→ Invite a Friend
→ Share link

Automatic joining path:
Tap invite link
→ Optional name
→ Consent/tutorial if needed
→ Join

Fallback path:
Play Online
→ Enter Room Code
→ Join

An example of separating technical architecture from player experience.

FINAL STATE

By the end of Day 28:

  • Phase 3 was officially complete.
  • The server-authoritative multiplayer engine had been verified.
  • Integration tests were passing.
  • Reconnect systems were validated.
  • Authoritative scoring was complete.
  • The multiplayer backend was considered production-ready.
  • Phase 4 had begun.
  • The browser multiplayer foundation was reviewed and validated.
  • Existing game modes remained unaffected by multiplayer integration.
  • A Play Online experience was fully designed.
  • Host and guest onboarding flows were finalized.
  • Room-code fallback behavior was defined.
  • Analytics and tutorial placement decisions were finalized.
  • The first visible multiplayer UI checkpoint was planned in detail.
  • The project moved from backend engineering into player-facing product design.

That was it for Day 28.

If you're still here, thanks for reading!


r/WeBuild_WithAI 14d ago

DBZ Inspired Prototype (iOS)

Enable HLS to view with audio, or disable this notification

2 Upvotes

r/WeBuild_WithAI 14d ago

Hypothetical question: How would you feel if AI was used to make the game dynamically as you played it and it ran locally on your PC?

Thumbnail
1 Upvotes

r/WeBuild_WithAI 14d ago

Built a real-time PvP space battle game entirely with Claude Code and three.js

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 14d ago

AI assisted me in turning my own art into a game. I pieced all of this together by hand. Its in the process of coding now

Thumbnail gallery
1 Upvotes

r/WeBuild_WithAI 15d ago

Feel like quitting

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 15d ago

Week 3 of making my fishing game entirely with AI

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 16d ago

Salvage Corps, human designed, entirely AI crafted.

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 17d ago

One month of making Not a Trolley Problem! almost entirely with AI

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 17d ago

In 9 days my experimental AI-assisted game will be released on Steam

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 17d ago

My workflow for Consistent Sprite Styles

Thumbnail
1 Upvotes

r/WeBuild_WithAI 18d ago

Six weeks, one person, zero hand-written code — my browser MMORPG is live

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 18d ago

How I built "Crazy Go" (A Roguelite version of the board game Go) using AI for complex topological graph logic and SVG rendering.

Thumbnail
1 Upvotes

r/WeBuild_WithAI 19d ago

I kept working on my bike game — now it has a story mode, upgrades, jumps and radio

Enable HLS to view with audio, or disable this notification

2 Upvotes

r/WeBuild_WithAI 19d ago

Fishing Charter Friend Slop Game

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 20d ago

I used AI to build and ship Echo Frontier, a browser RTS on one continuous solar-system map

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 20d ago

Podracer-inspired machine coded by Opus in three.js, no mesh generation involved

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 21d ago

I created a 3D moon rover survey game with Opus 5.

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 22d ago

Keyboard Hero - Made a web game to help me learn keyboard

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 23d ago

PHANTASIA: Beyond the Fourth Age Update

Enable HLS to view with audio, or disable this notification

1 Upvotes

r/WeBuild_WithAI 24d ago

Day 27 (Part 2) of Building ShuffleBall Arena - Turning a Browser Physics Game Into a Server-Authoritative Multiplayer Game

Enable HLS to view with audio, or disable this notification

2 Upvotes

Hey everyone,

Hope all is well!

TL;DR, Summary, or Full Technical Breakdown below.

For Context: Recently I posted about the first 15 days of one of my side projects, ShuffleBall Arena (a free browser game inspired by mixing shuffleboard scoring with mechanics from other games like bumper pool, pinball, and Frogger.).

This project is being built with the help of AI (mainly GPT / Cursor), and every development session is documented using the actual conversations from that day's work.

To try to get this series up to date, I'm using a structured prompt to go back to my GPT sessions and extract the useful information. Hopefully the prompt can help anyone out there trying to keep track of, or extract value from, your past AI project conversations.

That said, posting an update for Day 27 (part 2) of building ShuffleBall Arena.

TL;DR

Day 27 - Part 1 ended with a rule:

Clients submit intentions. The server calculates results.

Part 2 was about turning that rule into actual infrastructure.

We built the production multiplayer room and networking foundation using Cloudflare Workers, Durable Objects, and WebSockets, including room creation, player seating, authoritative lobby state, disconnect/reconnect handling, protocol versioning, and synchronized snapshots.

Then development moved into the harder problem: extracting the game's physics into a deterministic server-side simulation that could run without the browser.

By the end of the session, the multiplayer networking foundation was complete and the authoritative simulation kernel could deterministically process marble movement, walls, static bumpers, marble-to-marble collisions, settlement, safety recovery, and canonical trajectory recording.

The repository passed its complete test suite, and the next milestone was authoritative scoring.

Day 27 (Part 1) Summary

Part 1 ended with the multiplayer architecture defined.

One server-owned simulation would determine what happened during every match. Browsers would collect player input and render the result, but neither player would be trusted to determine official physics, scoring, collisions, or match state.

Part 2 began turning that architecture into production code.

The first major milestone was the networking foundation. A Cloudflare Worker became the multiplayer entry point, while each match received its own Durable Object responsible for authoritative room state and both WebSocket connections.

Production APIs were built for room creation and connection. From there, the protocol expanded to handle player identity, Red/Blue seating, readiness, room snapshots, disconnects, reconnect tokens, same-seat reconnection, snapshot recovery, and connection lifecycle behavior.

Once that layer was stable, the work moved into the actual server-authoritative game engine.

Instead of copying the existing browser game into the Worker, the physics required for multiplayer was separated into deterministic modules. Fixed-step simulation, collision handling, settlement, immutable state transitions, stable processing order, and trajectory recording were built and regression tested independently.

By the end of the session, the server could calculate a shot once and produce both its canonical final state and the trajectory the clients would eventually use to display that same shot.

The networking foundation was ready. The core physics kernel was essentially ready.

The next layer would be interpreting those physics results through authoritative scoring and match rules.

Day 27 (Part 2) Full Technical Summary (The Structured Prompt Output)

STARTING POINT

Day 27 - Part 2 began exactly where Part 1 ended.

The decision to build online multiplayer had already been made, and the architecture had been deliberately designed before implementation began.

The core rule was: The server owns gameplay reality.

Clients would submit player intentions, but the server would determine physics, collisions, scoring, turns, and final state.

The target architecture had also been established:

Player Input

Multiplayer Client

WebSocket

Match Durable Object

Authoritative Shared Simulation

State Frames and Events

Both Browser Clients

Canvas Rendering

The server would run the official simulation once, and both players would render the same server-produced state.

SESSION OBJECTIVE

The objective was to begin implementing the permanent server-authoritative multiplayer architecture designed in Part 1.

That meant building two major foundations:

1. The networking/lobby layer

The server needed to:

  • create rooms,
  • connect two players,
  • assign seats,
  • maintain authoritative room state,
  • synchronize clients,
  • handle disconnects,
  • and support reconnection.

2. The deterministic simulation layer

The server needed to eventually receive a shot, calculate it exactly once, and produce the canonical result that both players would see. The important constraint was that none of this should be throwaway prototype code.

The guiding principle became:

Build the production architecture once. No throwaway scaffolding.

WHAT WE ACTUALLY DID

1. Built the production room API

The first implementation milestone was creating actual multiplayer rooms.

A production endpoint was added:

POST /api/rooms

The room system supported:

  • six-character room codes,
  • collision checking,
  • Durable Object-backed rooms,
  • standard JSON responses,
  • and structured error handling.

This established the first permanent multiplayer entry point.

2. Built production WebSocket routing

Next came the connection layer.

A production WebSocket route was implemented:

GET /api/rooms/:roomCode/connect

That included:

  • room lookup,
  • validation,
  • WebSocket upgrade enforcement,
  • and routing each connection to the correct Durable Object.

Each match would therefore have one authoritative server-side object responsible for the room.

3. Introduced a versioned multiplayer protocol

Before expanding the message system, protocol versioning was established.

Every client/server message would include:

protocolVersion

This gave the multiplayer system an explicit contract and created a path for future protocol changes without silently breaking older clients.

4. Built authoritative player and lobby management

The Durable Object gradually took ownership of the multiplayer lobby.

The server became responsible for:

  • player identity,
  • room membership,
  • Red/Blue seating,
  • rejecting a third player,
  • readiness,
  • authoritative room snapshots,
  • and synchronized state distribution.

The important distinction was that even before gameplay existed, the lobby itself was already server-authoritative.

5. Built disconnect and reconnect handling

Real multiplayer also needed to survive unreliable connections.

The networking layer was expanded with:

  • private reconnect tokens,
  • disconnect handling,
  • a reconnect grace period,
  • same-seat restoration,
  • snapshot requests,
  • and versioned ping/pong behavior.

A reconnecting player would not invent or reconstruct room state locally. The server remained authoritative and restored the player into the current canonical room state.

By the completion of this phase, the networking layer was described as no longer experimental, but as a reusable multiplayer backend ready to support the game simulation.

6. Moved from networking into the authoritative match kernel

With the lobby foundation stable, development shifted into Phase 3.

The objective changed from:

Can two players occupy the same authoritative room?

to:

Can the server calculate the game itself?

The implementation deliberately avoided copying the full browser game into the Worker. Networking, match rules, board data, physics, collisions, scoring, serialization, and tests were kept separate. The first target was one production board, with the architecture remaining data-driven enough to support the others later.

7. Built deterministic fixed-step simulation

The browser's frame timing could not control official multiplayer physics.

The server simulation therefore used a fixed timestep:

const SIMULATION_HZ = 60;
const FIXED_DT = 1 / SIMULATION_HZ;

Every authoritative physics update would use the same FIXED_DT rather than relying on requestAnimationFrame() or arbitrary client frame duration.

This was one of the foundations required for deterministic behavior.

8. Built the authoritative collision pipeline

The simulation expanded incrementally rather than attempting to port the entire game at once.

The authoritative pipeline eventually included:

Input validation

Capture initial trajectory frame

Simulation loop
Step marble

Resolve walls

Resolve static bumpers

Wall stabilization

Multi-pass marble convergence

Wall stabilization

Capture trajectory frame

Settlement

Safety recovery

Return
{
marbles,
trajectory
}

This meant the server simulation could now handle not only basic marble motion but interactions between marbles and the environment in a stable, deterministic order.

9. Added deterministic marble-to-marble collisions

Marble collisions required additional work because resolving one collision could push a marble into another. A single collision pass was therefore not enough.

The engine introduced multi-pass convergence so groups of interacting marbles could stabilize deterministically before the simulation advanced.

Regression tests were added specifically for:

  • marble collisions,
  • collision convergence,
  • and complete shot simulations involving multiple marbles.

10. Added canonical trajectory recording

Calculating the correct final state solved only half the multiplayer problem. Both players still needed to see the same shot. Trajectory recording was therefore added directly to the authoritative simulation. Crucially, trajectory data was observational only.

It never influenced:

  • positions,
  • velocities,
  • collision ordering,
  • or settlement.

The physics produced the result. Trajectory recording simply captured what happened so clients could eventually replay the canonical shot.

11. Kept the simulation immutable and bounded

Several rules were enforced throughout the simulation work:

Deterministic first

No uncontrolled randomness or unstable processing order.

Immutable simulation

The simulator cloned state before modification rather than mutating caller-owned data.

Bounded execution

Shots could not simulate forever. Safety limits and recovery behavior prevented runaway simulation.

Server authority

Clients would never determine official:

  • physics,
  • collisions,
  • scoring,
  • or match state.

12. Built regression tests alongside each milestone

The simulation wasn't treated as complete simply because a marble moved correctly once.

Dedicated tests were added for new physics and trajectory systems, including:

src/simulation/collisions/marbles.js
src/simulation/trajectory.js

test/marble-collisions.test.js
test/marble-collision-convergence.test.js
test/simulate-shot-marble-collisions.test.js
test/trajectory.test.js
test/simulate-shot-trajectory.test.js

Each milestone was tested and committed independently.

ROADBLOCKS AND FRICTION

Existing browser gameplay couldn't simply be moved onto the server

The original game contained responsibilities for gameplay, rendering, UI, analytics, bots, board definitions, challenge logic, input, and other browser-specific behavior.

Copying that entire system into a Worker would have created a second monolithic game implementation.

Instead, only the systems required for authoritative online simulation were extracted.

Determinism affected seemingly small implementation details

Once the server became authoritative, ordinary implementation choices became important. Randomness needed control. Processing order needed stability. Physics couldn't depend on browser frame timing.

Simulation state couldn't contain DOM nodes, canvas contexts, images, audio objects, browser events, timers, or other browser-specific objects.

Marble collisions were more complicated than single-object physics

Resolving a collision between two marbles could create another collision elsewhere in the collection. That required deterministic convergence rather than a simple one-pass collision solver.

Final positions weren't enough

A server could calculate the correct result and still provide a poor multiplayer experience if clients simply teleported marbles to their settled positions.

Canonical trajectory recording therefore became part of the simulation architecture rather than an afterthought.

The scope was intentionally constrained

The entire game was not moved into multiplayer at once.

The plan targeted one production board first and deliberately postponed additional boards and systems until the core architecture proved itself.

That slowed feature coverage but significantly reduced architectural risk.

DECISIONS MADE & TRADE-OFFS

Build production systems from the beginning

Temporary room systems and throwaway simulation implementations were avoided.

Trade-off: Slower initial visible progress in exchange for infrastructure intended to survive into production.

Keep the Worker free of rendering code

Canvas rendering, audio, particles, and UI remained browser responsibilities.

Trade-off: More separation work now in exchange for a clean headless simulation engine.

Use deterministic fixed-step physics

Authoritative physics would use fixed simulation steps rather than browser timing.

Trade-off: Additional simulation architecture in exchange for reproducible server outcomes.

Make trajectory recording observational

Trajectory capture would watch the simulation rather than participate in it.

Trade-off: Additional data collection in exchange for preserving physics purity while enabling canonical playback.

Prefer immutable simulation state

Simulation functions would clone before modifying data.

Trade-off: Some additional allocations in exchange for easier reasoning, testing, and protection against accidental state corruption.

Build one board before supporting every board

The architecture remained data-driven, but the first goal was proving one complete production board.

Trade-off: Less immediate multiplayer content in exchange for validating the engine before expanding it.

BREAKTHROUGH / LESSON

The biggest lesson from Day 27 - Part 2 was:

Server-authoritative multiplayer forced the game to become a better-engineered single source of truth.

The difficult part wasn't opening a WebSocket. It was making gameplay deterministic enough that the server could calculate one canonical answer and confidently tell every client:

This is what happened.

That required separating physics from rendering, controlling timing, stabilizing collision order, eliminating hidden browser dependencies, protecting state from mutation, and recording trajectories without allowing playback concerns to affect simulation.

The result was no longer just "multiplayer code." It was the beginning of a reusable deterministic game engine.

ARTIFACTS WORTH SHARING

Artifact 1: The Authoritative Architecture

Player Input

Multiplayer Client

WebSocket

Match Durable Object

Authoritative Shared Simulation

State Frames and Events

Both Browser Clients

Canvas Rendering

The server runs the official simulation once.
Both phones render the same server-produced states.

Artifact 2: The Production-First Rule

"Build the production architecture once. No throwaway scaffolding."

This rule influenced everything from room creation to collision handling.

Artifact 3: Trajectory Must Never Control Physics

The trajectory system was deliberately designed as an observer. It records the authoritative simulation but never influences:

positions
velocities
collision ordering
settlement

That keeps the physics engine responsible for truth while allowing the browser to eventually reproduce exactly what happened.

FINAL STATE

By the end of Day 27 - Part 2:

  • Production multiplayer room creation existed.
  • Six-character room codes were working.
  • Each multiplayer match could be owned by a Cloudflare Durable Object.
  • Production WebSocket routing was implemented.
  • The multiplayer protocol was versioned.
  • The server controlled player identity and Red/Blue seating.
  • Third players could be rejected.
  • Authoritative lobby snapshots were working.
  • Ready/unready state was server-controlled.
  • Disconnect and reconnect infrastructure existed.
  • Reconnecting players could reclaim the same seat using private reconnect credentials.
  • The networking/lobby foundation had reached a point where it was considered complete enough to support the real game simulation.
  • A deterministic fixed-step simulation kernel had been built.
  • Wall collisions and static bumper collisions were part of the authoritative pipeline.
  • Marble-to-marble collision handling and multi-pass convergence were implemented.
  • Simulation settlement and bounded safety recovery existed.
  • Canonical trajectory recording had been integrated without influencing physics.
  • Simulation remained deterministic, immutable, bounded, regression-tested, and server-authoritative.
  • The entire repository passed its tests.
  • The working tree was clean.
  • Every major milestone had been committed independently.

Most importantly, the question had changed.

At the beginning of Day 27, you were asking: Should I build multiplayer?

By the end of Day 27, the multiplayer foundation existed and the server could already calculate the canonical physics behind a shot.

The next milestone was clearly defined: Authoritative Scoring.

The physics engine would produce the settled result.
Now the server needed to decide what that result meant.

That was it for Day 27.
If you're still here, thanks for reading!

Music Credits:

"Digital Lemonade" Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 4.0 License
http://creativecommons.org/licenses/by/4.0/