๐ŸŽฎ Counter-Strike 1.6 โ€” free in your browser, solo vs bots (no real players)

AI-generated summary

:bullseye: What you get: Play Counter-Strike 1.6 offline against bots directly inside your web browser with no account needed.

:white_check_mark: Start here:

  • cs-online.io โ€” instant play offering 26 maps and up to 9 bots without downloads.
  • cs16-solo.sh script โ€” self-hosts the web build locally via Python on port 8099.

:toolbox: Also useful:

  • Custom maps โ€” add custom arenas like aa_dima directly through shell variables.
  • Local configs โ€” adjust bot enemy count, custom keybinds, and instant respawn settings.

:warning: Watch out:

  • Initial load downloads roughly 143 MB online, or ~430 MB when hosting locally.

ONE GAME ยท TWO DOORS ยท ZERO OTHER HUMANS

:globe_with_meridians: Door 1 โ€” the game in a browser tab, this minute: one link, any device
:floppy_disk: Door 2 โ€” the same game on your own computer, kept forever: the single file in the first drawer

:globe_with_meridians: Door 1 :floppy_disk: Door 2
:joystick: Opens with one tap, any device one saved file, once
:hourglass_not_done: First wait ~143 MB ~430 MB
:world_map: Maps 26 26, plus any map you add
:robot: Bots 9, all on the other team you choose 1โ€“10, respawn on
:mobile_phone_off: After that needs the internet runs from your own disk

:globe_with_meridians: Door 1 โ€” in a browser tab

  1. Open cs-online.io/en/#offline โ†’ tap SINGLE PLAYER
  2. Tap any map โ†’ press 2
  3. Click the game once to take the mouse โ†’ you are in, bots on the other side

Tab scoreboard ยท B buy menu ยท F4 change map

:floppy_disk: Door 2 โ€” on your own computer

  1. The main link first โ€” the gameโ€™s own page: the whole game sits there, ~430 MB, and the file below pulls it
  2. Save the drawerโ€™s file as cs16-solo.sh in a new folder, then bash cs16-solo.sh โ€” it pulls that build once (~430 MB) and adds the map
  3. Open http://127.0.0.1:8099 โ†’ F4 โ†’ a map โ†’ 1

127.0.0.1 is your own computer โ€” the name a machine uses for itself. The game opens from your own disk, nothing leaves it.

๐Ÿ“œ The whole file โ€” copy this, save as cs16-solo.sh

Tap the copy icon at the top right of the block โ€” it takes the whole file in one go.

#!/usr/bin/env bash
# Counter-Strike 1.6 โ€” offline, in your browser, solo vs bots.
# One-time setup: pulls the public CS 1.6 web build + game files, adds a custom
# map, sets your enemy count and respawn, then serves on http://127.0.0.1:8099
set -euo pipefail

# -------- the lines you change --------
ENEMIES=7                                  # bots you face (1..10)
RESPAWN=1                                  # 1 = back the instant you die
MAP_NAME="aa_dima"                         # the custom map to add
MAP_URL="https://fastdl.gamehosting.rs/cstrike/maps/aa_dima.bsp"
NAV_URL="https://fastdl.gamehosting.rs/cstrike/maps/aa_dima.nav"
# ------------------------------------------

BASE="https://s3.ru1.storage.beget.cloud/fa44ebbed79a-mingame-cloud/cs16-web"
DIR="${1:-$HOME/cs16-solo}"
mkdir -p "$DIR/vendor" "$DIR/nav" "$DIR/cfg" "$DIR/maps"
cd "$DIR"

echo "โ–ถ game files (one time, ~430 MB)โ€ฆ"
[ -f valve.zip ] || curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$BASE/valve.zip" -o valve.zip
curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$BASE/index.html" -o index.html
for f in vendor/jszip.min.js vendor/raw.js vendor/extras.pk3 vendor/xash.wasm vendor/filesystem_stdio.wasm vendor/libref_webgl2.wasm vendor/menu_emscripten_wasm32.wasm vendor/cs_emscripten_wasm32.wasm vendor/client_emscripten_wasm32.wasm nav/manifest.json; do
  curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$BASE/$f" -o "$f"
done
for n in $(python3 -c "import json;print(' '.join(json.load(open('nav/manifest.json'))))"); do
  curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$BASE/nav/$n" -o "nav/$n"
done

echo "โ–ถ memory fix (stops the page running out of RAM mid-map)"
python3 - index.html <<'PY'
import pathlib, sys
p = pathlib.Path(sys.argv[1])
s = p.read_text()
if 'cs16-solo patched' in s:
    sys.exit(0)
a = 'const zip = await JSZip.loadAsync(await fetchZipBytes());'
b = '            files[path] = await file.async("uint8array")\n        }))'
c = 'this.FS.writeFile(k, files[k]);'
for line in (a, b, c):
    if line not in s:
        sys.exit('unexpected build layout at: ' + line[:40])
s = s.replace(a, 'let zip = await JSZip.loadAsync(await fetchZipBytes()); // cs16-solo patched')
s = s.replace(b, b + '\n        // cs16-solo patched: everything is unpacked, drop the archive copy\n        zip = null;')
s = s.replace(c, c + '\n                        delete files[k]; // cs16-solo patched: the engine has its copy now')
p.write_text(s)
print('  patched', p)
PY

echo "โ–ถ adding map: $MAP_NAME"
curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$MAP_URL" -o "maps/$MAP_NAME.bsp"
if [ -n "$NAV_URL" ]; then curl -sk --tlsv1.2 -A 'Mozilla/5.0' "$NAV_URL" -o "nav/$MAP_NAME.nav"; fi
python3 - "$MAP_NAME" <<'PY'
import sys, zipfile
name = sys.argv[1]
inner = f"cstrike/maps/{name}.bsp"
with zipfile.ZipFile('valve.zip', 'a') as z:
    if inner not in z.namelist():
        z.write(f"maps/{name}.bsp", inner)
print('  map inside the archive:', inner)
PY
[ -f "nav/$MAP_NAME.nav" ] && python3 - "$MAP_NAME" <<'PY'
import json,sys
name=sys.argv[1]
nav=json.load(open('nav/manifest.json'))
if f"{name}.nav" not in nav:
    nav.append(f"{name}.nav")
    json.dump(sorted(nav), open('nav/manifest.json','w'), indent=2)
PY

echo "โ–ถ $ENEMIES enemies ยท respawn $RESPAWN"
cat > cfg/listenserver.cfg <<EOF
mp_maxmoney 16000
mp_startmoney 16000
mp_timelimit 0
mp_roundtime 5
mp_freezetime 0
mp_buytime 0.5
mp_friendlyfire 0
mp_autoteambalance 0
mp_limitteams 0
bot_join_team T
bot_join_after_player 0
bot_quota $ENEMIES
bot_difficulty 2
mp_forcerespawn $RESPAWN
mp_randomspawn $RESPAWN
mp_respawn_immunitytime 2
mp_round_infinite 1
mp_buy_anywhere 1
humans_join_team ct
EOF
cat > cfg/userconfig.cfg <<EOF
name "Player"
maxplayers 16
sv_lan 1
alias bots_add "bot_add"
bind "=" "bots_add"
bind "BACKSPACE" "bot_quota 9"
bind "DEL" "bot_quota 0"
bind "CAPSLOCK" "+duck"
unbind "CTRL"
mp_autoteambalance 0
mp_limitteams 0
bot_quota $ENEMIES
EOF

echo "โ–ถ ready โ€” open http://127.0.0.1:8099  (Ctrl+C stops)"
python3 -m http.server 8099 --bind 127.0.0.1

Needs: bash, python3, curl โ€” already on Linux and macOS. Windows: wsl --install, then the same three steps.

โš™๏ธ Make it yours โ€” 1 vs 10, instant respawn, any map

In cs16-solo.sh, the top four lines are yours:

ENEMIES=7      # bots in front of you, 1 to 10
RESPAWN=1      # 1 = back the instant you die, 0 = wait for the round
MAP_NAME="aa_dima"
MAP_URL="https://fastdl.gamehosting.rs/cstrike/maps/aa_dima.bsp"

aa_dima is a small aim map, already included โ€” its page. Swap those two lines for any .bsp address and the map lands in the list.

In game: = adds a bot, - removes one, Backspace fills the team back up, Delete clears them, Caps Lock crouches.

:chequered_flag: Pick a door, spawn in, and every round is yours โ€” no lobby, no rank, no one shouting at you.

1 Like