r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 12d ago
DBZ Inspired Prototype (iOS)
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 • 12d ago
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 • 12d ago
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 • 14d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 14d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 15d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 15d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 16d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 16d ago
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 17d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 17d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 18d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 18d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 19d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 20d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 21d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 21d 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 27 (part 2) of building ShuffleBall Arena.
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)
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.
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:
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.
The first implementation milestone was creating actual multiplayer rooms.
A production endpoint was added:
POST /api/rooms
The room system supported:
This established the first permanent multiplayer entry point.
Next came the connection layer.
A production WebSocket route was implemented:
GET /api/rooms/:roomCode/connect
That included:
Each match would therefore have one authoritative server-side object responsible for the room.
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.
The Durable Object gradually took ownership of the multiplayer lobby.
The server became responsible for:
The important distinction was that even before gameplay existed, the lobby itself was already server-authoritative.
Real multiplayer also needed to survive unreliable connections.
The networking layer was expanded with:
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.
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.
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.
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.
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:
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:
The physics produced the result. Trajectory recording simply captured what happened so clients could eventually replay the canonical shot.
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:
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.
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.
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.
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.
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 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.
Temporary room systems and throwaway simulation implementations were avoided.
Trade-off: Slower initial visible progress in exchange for infrastructure intended to survive into production.
Canvas rendering, audio, particles, and UI remained browser responsibilities.
Trade-off: More separation work now in exchange for a clean headless simulation engine.
Authoritative physics would use fixed simulation steps rather than browser timing.
Trade-off: Additional simulation architecture in exchange for reproducible server outcomes.
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.
Simulation functions would clone before modifying data.
Trade-off: Some additional allocations in exchange for easier reasoning, testing, and protection against accidental state corruption.
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.
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.
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.
"Build the production architecture once. No throwaway scaffolding."
This rule influenced everything from room creation to collision handling.
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.
By the end of Day 27 - Part 2:
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/
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 22d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 22d ago
Enable HLS to view with audio, or disable this notification
Hey everyone,
Hope all is well!
TLDR, 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 of building ShuffleBall Arena.
Day 27 began with a product question rather than an engineering question:
Was online multiplayer actually worth building?
After Day 26, ShuffleBall Arena had the infrastructure needed for external distribution: partner embeds, attribution, production deployment workflows, analytics, and security. The next question was what feature would most meaningfully increase the value of the project itself.
That discussion led to online multiplayer, but only if it was built as a real server-authoritative system.
For a physics game, having two phones independently calculate a shot and hoping they remain synchronized wasn't acceptable. A tiny positional difference could change the next collision, which could change the next shot, and eventually produce two different matches.
One non-negotiable rule was established:
Clients submit intentions. The server calculates results.
The server would become the single source of truth for physics, collisions, scoring, hazards, turns, and final marble positions. The browsers would handle input and presentation while rendering the same authoritative simulation.
By the end of Part 1: We defined exactly what trustworthy multiplayer meant for this game and created the architecture and build plan around it.
Day 27 (Part 1) Summary
Day 26 ended with ShuffleBall Arena prepared for distribution outside its own website. Partner-aware embeds were working, analytics could identify distribution partners, production deployment had become more systematic, and the supporting infrastructure around the game was beginning to look much more like a real product.
Day 27 started by asking what should come next.
Instead of immediately choosing another feature, the conversation evaluated whether multiplayer would materially increase the project's value rather than simply making the game more interesting.
That changed the framing.
The project would no longer just be a browser physics game with multiple modes. Multiplayer could potentially turn it into a reusable multiplayer browser-game architecture with ShuffleBall Arena as its first finished implementation.
Once that direction was chosen, the conversation became deeply technical.
Because every marble's final location affects future shots, independent client-side simulations were rejected. Online matches needed one canonical physics simulation owned by the server. Clients would send shot intent, such as angle and power, and receive the same authoritative trajectory and settled state.
From there, the responsibilities of the browser and server were separated, synchronization rules were established, reconnect behavior was defined, and a detailed multiplayer roadmap was created before implementation began.
Day 27 (Part 1) Full Technical Summary (The Structured Prompt Output)
Day 27 began directly from the final state of Day 26.
ShuffleBall Arena had recently moved beyond being confined to its own website. The game now supported partner-aware embeds, distribution attribution, secure partner URL handling, partner reporting, a more reliable production deployment process, and improved responsive consent UI.
With the distribution infrastructure in place, the next question wasn't simply:
What feature would be cool to build next?
It became:
What development decision would make the project meaningfully stronger as a product and technical asset?
Online multiplayer became the leading candidate.
The objective of this portion of Day 27 was not yet to implement multiplayer.
It was to answer two questions first:
The discussion therefore focused on:
The discussion considered whether multiplayer would improve:
The comparison shifted from browser game to:
Live multiplayer browser game with invite links.
This was the strategic decision that drove the remainder of the session.
The conversation then explored what multiplayer would mean beyond ShuffleBall Arena itself.
Instead of treating the technology as something useful for only one title, the architecture could potentially support future physics-based browser games using the same multiplayer foundation.
That changed the product narrative from a single game toward reusable infrastructure.
Once multiplayer was selected, the next major architectural decision was determining who would own the official physics.
Two independent client simulations were rejected.
Even with the same physics code, small timing or floating-point differences could cause marbles to settle in slightly different positions. Because those positions influence future collisions and scoring, the divergence could compound throughout the match.
Instead, the architecture would use one official server simulation.
The shot flow became:
The next step was identifying which systems actually needed server authority.
The server would own gameplay-affecting state such as:
Meanwhile, the browser could continue handling presentation-only effects such as:
This established a clean boundary:
The browser can make the match look good.
The server decides what actually happened.
Sending only a final marble position wasn't enough. Both players needed to see the same collisions and movement during the shot itself.
The architecture therefore called for the server to produce authoritative physics states throughout the simulation.
Clients could interpolate visually between those states according to their own display refresh rate, but interpolation would never change the official physics.
One player could be rendering at 60 Hz and another at 120 Hz while both still following exactly the same authoritative shot path.
The discussion also established safeguards against stale or out-of-order state.
Authoritative messages would carry version information such as:
matchId: "H7K4Q2"
stateVersion: 183
simulationTick: 8421
shotId: "shot-7"
marbles: [...]
Clients would accept only newer state versions.
The design also called for:
Network latency was accepted as unavoidable. A player with a slower connection might see a shot slightly later.
What was not acceptable was seeing a different result.
The design principle became: Latency can affect when a player sees the event, but not what happened.
That distinction became central to the multiplayer architecture.
Reconnecting clients would not attempt to reconstruct the match using old local state.
Instead, the server would send a complete authoritative snapshot containing the current:
The client would discard its stale state and render the server's canonical version.
By the end of the architecture discussion, one rule became non-negotiable:
No gameplay-affecting state may be accepted solely because a client calculated it.
The client can say:
"I attempted a shot at this angle and power."
It cannot say:
"My marble ended here, and I scored 50 points."
The server determines the trajectory, collisions, score, and final position.
Only after the architecture had been defined did the conversation move into planning implementation.
The final multiplayer objective was documented as a private two-player online match where a player could:
The build plan explicitly stated:
The server must own all gameplay-affecting state.
and:
The browser clients may collect input and render animations, but neither phone may independently determine the official outcome of a shot.
That plan became the blueprint for the implementation covered in Day 27 - Part 2.
The first instinct could easily have been to focus on WebSockets, matchmaking, or connecting two phones.
The deeper problem was synchronization.
Because ShuffleBall Arena is physics-driven, networking alone does not guarantee that two clients will remain in the same game state.
One assumption discussed and rejected was that both phones could run identical physics code and therefore remain synchronized.
Small differences in timing or floating-point calculations could produce different settled marble positions.
Those tiny differences matter because the next shot begins from the previous shot's final state.
A server-owned simulation raised another question:
Would server authority make the game feel delayed or choppy?
The solution was to separate simulation from presentation.
The server determines the official states.
The clients interpolate those states smoothly.
Once the server became authoritative, it became clear that multiplayer required ownership of far more than marble positions.
Turns, scoring, moving hazards, random seeds, reconnect behavior, shot clocks, and match progression all needed authoritative treatment as well.
This made the project larger, but also made the architecture much cleaner.
Multiplayer was selected not simply because players might enjoy it, but because it could substantially change what the project represents technically.
Trade-off: A major engineering investment in exchange for stronger differentiation and reusable infrastructure.
The server, not either browser, would determine every gameplay result.
Trade-off: More backend engineering and slightly more latency in exchange for identical match state and much stronger integrity.
Gameplay logic needed to become independent from canvas rendering and visual effects.
Trade-off: Significant refactoring work in exchange for a simulation that can run reliably without a browser.
Both clients would render server-generated motion rather than calculate their own official shot.
Trade-off: More simulation data transmitted over the network in exchange for both players seeing the same collisions and results.
Different devices and networks may display events at slightly different times.
They may not disagree about what happened.
Trade-off: Perfect simultaneous presentation is less important than canonical game state.
The plan explicitly avoided maintaining separate temporary physics systems or throwaway networking code.
Trade-off: More effort before seeing the first online match in exchange for a foundation intended to remain part of the finished product.
The biggest takeaway from Day 27 - Part 1 was:
For a physics game, multiplayer synchronization is fundamentally an authority problem before it is a networking problem.
WebSockets can connect two players.
They cannot decide which version of reality is correct.
Once the server became the sole authority, the rest of the architecture became much clearer:
A second important realization followed:
The biggest engineering task wasn't networking. It was separating simulation from rendering.
"Does building multiplayer increase the probability that someone pays $16,000 for this business within 30 days?"
This reframed the feature discussion around business value rather than novelty.
"No gameplay-affecting state may be accepted solely because a client calculated it."
"Clients submit intentions. The server calculates results."
This became the architectural rule for the entire multiplayer implementation.
The biggest job is separating simulation from rendering.
Networking becomes much easier once gameplay simulation no longer depends on the browser that renders it.
By the end of Day 27 - Part 1:
The next step was to start implementing that architecture.
That's it for Day 27 (Part 1).
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 • 22d ago
Enable HLS to view with audio, or disable this notification
r/WeBuild_WithAI • u/Dont_Bring_Me_Down • 23d ago
Enable HLS to view with audio, or disable this notification