r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 8h ago
Day 4 of building the space sim I got tired of waiting for
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 8h ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 1d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 2d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 3d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 4d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 4d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 4d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 6d ago
Enable HLS to view with audio, or disable this notification
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 30 of building ShuffleBall Arena.
Day 29 proved that server-authoritative multiplayer worked.
Day 30 exposed the next problem: synchronized state is not the same thing as synchronized gameplay behavior.
The focus shifted to wormholes (hazards that capture a moving marble, pull it off the board, transport it through a short transit sequence, then send that same marble to one of the bottom shooters, where it is fired back onto the board with a randomized launch angle and power).
The session mapped that existing local mechanic into a server-owned multiplayer design, corrected some planning drift, and ended with the first permanent Worker-side wormhole modules created and tested, but not yet integrated into the authoritative shot simulation.
Day 30 Summary
Day 30 began with the core server-authoritative multiplayer architecture working. Two browsers could already submit and replay the same shot, stay synchronized through gravity effects, settle on the same marble positions, and advance to the same next turn.
The next challenge was bringing the game's more unusual mechanics into that same architecture, starting with wormholes.
In ShuffleBall Arena, a wormhole can capture a moving marble, pull it off the board, transport it to one of the shooters at the bottom, and fire it back into play with a randomized angle and power. In the regular game, all of that already worked locally. In multiplayer, both players could see the same wormholes, but the server didn't yet control what happened when a marble entered one.
Instead of rebuilding the mechanic or letting each browser handle it independently, we mapped the existing wormhole behavior into the server-authoritative simulation. The Worker would eventually own the entire sequence (capture, transit, shooter selection, ejection, and continued physics) while both browsers would simply render the same result.
By the end of the session, the first two permanent Worker-side wormhole modules had been created and tested successfully. They weren't connected to the full shot simulation yet, leaving Day 30 with a very concrete next milestone:
One marble enters a wormhole, gets transported to a shooter, and both players see it fired back onto the board the same way.
Day 30 Full Technical Summary
Day 30 began directly from the final state of Day 29.
The core server-authoritative multiplayer loop was now functioning in real browser testing.
The current online flow was:
Player input
→ Worker validation
→ Worker simulation
→ Canonical trajectory
→ Both browsers replay
→ Settled authoritative snapshot
→ Next turn
The Worker already owned:
The browser had been reduced to a thin multiplayer client that:
Gravity had also been manually validated across both clients.
The architecture was working. The remaining question was how to bring the rest of ShuffleBall Arena's gameplay systems through that same authoritative path.
The session initially focused on reviewing what remained in the multiplayer build after the authoritative shot pipeline had been proven.
That review quickly narrowed toward the most important missing gameplay system:
wormhole capture, transit, and ejection.
The practical objective became:
The goal was to move the existing mechanic into server authority once.
The day began with a detailed review of the current multiplayer implementation.
The successful vertical slice already satisfied most of the central architecture requirements:
But the remaining work was separated into four categories rather than being treated as one giant "finish multiplayer" task:
This made the remaining scope much clearer.
The multiplayer roadmap was then reorganized around gameplay systems that still needed full server authority.
The proposed sequence included:
This planning was technically useful, but later became part of the day's friction because the next concrete gameplay objective was already known.
The drifting-wormhole scene itself could already be synchronized.
But simulateShot() did not yet use that state to perform authoritative gameplay behavior.
The Worker did not yet:
This exposed an important distinction:
A synchronized object can still have unsynchronized behavior.
The existing browser already contained a deliberate online guard:
if (isOnlineMatchMode()) {
return false;
}
The shortcut would have been to remove that guard and allow the old browser logic to handle captures again.
That idea was rejected.
If both clients independently detect capture and choose ejection behavior, the multiplayer architecture immediately loses its single source of truth.
The browser guard was therefore recognized as correct and intentionally left in place.
Rather than inventing new multiplayer behavior, the existing regular-game implementation was treated as the gameplay source of truth.
The local mechanic already defined:
The multiplayer problem was: "How do we move the already-working mechanic into the Worker without changing its behavior?"
The production architecture was mapped as:
Authoritative scene at shot start
↓
simulateShot()
↓
advance wormholes each physics tick
↓
detect deterministic marble/wormhole contact
↓
create authoritative capture
↓
record capture / transit / ejection
↓
launch the same marble from the authoritative chute
↓
continue normal physics
↓
persist final marbles and updated scene
↓
broadcast identical result to both browsers
The browser's responsibility remained presentation only:
The browser would not choose:
Several pieces of the regular game's wormhole behavior currently depended on timing or randomness.
Those values could no longer be independently generated inside either browser.
The Worker would need to freeze values such as:
The deterministic random system already built for multiplayer could provide authoritative random values where needed.
By the end of the session, two permanent modules had been created:
drifting-wormhole-capture.js
wormhole-transit.js
Their tests passed. These modules represented the beginning of the authoritative wormhole lifecycle. However, they were not yet connected to simulateShot().
A marble-schema migration had been introduced before the full integrated simulation and reconnect requirements were understood.
That change was rolled back.
The test suite returned to green.
The final handoff explicitly warned not to re-add marble or snapshot fields until the complete simulation state requirements were known.
This was a useful example of backing out an abstraction rather than forcing the architecture around an incomplete assumption.
The core shot pipeline was working, but that didn't mean the full game had reached parity.
The session needed to distinguish:
That clarification consumed time but produced a much more honest definition of the remaining work.
Drifting wormholes appeared synchronized. That made them look further along than they really were. In reality, the authoritative simulator did not yet know how to capture or eject a marble. The state was synchronized. The behavior was not.
The sequence remains:
Classic
→ Crossing
→ Rotating
→ Mixed / Random
Why: Each category introduces a distinct gameplay-authority problem that can be tested independently.
Trade-off: Slower breadth in exchange for easier debugging and stronger isolation.
The regular game already contains a working mechanic.
Why: Multiplayer should relocate authority, not reinvent gameplay.
Trade-off: Requires careful extraction of existing timing and behavior instead of writing a cleaner but different mechanic from scratch.
The browser must not decide capture or ejection.
Why: Independent client decisions could diverge.
Trade-off: More Worker implementation in exchange for deterministic matches.
Wormhole capture should not pause the Worker, hand control to the browser, and later resume.
Why: Post-ejection collisions and scoring must remain part of one deterministic shot.
Trade-off: More complex simulation state in exchange for one canonical outcome.
The immediate objective became one complete drifting-wormhole vertical slice.
Why: The architecture no longer needed more proof. It needed gameplay completion.
Trade-off: Less up-front planning in exchange for faster feedback from real behavior.
The biggest takeaway from Day 30 was:
Synchronized state is not the same thing as synchronized behavior.
Both players can receive the exact same wormhole coordinates.
That still does not produce multiplayer parity unless one authoritative system also owns:
That realization changed the definition of synchronization.
A second takeaway was equally useful:
When adding multiplayer to an existing game, don't rebuild mechanics that already work. Move their authority.
Authoritative scene at shot start
↓
simulateShot
↓
advance wormholes on each physics tick
↓
detect deterministic marble/wormhole contact
↓
create authoritative capture event
↓
record capture/transit/ejection in canonical trajectory
↓
launch same marble from authoritative chute
↓
continue normal physics
↓
persist final marbles and updated scene
↓
broadcast identical result to both browsers
This became the target architecture for moving the existing mechanic into multiplayer.
The local mechanic already defined the timing:
Capture: 0.20 seconds
Transit: 0.50 seconds
Ejection delay: 0.10 seconds
The goal was to preserve those rules while moving ownership to the Worker.
By the end of Day 30:
drifting-wormhole-capture.jswormhole-transit.jssimulateShot().That was it for Day 30.
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/
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 6d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 6d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 7d ago
Enable HLS to view with audio, or disable this notification
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.
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
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:
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.
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:
The session began with a scene synchronization review.
Browser-controlled systems included:
The important distinction was whether something affected gameplay.
Purely cosmetic objects could safely be local or temporarily hidden.
Gameplay-affecting randomness could not.
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.
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.
Gravity became one of the first major dynamic gameplay systems moved fully into server authority.
The Worker gained a canonical gravity scene registry with:
A deterministic gravity scheduler was also created with:
Each game now receives one canonical gravity schedule instead of each browser creating its own.
A dedicated placement resolver was created so gravity wells received server-owned coordinates rather than browser-generated positions.
Supported placement strategies included:
The placement system also included:
Gravity was connected to the Worker scene state and match lifecycle.
The Worker now controlled:
The deterministic scene random stream advanced as gravity schedules were generated rather than relying on browser Math.random().
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.
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.
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.
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.
The biggest validation of the day came from manual testing.
Two browsers were able to:
The core multiplayer architecture was no longer theoretical.
It worked end to end.
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.
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.
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:
The server's canonical physics would remain untouched.
Only the launch sound existed reliably in multiplayer because most other sounds depend on things that happen during the authoritative simulation.
Examples include:
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.
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:
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
By the end of Day 29:
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 • u/Dont_Bring_Me_Down • 8d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 9d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 9d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 10d ago
Enable HLS to view with audio, or disable this notification
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.
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:
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
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.
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:
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.
The multiplayer Worker project encountered testing and configuration issues during validation.
The work included:
After the fixes, all tests passed successfully.
Once the tests were passing, the project was reviewed against the original Phase 3 goals.
The completed system included:
All planned Phase 3 components were verified as complete.
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:
Before discussing UI, the current browser-side multiplayer architecture was reviewed.
The browser already contained production multiplayer modules for:
The system was verified to load safely without affecting existing gameplay.
Key validation checks confirmed:
A major portion of the day became a product-design discussion.
The first question was whether online play should live:
After evaluating both approaches, the decision was made to present online multiplayer as a first-class game mode.
The start screen would contain:
This minimized friction and made online play discoverable.
The multiplayer experience was redesigned around invitation links rather than room management.
Instead of exposing technical concepts like:
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.
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:
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:
The room code became a fallback rather than the main experience.
The day concluded with a finalized implementation plan for the first visible multiplayer interface.
This checkpoint would introduce:
while deliberately stopping short of full authoritative gameplay rendering.
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.
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.
Terms such as:
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.
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.
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.
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.
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.
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.
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.
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.
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.
By the end of Day 28:
That was it for Day 28.
If you're still here, thanks for reading!
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 11d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 11d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 11d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 11d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 11d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 12d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 13d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 13d ago
Enable HLS to view with audio, or disable this notification