- Every attack is now assembled from traits on its definition instead of per-weapon code: an anchor and path (thrusts, out-and-back, arcs), shared flight physics (gravity, drag, acceleration, homing, and one wall response: end, burst, stick, crawl, bounce, stop, pass, return, latch), and flags like bouncy, drifting, tethered, orbiting, instant and arming. Melee are projectiles too. - Shots have a lifetime and a fade (when damage bottoms out). Range is speed times lifetime. Ricochets and the Vacuum wind lifetime back. - The Vacuum pulls anyone's shots, and its airblast flips them out along the aim, claiming enemies' (fading into your colour). - New trinket: Hourglass, longer projectile lifetime and range. Ropes and chains lengthen with it and the Accelerator. - Fashion: 23 items worn on the head, face or torso, chosen in Profile. - Flamethrower flames hit continuously, the whip coils and sweeps, bouncing shots roll over ramps, and Ricochet relights grenade fuses. - Profile tab, colour tooltips, option hints on every setting, an About tab with credits and links, and the Ithaca font. - Loadouts lock once readied, tomatoes clear with the match, and the round-over pause is 4 seconds. - CC0 license. Tools and CLAUDE.md are no longer tracked, and the web shell moves to web/.
Smack a Brother
Online platform fighter. Lobbies of up to 16 players, games of up to 8. Play it in the browser here.
Clarification
This application was developed with the assistance of a large language model.
Build
After cloning and entering the repository's directory, make sure to initialize the submodules:
git submodule update --init --recursive
Everything (SDL, libdatachannel, simdjson) is built statically from the submodules. The game's resources are in resources/ and get linked next to the executable.
Linux
Needs OpenSSL, plus the X11/Wayland and audio headers SDL builds against.
mkdir build
cd build
cmake ..
make
Web
Needs the Emscripten SDK.
emcmake cmake -B build-web -DCMAKE_BUILD_TYPE=Release
cmake --build build-web
This makes smack-a-brother.html, .js, .wasm and .data. Rename the .html to index.html and serve all four.
Server
The server builds on its own, without SDL. It needs OpenSSL (libssl-dev on Debian).
cmake -S server -B build-server -DCMAKE_BUILD_TYPE=Release
cmake --build build-server
Run it with:
smack-a-brother-server [port] [first UDP port] [last UDP port]
Defaults are 47800, 47810 and 47899. It only listens on 127.0.0.1, so put it behind a reverse proxy that handles TLS. For nginx:
location /smack-a-brother/ws {
proxy_pass http://127.0.0.1:47800;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 120s;
}
Open the UDP range in the firewall (e.g. ufw allow 47810:47899/udp).
Netcode
- The server runs every lobby: a sandbox everyone in the lobby shares, plus the games queued in it. Each is its own simulation. All of them run on one thread, at 60 ticks a second.
- Clients send their inputs ahead of time. Each tick the server takes what has arrived (repeating a player's last inputs if they're late), steps the simulation, and sends everyone the inputs it used. Every 60 ticks it also sends a checksum.
- Clients run the same simulation about 3 ticks ahead of the server, guessing other players' inputs. When the server's inputs differ from the guess, the client rolls back and replays.
- The simulation is deterministic on every platform (strict floating point, own maths functions), so desktop and web play together.
- Clients connect over a WebSocket first (lobbies, chat, WebRTC signaling). Then they open a WebRTC connection to the server with two data channels: a reliable one, and an unreliable one for inputs and frames. If WebRTC can't connect, everything stays on the WebSocket.
- STUN:
stun.l.google.com:19302. - The server address is set in Settings. Default:
wss://shweetz.net/smack-a-brother/ws.
Joining a lobby directly
- Desktop:
smack-a-brother --join CODE - Web:
https://shweetz.net/smack-a-brother/?lobby=CODE
Environment variables
SAB_SERVER_URL: use a different server, e.g.ws://127.0.0.1:47800SAB_NET_LAG: add this many milliseconds of lagSAB_NET_LOSS: drop this percent of input packetsSAB_NET_STATS: log how the client is keeping up with the server
License
The game's code and art are released into the public domain under CC0 1.0. Not covered by that: the Ithaca font (SIL Open Font License, see resources/font/LICENSE.txt), the sound effects cut from the Sound Ideas libraries (see resources/sfx/SOURCES.md), and the libraries in external/, each under its own license.



