This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.
Prefer Watching Instead?
If reading isn't your thing,...
For further actions, you may consider blocking this person and/or reporting abuse
I remember this one! This is the one where I didnt realize I actually had to shift to move. Haha!
I totally remember your comment. I was like: βoh no, do I have a bug somewhere?βπ
Then I realized it was by designπ
πππ
240hz isnt even the limit tbh, with 1kHz monitors, the new 'standard' for gaming monitors being up from 144hz to 240hz, with the 'high refresh rate' being 300hz+, it's a bit of a tricky one. My advice, always decouple rendering from the gameloop, else you end up with issues like the old Bionicle game, where if you werent running on a potato, it runs at unplayable speeds.
For perspective, with my current endeavor on the gaming front, I am building Dwarven Stronghold (Think Dwarf Fortress, but written in Rust, so it's not so slow and heavy to run), One of the first things I did, was build the framework for the game, specifically separating the render loop from the simulation loop, so the simulation loop runs as fast as it wants, with the game-loop running at a fixed 'game time : wall clock time', so the sub-second simulations are variable depending on the overhead, while keeping the rendering separate, so the rendering isnt limited by the game's loop. So you can keep 240hz or even 1000hz, even if the game drops it's simulation to 10 TPS. The separation of concerns allows the game to stay smooth, even when the gameloop fluctuates.
Think COD, if you play online and your network drops, you still run around, still shoot, etc. Then disconnect after it times, so it doesnt interrupt the gameplay for minor stutters.
Totally agree. Decoupling render loop from sim loop is the way to go for high refresh rates.
240hz/1000hz monitors are useless if your game logic is tied to FPS.
Fixed timestep for simulation + variable render = smooth gameplay even at 10 TPS.
Great example with Dwarven Stronghold in Rust!
That makes sense π―
Such an insightful comment. That just opens up more things to research for me as a beginner in the game development area.
Thanks a lot!π
Anytime, if you're looking in to game-states, I'd highly recommend looking up merkle roots and how you can use them to track state propagations. It makes sure that anomalies are pruned and that the state is always preserved. If you use hardware AES processing, it's also practically free, because it uses a part of the processor games dont generally use. Just be mindful of how dense you make it, keep it transactional with pointers, not full-on state dumping, else you'll hit OOM in no time.
This is great. Next time Iβll decide to write a game, Iβll definitely get back to your comments!
Same path here - backend habits, no game-dev background, and I also ship a browser game. Although it's just a chat, no fancy visuals. The same bug shape lives one layer up though: the game is tuned against specific AI models, a provider ships a new version, and the bots behave differently on identical code.
The game looks awesome. After the re-tune, does it still feel like the game you built, or are you driving a slightly different car on your own 165Hz now?
Good to know Iβm not the only one.
It feels fine now, but it took quite a lot of tuning and testing. Totally worth it, though.
Hi, there!
I am looking for a partner to collaborate with by sharing an account.
In return, you will receive a 20β30% share;
I hope this collaboration leads to a long-term partnership.
WhatsApp: +1 (910) 852-7435
Telegram: @bytepil0t
So cool! π
Great job!
Thank you!π
It's great idea using articles as a billboard and I enjoyed night driving π
I know, itβs real fun! π
Good technical content. I'd love to see more exploration of the edge cases and failure modes β understanding when and why these patterns break down is often more valuable than knowing how to implement them.
Thanks a lot. It really had me dive DEEP into some low-level stuff.
Great write-up, the part most "just multiply by dt" tutorials skip is exactly the part you nailed: decay and lerp need Math.pow, not linear scaling. The 0.97 * dt = 1.94 example makes the failure mode click instantly.
Thanks a lot. At first I just went for the dt multiplication but I quickly realized it wasnβt gonna cut it.
Hi, there!
I am looking for a partner to collaborate with by sharing an account.
In return, you will receive a 20β30% share;
I hope this collaboration leads to a long-term partnership.
WhatsApp: +1 (910) 852-7435
Telegram: @bytepil0t
Really enjoyed this deep dive. The βmy monitor was secretly a system dependencyβ part made me laugh, but the technical lesson is actually a great one.
I especially liked the distinction between value += rate * dt, exponential decay with Math.pow(factor, dt), and frame-rate-independent lerp. Itβs easy to think βjust multiply everything by delta timeβ solves the problem, but smoothing and decay require a bit more care.
This is also a good reminder that performance bugs arenβt always obvious bugs β sometimes the code works perfectly on the developerβs machine while behaving like a completely different application elsewhere. Great write-up!
Thanks a lot. This is another reminder that sometimes things turn out to be way more complex than they seem.
This is exactly why I like weekend challenges. π The goal isnβt always to build something perfect, itβs to force yourself into territory you normally wouldnβt touch. A backend engineer deciding to build a browser game in two days sounds like the perfect recipe for chaos and learning. Looking forward to seeing how this turned out!
It really was pretty chaoticπ I almost failed to finish itπ
Interesting game, definitely worth playing! π
Thanks! Enjoy!π
Hi, there!
I am looking for a partner to collaborate with by sharing an account.
In return, you will receive a 20β30% share;
I hope this collaboration leads to a long-term partnership.
WhatsApp: +1 (910) 852-7435
Telegram: @bytepil0t
This is a really clean explanation of delta time, the lerp formula
especially, most people just do alpha * dt and don't realize it breaks
down at higher dt values.
Bookmarking this for the next time I touch anything with requestAnimationFrame.
Thanks a lot! I tried my best.π
The interesting part is that the bug wasn't really in the physics formula, it was in an unstated assumption about the environment. That's a pattern that shows up far beyond games: hardware, browser behavior, timing, concurrency, and configuration can quietly become dependencies. Making those assumptions explicit and testing across them is often what separates "works locally" from software that's actually portable.
Exactly! And thatβs the reason why game development is so complicated and tricky. I mean this one was a simple game, nothing complicated in it conceptually, but still, a major issue showed up. Granted, Iβm still a rookie in this regard, but still.
This is such a relatable βworks on my machineβ bug π The 165Hz monitor secretly becoming a system requirement is hilarious, but the explanation of delta time and why simply adding * dt isnβt enough makes this genuinely useful. Great write-up!
Thank you!π
The exponential decay one is the part worth the whole article and i think its sharper than you let on.
you say the naive fix, speed *= 0.97 * dt, is wrong. it is, but its a worse class of wrong than the bug it replaces. the original bug was at least monotonic. everybody got a slower car than you intended, consistently, scaled by their refresh rate. annoying but predictable. the naive fix flips the sign. at dt of 2 you get 1.94 and the car accelerates when it drives off road, so a 30fps player gets the opposite of the mechanic. you didnt just fail to fix it, you built a machine that behaves backwards on the exact hardware that was already suffering most.
and thats the trap in the pattern, its that * dt genuinely works on case one. you learn the rule from the linear case, it rewards you, then you carry it into the multiplier case and it quietly inverts. a fix that works the first three times you try it is how you end up shipping the fourth one without checking.
good writeup. the fact that your own monitor was an untracked variable in every test you ran is the part id put on a sticker.
Hmβ¦ interesting insight Iβll have another look sometime in the future. Thank you!
ππ
β¨β¨
Great Game!
Thanks a lot!π
"Works on my machine" taken to the ultimate physical level: Works on my monitor!
As a backend developer, it is so easy to forget how chaotic the frontend display ecosystem is compared to server environments where parameters are fixed. Hardcoding coordinate logic based on your own screen resolution is a rite of passage every engineer goes through at least once. Rebuilding the canvas loop with proper aspect ratio scaling and resolution independence is a great recovery. Hilarious writeup!
Such a great post-mortem! Canvas coordinate scaling and frame-rate independence catch almost everyone building their first browser game.
Going from hardcoded pixel offsets to a normalized coordinate space (or logical resolution scaled to the viewport) is one of those architectural shifts that feels so satisfying once implemented. The lesson here on separating game-state logic from rendering coordinates is spot on. Thanks for sharing the honest breakdown!
this sound like 'to the mad' ''p
is purely, i like that,, new stuff is now overclock for an idea own who missed a support to work, i take it c[_]
Hi, there!
I am looking for a partner to collaborate with by sharing an account.
In return, you will receive a 20β30% share;
I hope this collaboration leads to a long-term partnership.
WhatsApp: +1 (910) 852-7435
Telegram: @bytepil0t