Elite Duel Speed manual
This manual ships with the game as manual.md in the game folder. In game, open it from the main menu with Manual, bottom right.
Getting started
Main menu
- Play: servers, your own lobby, and race time trials.
- Watch: replays saved on this machine.
- Maps: installed maps, custom maps, tracks, and the map and track editors.
- Settings: everything in Settings.
- The profile button, top right, opens Customize: character, outfit, emotes, dances and cards.
- Feedback, bottom right next to Manual and also on the pause screen, sends a bug report or an idea to the developers. A report carries what you type, your Steam name and ID, the game build, what you were doing, and this session's log unless you untick it.
The line next to Manual shows the game version, build number and commit. Settings > About has the full report and a Copy report button for bug reports.
Play
- Browse: dedicated servers run by other people. See Playing online.
- Custom: host a lobby on this machine. See Listen server.
- Race: time trials against the clock and other players' ghosts.
- The code box at the top joins a lobby by its five character invite code.
Online play needs Steam running.
Game modes
| Mode | Id | Rules |
|---|---|---|
| Duel | duel | Two teams. Win two fights to take a round. Each fight draws a gun from the lobby's pool. |
| Free-for-all | ffa | Everyone for themselves. The last player standing takes the round. |
| Tag | tag | One player is it, with a one round pistol. Shoot someone to pass it on. The least time spent as it wins. By default only a headshot tags. |
| Race | race | Time trials on a track. |
| Gun Game | gungame | Kills move you up a ladder of guns. |
| HORSE | horse | One player sets a mark. Everyone else has to reach it before time runs out. |
| Bomb | bomb | Two teams, one bomb. A random attacker starts with it on key 3, in place of their utility gun for the round. Attackers plant it on a site; defenders stop them or defuse it. Needs a map with bomb sites. |
| Capture the Flag | ctf | Two teams, two flags. Bring the enemy flag home while yours is on its stand. Needs a map with flag stands. |
Warmup and matches
A lobby starts in warmup. Everyone can move and shoot, and a death only costs a short respawn. The lobby owner starts a match from Esc > Manage lobby > New match, which sets the mode, map, guns and round limit. If the owner leaves, the next player in the lobby becomes owner.
Movement
- Hold jump to bunny hop. Jumping skips ground friction.
- Strafe and turn in the air to gain speed.
- Crouch while running fast to slide. Jump out of a slide to keep the speed.
- Press jump in the air next to a wall to wall jump. Chains of wall jumps work on any wall.
- Hold forward into a ledge between waist and head height to climb it.
- Face a ladder and hold forward to climb. Jump to get off.
- Steps up to 18 units are climbed without jumping. Slopes steeper than 45 degrees are surfable.
The training range is the default map. It has lanes and props for practicing each of these.
Controls
Default binds
| Key | Name | Command | Action |
|---|---|---|---|
| W | KeyW | +forward | Move forward |
| S | KeyS | +back | Move back |
| A | KeyA | +left | Strafe left |
| D | KeyD | +right | Strafe right |
| Space | Space | +jump | Jump |
| L Ctrl | ControlLeft | +crouch | Crouch / slide |
| Caps | CapsLock | +crouch | Crouch / slide |
| L Shift | ShiftLeft | +sprint | Sprint |
| Mouse 1 | MouseLeft | +fire | Fire |
| Mouse 2 | MouseRight | +ads | Aim down sights |
| R | KeyR | +reload | Reload |
| E | KeyE | +use | Use / open door |
| Tab | Tab | +scoreboard | Scoreboard |
| T | KeyT | +chat | Chat |
| G | KeyG | +emote | Emote wheel |
| F | KeyF | +dance | Dance wheel |
| Escape | Escape | +menu | Menu |
| V | KeyV | +reset | Reset / restart run |
| C | KeyC | +checkpoint_back | Back to last checkpoint |
| F7 | F7 | toggle hud.show | |
| F1 | F1 | hud_edit | Edit HUD |
| 1 | Digit1 | +weapon_1 | Weapon slot 1 |
| 2 | Digit2 | +weapon_2 | Weapon slot 2 |
| 3 | Digit3 | +weapon_3 | Weapon slot 3 |
| 4 | Digit4 | +card | Playing card |
| B | KeyB | +loadout | Loadout |
| Backquote | Backquote | toggleconsole | Console |
Loadout and wheels
Keys 1 to 3 draw your loadout slots: a primary, a sidearm and something to throw. Hold one to open the gun wheel and pick a gun for that slot. 4 draws your playing card; hold it for the card wheel. G and F open the emote and dance wheels. B opens the loadout screen with four named presets.
In a duel the fight hands out the gun. Loadouts apply in warmup, on the range, and in modes where everyone brings their own guns.
A loadout mode gives each key a job. By default key 1 takes any rifle, SMG, sniper or shotgun, key 2 any sidearm, and key 3 the grenade or the sawed-off, carrying three, four and two magazines. Servers set their own with sv.loadout_1 to sv.loadout_3 and sv.spares_1 to sv.spares_3; a lobby owner moves the same values with game.loadout_* and game.spares_*. A rule is a list of words, where a plural is a whole class (rifles, smgs, shotguns, snipers, sidearms, specials) and a singular is one gun by tag. The spare counts are magazines beyond the one loaded; -1 leaves reloads unlimited.
The loadout screen shows the rules: each slot says what it takes and how much ammo it carries, every gun is badged with the keys it may sit on, and choosing a slot narrows the grid to what fits. Guns that belong on another key, and guns the server does not offer, sit dimmed below. A preset that does not fit the server is flagged, with one button to move its guns onto keys that will take them.
Spectating
Fire and reload cycle the player you watch. Jump switches between following and free camera. Crouch switches between first and third person.
Changing binds
Settings > Controls has a bind table with two keys per action. Click a slot and press a key or mouse button. Escape cancels. Right click clears a slot.
From the console:
bind KeyG +emote
bind MouseMiddle "toggle hud.show"
unbind KeyG
bindsKey names follow the table above: KeyA to KeyZ, Digit0 to Digit9, F1 to F24, Space, Tab, Escape, Backquote, ShiftLeft, ControlLeft, AltLeft, arrow keys, Numpad0 to Numpad9, MouseLeft, MouseRight, MouseMiddle, MouseBack, MouseForward, WheelUp and WheelDown. Short forms like mouse1, ctrl, shift and single letters also work.
The last key bound to +menu cannot be unbound.
Settings
Settings are console variables. Every row below shows its variable, so you can also set it from the console or a config file. See Console and config files.
Reset all, top right of the settings screen, restores every setting and bind to its default.
General
Gameplay
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Aim down sights | Hold | Hold, Toggle | input.ads_toggle | The aim key toggles the sights instead of being held |
| Gun hand | Right | Right, Left | profile.hand | Gun hand |
Replays
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Save replays | On | Off, On | net.auto_replays | Save a replay of every match |
Discord
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Presence | On | Off, On | discord.presence | Rich presence |
| Lobby invites | On | Off, On | discord.lobby_invites | Lobby invites in presence |
Steam
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Keep settings and HUD layouts in Steam Cloud | Off | Off, On | app.cloud_sync | Push config.cfg and hud_profiles.json to Steam Cloud on every save |
Controls
Mouse
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Mouse sensitivity | 0.04 | 0.005 to 0.3 | input.sensitivity | Degrees of view rotation per mouse count |
| Zoom sensitivity | 1 | 0.2 to 2 | input.zoom_sens | Multiplier on the focal-length sensitivity scale through a magnified scope |
Crosshair
The crosshair panel sets style, length, gap, thickness, colour and outline, with a live preview. The variables start at crosshair.style.
HUD
Overlay
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Show HUD | On | Off, On | hud.show | Draw the HUD |
| Scale | 1 | 0.5 to 2 | hud.scale | Size of the overlay |
| Update rate | 0 Hz | 0 to 1000 Hz | hud.max_hz | HUD updates per second; 0 sends one every frame |
HUD editor
Press F1 in game to edit the HUD. Drag panels to move them and drag edges to resize. Delete removes a panel, Ctrl+Z undoes, Ctrl+D duplicates, arrow keys nudge by 1 pixel and Shift with an arrow key by 10. Esc or F1 leaves the editor.
HUD profiles
A profile is one HUD layout. The Profiles panel picks the default profile and can assign a different one to each game mode and to spectating. Profiles are stored in hud_profiles.json next to config.cfg. The hud_profile and hud_profiles commands do the same from the console.
Video
Display
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Window | Borderless | Windowed, Borderless, Fullscreen | video.mode | Window mode |
| Display | Primary | Primary or a monitor | video.monitor | Display to use; empty means the primary |
| Window width | 1600 px | 640 to 16384 px | video.width | Window width in windowed mode |
| Window height | 900 px | 480 to 16384 px | video.height | Window height in windowed mode |
| V-sync | Off | Off, On, Fast | video.vsync | Off presents as soon as a frame is done, On waits for the display, Fast keeps only the newest frame |
| Frame cap | 0 Hz | 0 to 1000 Hz | video.fps_cap | Frame cap; 0 follows the monitor |
| Low latency | On | Off, On, Boost | video.low_latency | NVIDIA Reflex or AMD Anti-Lag when the driver offers it |
| Render scale | 100% | 50 to 200% | video.render_scale | Scene resolution as a share of the window; above 100 supersamples |
| Field of view | 105 deg | 70 to 130 deg | video.fov | Horizontal field of view |
| View model FOV | 65 deg | 50 to 90 deg | video.viewmodel_fov | Field of view the held weapon is drawn with |
| Brightness | 1 | 0.5 to 2 | video.brightness | Exposure multiplier |
| Reticle brightness | 1 | 0.2 to 2.5 | video.reticle_brightness | How bright a red dot or holo reticle is drawn |
| Gamma | 2.2 | 1.8 to 2.6 | video.gamma | Output gamma |
Quality
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Quality | Medium | Competitive, Low, Medium, High, Ultra, Custom | video.quality | Render preset; changing a detail below makes it Custom |
| Shading | Quality | Competitive, Quality | video.shading | Competitive is the flat, high contrast look; Quality is the full lighting model |
| Surface detail | High | Low, High | video.surface_detail | Normal, roughness, emissive and directional lightmap detail on surfaces |
| Shadows | Medium | Off, Low, Medium, High, Ultra | video.shadows | Sun shadow resolution, reach and softness |
| Dynamic shadows | On | Off, On | video.dynamic_shadows | Shadows cast by players and props |
| Ambient occlusion | Low | Off, Low, Medium, High | video.ambient_occlusion | Screen space contact shading |
| Reflections | Low | Off, Low, High | video.reflections | Reflection detail |
| Water | Medium | Low, Medium, High | video.water | Water surface detail; Medium refracts and reflects the scene, High adds screen space reflections and caustics |
| Bloom | Off | Off, On | video.bloom | Glow around bright light, where the map style uses it |
| Dynamic lights | On | Off, On | video.dynamic_lights | Muzzle flashes and explosions light the world |
| Physics props | On | Off, On | video.physics_props | Bottles, crates and barrels react to the player, shots and blasts |
| Card trails | On | Off, On | video.card_trails | Ribbons, glyph walls, smoke, stars and wires trailing behind players holding a foil card |
| Anisotropic filtering | 8x | Off, 2x, 4x, 8x, 16x | video.anisotropy | Texture sharpness at grazing angles |
| Texture detail | High | Low, Medium, High | video.texture_detail | Lower levels skip the sharpest mip levels |
| Anti-aliasing | Off | Off, FXAA | video.antialiasing | Edge smoothing; render scale above 100 supersamples as well |
| Sharpening | 0 | 0 to 1 | video.sharpen | Contrast adaptive sharpening after anti-aliasing |
Picking a Quality preset sets the detail rows under it. Changing one of those rows sets Quality to Custom. Window width and height only apply in Windowed mode.
Audio
Volume
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Master volume | 0.75 | 0 to 1 | audio.master | Master volume |
| Sound effects | 1 | 0 to 1 | audio.sfx | Sound effects |
Spatial
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Spatial audio | Headphones | Headphones, Speakers | audio.spatializer | Spatial audio |
| Reverb | On | Off, On | audio.reverb | Reverb |
Radio
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Play the station | On | Off, On | audio.radio | Play the music a server is streaming; off tells the server to send none of it |
| Station volume | 0.5 | 0 to 1 | audio.radio_volume | How loud the server's station is |
Network
Crash reports
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Upload crash reports | Off | Off, On | oiko.upload_crash_dumps | After a crash, send the minidump, the log and the build to the developers on the next launch |
Maps
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Download maps | On | Off, On | net.auto_maps | Download a lobby's map when this client lacks it |
Replays
| Setting | Default | Values | Variable | Description |
|---|---|---|---|---|
| Upload match replays | On | Off, On | net.upload_replays | Send a replay of every match you host to the backend |
Dedicated server keys
A server key lets a dedicated server upload replays and match results. Sign in, then use Generate. Keys start with eds_sk_. Copy, rename or revoke them here. See Server list and server key.
About
Build, Steam and session details. Copy report puts all of it on the clipboard. The version and status console commands print the same.
Steam Cloud
With Settings > General > Steam > Keep settings and HUD layouts in Steam Cloud on, config.cfg and hud_profiles.json sync through Steam Cloud. Video settings stay local to each machine.
Console and config files
Console
Press ` (Backquote) to open the console. Tab completes names. Up and Down walk history. Ctrl+R searches history. Ctrl+F searches the output. Esc closes it.
helplists everything.help <name>explains one command or variable.varslists variables.vars videolists one namespace.vars --changedlists what differs from the defaults.vars --tableopens a searchable table.
Console size, font and opacity are the console.* variables, starting at console.height.
Syntax
set video.fov 110
get video.fov
toggle hud.show
cycle video.vsync
inc input.sensitivity 0.005
reset video.fov
set profile.loadout_names [Assault, Close, Long, Utility]
alias fast "set video.quality Competitive"
exec practice.cfg
writeconfig backup.cfg --changed- One statement per line, or several split with
;. - Quote values with spaces.
- Lists use
[a, b]. - Enum values ignore case. The console uses the names from Console variables, which can differ from the menu labels. For example
video.vsync Mailboxis shown as Fast. - Numbers outside a variable's range are clamped.
- Lines starting with
#or//are comments.
config.cfg
The game saves settings, binds and aliases to config.cfg shortly after every change. It uses the first of these that applies:
- The path in the
EDS_SETTINGSenvironment variable. config.cfgin the working directory, if it exists.config.cfgnext to the game executable, if it exists. Use this for a portable install.~/.config/eds/config.cfgon Linux,%APPDATA%\eds\config.cfgon Windows.
autoexec.cfg
autoexec.cfg in the same folder as config.cfg runs after it on every start. Use it for commands you want to run every time the game starts.
Playing online
Server browser
Play > Browse lists servers.
- Internet: every public server. Filter by mode and hide full, empty or other version servers.
- Favorites: servers you starred.
- History: servers you connected to recently.
- Lobbies: public lobbies hosted by players.
- Direct: type
host:portand press Connect or Watch. The port is required. The default server port is27960.
Connect takes a seat. Watch joins as a spectator. A server that asks for a password prompts for it.
From the console: connect <host:port>.
Servers and the hub
Joining a dedicated server puts you in its hub. The hub shows the server's arenas, the rotation, and the ranked ladder or track records. Play takes a seat. On a ranked server Play joins the solo or duo queue.
Invite codes
Every lobby has a five character code. Type it into the box on the Play screen, or use join <code> to play and watch <code> to spectate. Esc > Manage lobby shows the code with a Copy button.
Map downloads
If a lobby runs a map you do not have, the game downloads it. Turn this off with Settings > Network > Download maps. Downloaded maps are cached and do not show in your map list.
Replays
With Settings > General > Save replays on, every match is saved on this machine. Watch lists them. Open folder shows where they are.
savereplaysaves the current match so far.recordstarts a server-side recording, including warmup.stopends it and saves it here. Lobby owner or admin only.
Replay controls: Space play and pause, Left and Right seek (hold Shift for bigger steps), , and . step one tick, [ and ] change speed, Tab switches camera, Up and Down jump between marks.
Hosting a server
Listen server
Play > Custom hosts a lobby on this machine. Others join through Steam, so no port forwarding is needed.
- Who can join: Invite only, Friends or Public. Public lobbies show in Browse > Lobbies.
- Invite friends sends invites through Steam. The invite code works too.
- New match sets the mode, map, guns and limits. End match returns to warmup.
- The owner can kick players.
Lobby rules are the game.* variables. See game. Set them from the lobby screens, or with set in the console while you own the lobby.
Dedicated server
eds-server is the dedicated server. It ships in the game folder next to the game executable (eds-server.exe on Windows). In Steam, find the folder with right click > Manage > Browse local files.
Run it from a terminal inside the game folder. It reads server.cfg, writes its database and looks for maps relative to the folder it is started from.
cd "<game folder>"
./eds-server --hostname "my server" --map ut_uptownA server runs one of three modes, set with sv.mode:
game: a rotation of maps and modes for whoever joins.ranked: a rated ladder with solo and duo queues.race: time trials on a rotation of tracks, with server records.
Settings apply in this order, later wins:
server.cfgin the working directory.- Environment variables.
- Command line flags.
Changes to sv.bind, sv.mode, sv.backend, sv.db, sv.default_map, sv.tracks_dir, sv.record and sv.record_dir need a restart. Everything else applies live.
Stop the server with Ctrl+C. It logs to the terminal.
Ports
The server uses one UDP port, 27960 by default, for gameplay, browser pings and map downloads. Forward that UDP port on your router to host on the internet. No TCP ports are needed.
Change it with --bind 0.0.0.0:27970 or sv.bind.
On Linux the server asks for large UDP buffers. If it logs that it got less, raise net.core.rmem_max and net.core.wmem_max.
server.cfg
server.cfg uses console syntax. Every sv.* variable is listed under sv.
set sv.mode game
set sv.hostname "my server"
set sv.region "eu-west"
set sv.password ""
set sv.admins [steam:76561198000000000]
set sv.rotation [ut_uptown:ffa, q3_aerowalk:gungame, ut_uptown:tag]
set sv.max_players 16
set sv.warmup_secs 20
exec extra.cfgCommand line flags
| Flag | Does |
|---|---|
--bind <addr:port> | Sets sv.bind. |
--mode <game|ranked|race> | Sets sv.mode. |
--hostname <name> | Sets sv.hostname. |
--password <text> | Sets sv.password. |
--map <name> | Sets sv.default_map. |
--max-players <n> | Sets sv.max_players. |
--max-viewers <n> | Sets sv.max_viewers. |
--public-addr <host:port> | Sets sv.public_addr. |
--private | Sets sv.public to false. |
--db <file> | Sets sv.db. |
--backend <url> | Sets sv.backend. |
--maps-dir <dir> | Looks for maps here. Repeat for more folders. The first one replaces the default assets/maps. |
--radio-dir <dir> | Sets sv.radio_dir, and turns the station on. |
--record-dir <dir> | Records matches to this folder. |
--no-record | Does not record matches. |
--no-downloads | Does not send maps or replays to clients. |
--cheats | Allows noclip in every arena. |
--exec "<line>" | Runs a console line after server.cfg. Repeat for more. |
--snapshot-div <n> | Sets sv.snapshot_div. |
--spectator-snapshot-div <n> | Sets sv.spectator_snapshot_div. |
--download-mbits <n> | Sets sv.download_mbits. |
--max-downloads <n> | Sets sv.max_downloads. |
--max-replays <n> | Sets sv.max_replays. |
--replay-keep-secs <n> | Sets sv.replay_keep_secs. |
--race-track-secs <n> | Sets sv.race_track_secs. |
--control-socket <path> | Serves the control API on a unix socket. |
--control-tcp <addr:port> | Serves the control API on TCP. Anyone who can reach it controls the server. |
--no-control | Turns the control API off. |
-v, -vv | More logging. |
Environment variables
| Variable | Does |
|---|---|
EDS_BIND | Sets sv.bind. |
EDS_PUBLIC_ADDR | Sets sv.public_addr. |
EDS_BACKEND | Sets sv.backend. |
EDS_BACKEND_KEY | Sets sv.key. |
EDS_MAPS_DIR | Map folders, separated by : on Linux and ; on Windows. Default assets/maps. |
EDS_REPLAY_DIR | Where recordings go. |
EDS_RADIO_DIR | Where the station's songs and playlists live. Default radio beside the server. |
EDS_CONTROL_SOCKET | Control API address. tcp:<addr:port> or <ip:port> is TCP, anything else a unix socket path. |
Server list and server key
While sv.public is on, the server lists itself in every player's browser. --private keeps it off the list. Players can still connect directly.
The browser shows the address the server registered from, with its bound port. If players reach it on a different address or port, set sv.public_addr.
To upload replays and match results, the server needs a key. Generate one in game under Settings > Network > Dedicated server keys, then pass it with the EDS_BACKEND_KEY environment variable or set sv.key in server.cfg. Prefer the environment variable so the key stays out of files you share.
Players and admins
sv.passwordmakes players enter a password to connect.sv.authisrequiredby default: players must be signed in through Steam.optionalandoffrelax it.sv.adminslists admin player ids, likesteam:76561198000000000. Find your Steam ID in Settings > About. Withsv.auth required, an empty list means nobody is admin.
Admins get the server panel from the hub or the Esc menu: players, kicks and bans, banlists, the rotation, every sv.* variable, and a server console. A ban keeps somebody off this one server; a banlist is kept on the backend and shared with every server that follows it, and the official banlist is one every server takes unless its operator turns sv.official_bans off. In the game console, rcon <line> runs a line on the server, and set sv.<name> <value> on a server you administer is sent over rcon. The server commands are listed under Server.
Maps on a server
The server loads every .blvl file in its map folders, assets/maps by default. The map name is the file name without .blvl, in lowercase. The extension must be lowercase. Add folders with --maps-dir or EDS_MAPS_DIR.
Players who lack a map download it from the server. sv.download_mbits and sv.max_downloads limit the upload. sv.map_url points players at a web mirror first, as <url>/<name>.blvl. sv.map_url_only sends maps only through that mirror.
Rotation, ranked and race
- Game servers:
sv.rotationlistsmapormap:modeentries. Rotation modes areffa,tag,gungame,horse,bombandctf. A match starts oncesv.autostart_playersplayers are seated.sv.warmup_secsandsv.results_secsset the pauses. Userotation add,rotation remove,nextmapandmapto change it live. - Map voting:
sv.mapvote trueputs a ballot in front of players when a match ends instead of simply stepping to the next entry. The match summary steps aside after a few seconds, so everyone is back on the map and free to move while they pick with the number keys or thevotecommand.sv.mapvote_choicesis how many entries are offered andsv.mapvote_secshow long the ballot stays up, holding the results screen for at least that long. The pool is drawn from the rotation, never including what is playing now, weighted bysv.mapvote_recency(how hard it keeps off what was played lately) andsv.mapvote_popularity(above 0 offers frequent winners more often, below 0 less, 0 ignores the record). Ties break at random, and a ballot nobody answers still picks one of its own entries.mapvote status|open|close|cancel|resetdrives it by hand;resetforgets what has been played and what has won. - Ranked servers: set
sv.mode ranked. Thesv.ranked_*variables set rounds, queue widening and pauses. - Race servers: set
sv.mode raceandsv.tracks_dirto a folder of.btrkfiles.sv.rotationlists track ids.sv.race_track_secssets how long each track runs. Withsv.race_rules practice, a runner who falls goes back to their last checkpoint instead of restarting.
Radio
A server can play music to everyone on it. Put songs in a radio directory beside the server, turn it on, and restart:
set sv.radio trueEvery sv.radio_* variable is listed under sv. sv.radio and sv.radio_dir need a restart because they decide whether the server owns a station at all; everything else applies live.
What plays. Any .flac, .mp3, .ogg, .wav, .aiff, .m4a or .aac file under radio, including in subdirectories, so an Artist/Album tree works as it is. Titles, artists, albums and album art are read from the files' own tags; a file with no title shows its name. A cover can also sit beside the songs as cover.jpg, folder.jpg, front.jpg or album.jpg.
.opus files are not played. The decoder the game ships has no Opus support, so they are skipped with a line in the log saying so — convert them to FLAC and they will play.
Playlists. A name.txt at the top of radio is a playlist. One entry per line, each a path relative to radio or just a file name; # and ; start a comment and blank lines are ignored. Pick one with set sv.radio_playlist name, or leave it empty to play everything. set sv.radio_shuffle true plays in a random order either way, and never repeats a song immediately.
How it sounds. Whatever the operator collected is decoded and re-encoded to 48 kHz stereo FLAC, so a lossless source stays lossless and players receive a stream rather than your files. That costs about 0.9 Mbit/s per listener; sv.radio_mbits caps what the station may spend in total and sv.radio_max_listeners caps how many people it takes. A listener past either is told the station is full rather than everyone being turned down. The radio has first call on sv.download_mbits and map transfers take what is left, because a download that slows down merely finishes later while a stream that slows down stutters.
Players hear it about sv.radio_buffer_secs behind the server, all at the same point in the song. They can turn it off in Settings > Audio, which stops the server sending them anything at all.
Driving it. radio on the console, or the Radio tab of the server panel:
radio status
radio skip
radio pause
radio play
radio playlist chill
radio shuffle on
radio list drive
radio jump 41
radio rescanradio list searches and pages the library and prints each track's number; radio jump takes one of those numbers, or part of a title. sv.radio_scan_secs re-reads the directory on a timer if songs are added while the server runs.
Control API
--control-socket serves a JSON API for scripts and panels: server status, lobbies, console lines and events. Whoever can open the socket controls the server, so set its file permissions with care.
The station is on there too: GET /radio for what is playing, GET /radio/tracks?q=&page= and GET /radio/playlists for the library, and POST /radio/<action> for play, pause, skip, restart, rescan, playlist, shuffle and jump. They run the same code the radio console command does, so nothing can do one thing here and another there.
Scripting
A dedicated server can run JavaScript files that react to what happens on it, add ! chat commands, and run console commands. Each script runs in its own sandbox on a thread of its own, so a slow or broken script never holds up the game.
Enabling scripts
Put scripts in a scripts directory beside the server (/srv/eds/scripts in the Docker image), then name the ones to run:
set sv.scripts [skipsong, skipvote]A name is the file name without .mjs or .js. Take a name out of the list to stop that script and put it back to start it again. script reload <name> loads a changed file, script list shows what is running, and script info <name> shows a script's commands, what it listens to and its last error. Scripts do not run on a listen server.
sv.scripts_dir moves the directory and needs a restart. sv.script_mem_mb caps each script's memory. sv.script_budget_ms caps how long a script may run for one event, command or timer: past it, the script is stopped mid-call. A script that errors 10 times in a minute is unloaded.
What a script may run
A script must start with a list of every console command it will run:
export const commands = ["radio skip", "announce", "tell"];Only comments may come before it, and the list holds plain strings. The server reads it before the script runs and refuses any other command the script tries. An entry is a command, or a command and its first word:
"announce"allowsannouncewith anything after it."radio skip"allowsradio skipand nothing else fromradio.- Variables must be named:
"set sv.warmup_secs"or"get sv.rotation". A baresetis refused.
Some commands and variables are never given to a script, and a script that lists one does not load: exec, writeconfig, alias, unalias, bind, unbind, binds, vars, script, history and clear, and sv.key, sv.backend, sv.password, sv.admins, sv.auth, sv.auth_keys and every sv.script* variable. Read the list before enabling somebody else's script. Every command a script runs is written to the server log.
Writing a script
Scripts import what they need from eds:
export const commands = ["tell"];
import { command, on, exec, cmd } from "eds";
command("ping", async (c) => {
await c.reply("pong");
}, "Check the server is listening");
on("player_join", async (e) => {
await exec(cmd`tell ${e.player.ref} welcome, ${e.player.name}`);
});command(name, handler, help)adds!nameto chat. The line is not shown to other players. The handler getslobby,player,name,args,rawandreply(text), which sends the player a private line and needstellin the list. One script owns each name.on(event, handler)calls the handler for every event of that kind, and returns a function that stops it.exec(line)runs a console line and resolves to{ ok, lines }. It rejects when the line is not in the list.cmd`...`builds a line and quotes every value put into it, so a player's name can never turn into a second command.quote(value)does the same for one value.log,warnandconsole.logwrite to the server log.sleep(ms)waits.every(ms, handler)repeats until the function it returns is called.
A script is a single file with no file system, network or other modules.
Every event has the lobby's invite code in lobby, empty for the hub:
| Event | Fields |
|---|---|
player_join | player, watching |
player_leave | player, reason: left, kicked, timeout or closed |
chat | player, text; ! commands are not included |
kill | killer (null for a fall or the world), victim, weapon |
match_start | map, mode |
match_end | map, mode, result |
round_won | winner, tally |
map_changed | map |
lobby_created | |
lobby_closed | reason |
A player is { ref, id, name, slot, admin }. Use ref to name them in commands like tell and kick.
tell <player> <text>, announce <text> and lobbysay <code> <text> send a system line. It shows in the chat box marked as coming from the server, or from the script that sent it. start, end, map and nextmap act on the rotation arena.
TypeScript and examples
sdk/script/eds.d.ts types the whole API. sdk/script/examples has two scripts:
skipsong.jslets anyone skip the radio song with!skipsong, with a cooldown for each player.skipvote.jsends the match when three players type!skip, which opens the map vote on a server withsv.mapvote true.
The server runs JavaScript only, so compile TypeScript first. tsc keeps the commands list at the top of the file. A bundler may move exports to the end, so with esbuild put the list in --banner:js= instead.
Map editor
Opening
- Maps > New map creates a starter map with a floor and a player start.
- Maps > select a custom map > Edit opens it.
Only maps made in the editor can be edited. Other maps open read-only in the map debugger. Leave any lobby before editing.
Camera
- Hold right mouse and move to look.
WASDfly.EorSpacemoves up,Qmoves down.- Hold
Shiftto fly fast. - Mouse wheel changes fly speed.
Ffocuses the selection.
Selecting and editing
- Left click selects.
Shiftadds,Ctrltoggles. Drag on empty space to box select. Gmoves,Tscales,Rrotates by 90 degrees.Tabswitches between move and scale.Hhides the selection,Shift+Hshows everything.Ctrl+C,Ctrl+VandCtrl+Dcopy, paste and duplicate.DeleteorBackspaceremoves the selection.[and]change the grid size. Snap in the top bar turns grid snapping on and off.Ctrl+Zundoes.Ctrl+YorCtrl+Shift+Zredoes.
The inspector edits the selection: position, size, rotation, name, shape, colour, and whether a block is a ladder, water or glass. Glass has a pane preset, break speed, opacity, and whether it holds or breaks underfoot. The outliner lists every block and marker.
Placing
The left panel has blocks, markers and colours. Click an entry, then click in the world to place it. Shift click keeps placing. Esc or right click puts the tool down. 1 to 9 pick the first nine blocks.
- Blocks: box, floor, wall, platform, pillar, wedge, ramps at 15, 30 and 45 degrees, a 60 degree surf ramp, stairs, ladder, water, and four glass panes.
- Markers: player start, deathmatch spawn, dummy, and dummy rail.
- A dummy is a target. Killable dummies take damage. A dummy rail moves a dummy along a path.
Movement helpers
The top bar has tools for checking jumps:
- Arc draws the jump arc from the cursor along the camera direction.
- Reach shows how far a jump from the cursor lands in every direction.
- Gap: click two points to see if the gap can be jumped.
- The gait button switches the helpers between walk, sprint and strafe.
O toggles the run overlay.
Saving and testing
Ctrl+S or Save writes the map to the custom maps folder as <name>.blvl. See Installing a map. Map names use lowercase letters, digits, _ and -.
Test run plays the map right away without saving. Esc returns to the editor. Leaving with unsaved changes asks to save, discard or keep editing.
Edit tracks opens the track editor on the same map.
Map debugger
The map debugger inspects any map read-only. Open it with Debug in the editor, Inspect on a map that is not editable, or the mapdebug console command in game. It can show colliders, triggers, teleports, spawns, doors and lights, colour colliders by flags or source, list map problems, and copy or save a text dump of a selection.
Track editor
A track is a race course on a map: a start, checkpoints in order, and a finish.
Opening
- Maps > select a map > Tracks.
- Maps > Tracks tab > Edit on a track.
- Edit tracks in the map editor.
The track editor uses the same camera, selection and grid keys as the map editor. The map's blocks are read-only here.
Placing
Pick a tool from the Track menu or press its key, then click in the world.
| Key | Tool |
|---|---|
1 | Start |
2 | Checkpoint |
3 | Finish zone |
4 | Reset zone |
5 | NPC |
- Start sets where runs begin and which way the runner faces.
- Checkpoints must be touched in order.
PgUpandPgDnmove the selected checkpoint earlier or later. - A finish zone ends the run.
- A reset zone counts as a fall. In a race the run restarts. In practice the runner goes back to the last checkpoint.
- NPCs are dummies placed on the track.
Zones are boxes. Set their center and half size in the inspector.
Track settings
Track > Settings sets the name, id, author and loadout. The loadout is either the runner's own preset, or guns chosen by the track with spare magazines per slot. -1 magazines means unlimited reloads.
Runs
View > Runs opens saved runs, leaderboard runs and test runs, and draws them in the world. Toggle marks, jumps, second ticks and X-ray drawing from the View menu or the runs window. O toggles the run overlay.
Checks
A track cannot be run until it has a start and at least one checkpoint or finish zone, every zone has a size, and a track loadout names at least one gun. Save still works on an unfinished track and lists what is missing. Test run refuses until it is fixed.
Saving and publishing
Ctrl+S saves the track as <tracks folder>/<map>/<id>.btrk. See Files and folders. File > Test run plays it.
To share a track, open Play > Race, select the track and press Publish.
Custom maps and blvl
blvl
.blvl is an open level format for first person shooters. The blvl tool bakes maps from other games into .blvl files the game can load. See https://blvl.lol for how to get blvl, its documentation and the format spec.
blvl reads maps from:
- Quake 3 and Urban Terror (
--pk3) - Source: Counter-Strike: Source, Half-Life 2, Team Fortress 2, older CS:GO (
--source) - Source 2: Counter-Strike 2, Deadlock (
--source2) - Valorant (
--valorant) - Overwatch 2 (
--ow2) - Call of Duty 4, Modern Warfare 2, Black Ops (
--cod4,--mw2,--bo1) - Halo 2 from the Master Chief Collection (
--halo2) - Reflex Arena (
--reflex)
No game content ships with blvl. You bake from games you own.
Baking a map
blvl bake --pk3 ut4_uptown.pk3 --map ut4_uptown --out ut4_uptown.blvl
blvl bake --source2 --steam --map de_mirage --out de_mirage.blvl
blvl bake --reflex steam --map Aerowalk --out rfx_aerowalk.blvl--mapnames the map inside the game files.--outis the file to write.steamin place of a path finds the game in your Steam library, where supported.--fastdoes a quick bake in seconds to check that a map loads.blvl listwith a frontend flag lists the maps it can find.blvl info <file.blvl>andblvl probe <file.blvl> --problemscheck a baked map.blvl helpprints every option.
A bake also writes a .bsym file next to the map. Keep it with the .blvl for better debugging in the map debugger.
Installing a map
Put the .blvl file in the custom maps folder:
- Linux:
~/.local/share/eds/maps - Windows:
%APPDATA%\eds\maps
Then press Rescan on the Maps screen. Open folder on the same screen opens this folder. The EDS_CUSTOM_MAPS_DIR environment variable moves it. Maps made in the map editor are saved here too.
Maps that ship with the game are in assets/maps in the game folder. A shipped map hides a custom map with the same name.
Maps on servers
A custom map is only on your machine. To play it with others, host a lobby on it, or put it in a dedicated server's map folder. Players download it when they join. See Maps on a server.
Files and folders
On Linux, data goes under ~/.local/share/eds and settings under ~/.config/eds. On Windows both go under %APPDATA%\eds.
| What | Default location | Override |
|---|---|---|
| Settings | ~/.config/eds/config.cfg | EDS_SETTINGS |
| Startup script | autoexec.cfg next to config.cfg | |
| HUD profiles | hud_profiles.json next to config.cfg | |
| Console history | console_history next to config.cfg | |
| Log | latest.log in the game folder, or eds.log next to config.cfg | EDS_LOG |
| Custom maps | ~/.local/share/eds/maps | EDS_CUSTOM_MAPS_DIR |
| Downloaded maps | ~/.local/share/eds/servermaps | EDS_SERVER_MAPS_DIR |
| Tracks | ~/.local/share/eds/tracks | EDS_TRACKS_DIR |
| Runs | ~/.local/share/eds/runs | EDS_RUNS_DIR |
| Replays | ~/.local/share/eds/replays | EDS_REPLAY_DIR |
| Screenshots | ~/.local/share/eds/screenshots | EDS_SCREENSHOT_DIR |
| Shipped maps | assets/maps in the game folder | EDS_MAPS_DIR |
EDS_SERVER_MAPS_CACHE_MB caps the downloaded map cache, 4096 MB by default.
Command line
eds
| Option | Does |
|---|---|
--maps-dir <dir> | Adds a map folder. Repeat for more. |
--create | Hosts a lobby on start. |
--join <code> | Joins a lobby by invite code on start. |
--spectate <code> | Watches a lobby by invite code on start. |
--server <host:port> | Connects to a server on start. |
--replay <file.brep> | Opens a replay file. |
--display <name> | Opens the window on this monitor. |
-v, -vv | More logging. |
In Steam, set these under the game's Properties > Launch options.
eds-server
See Command line flags under Hosting a server.
Console variables
Every variable, its default, its allowed values and what it does. Set them with set <name> <value> or in config.cfg.
game.*variables are lobby rules. Only the lobby owner can set them.sv.*variables belong to dedicated servers. Set them inserver.cfg, or over rcon as an admin.
input
Mouse and keys.
| Variable | Default | Values | Description |
|---|---|---|---|
input.sensitivity | 0.04 | 0.005 to 0.3 | Degrees of view rotation per mouse count |
input.ads_toggle | false | The aim key toggles the sights instead of being held | |
input.zoom_sens | 1 | 0.2 to 2 | Multiplier on the focal-length sensitivity scale through a magnified scope |
video
Display and renderer.
| Variable | Default | Values | Description |
|---|---|---|---|
video.mode | Borderless | Windowed, Borderless, Fullscreen | Window mode |
video.display_server | Auto | Auto, X11, Wayland | Linux only: which display server to open the window on; the Steam overlay needs X11, auto follows the session |
video.monitor | empty | Display to use; empty means the primary | |
video.width | 1600 | 640 to 16384 px | Window width in windowed mode |
video.height | 900 | 480 to 16384 px | Window height in windowed mode |
video.vsync | Off | Off, On, Mailbox | Off presents as soon as a frame is done, On waits for the display, Fast keeps only the newest frame |
video.fps_cap | 0 | 0 to 1000 Hz | Frame cap; 0 follows the monitor |
video.low_latency | On | Off, On, Boost | NVIDIA Reflex or AMD Anti-Lag when the driver offers it |
video.render_scale | 100 | 50 to 200% | Scene resolution as a share of the window; above 100 supersamples |
video.fov | 105 | 70 to 130 deg | Horizontal field of view |
video.viewmodel_fov | 65 | 50 to 90 deg | Field of view the held weapon is drawn with |
video.brightness | 1 | 0.5 to 2 | Exposure multiplier |
video.reticle_brightness | 1 | 0.2 to 2.5 | How bright a red dot or holo reticle is drawn |
video.gamma | 2.2 | 1.8 to 2.6 | Output gamma |
video.quality | Medium | Competitive, Low, Medium, High, Ultra, Custom | Render preset; changing a detail below makes it Custom |
video.shading | Quality | Competitive, Quality | Competitive is the flat, high contrast look; Quality is the full lighting model |
video.surface_detail | High | Low, High | Normal, roughness, emissive and directional lightmap detail on surfaces |
video.shadows | Medium | Off, Low, Medium, High, Ultra | Sun shadow resolution, reach and softness |
video.dynamic_shadows | true | Shadows cast by players and props | |
video.ambient_occlusion | Low | Off, Low, Medium, High | Screen space contact shading |
video.reflections | Low | Off, Low, High | Reflection detail |
video.water | Medium | Low, Medium, High | Water surface detail; Medium refracts and reflects the scene, High adds screen space reflections and caustics |
video.bloom | false | Glow around bright light, where the map style uses it | |
video.dynamic_lights | true | Muzzle flashes and explosions light the world | |
video.physics_props | true | Bottles, crates and barrels react to the player, shots and blasts | |
video.card_trails | true | Ribbons, glyph walls, smoke, stars and wires trailing behind players holding a foil card | |
video.anisotropy | X8 | Off, X2, X4, X8, X16 | Texture sharpness at grazing angles |
video.texture_detail | High | Low, Medium, High | Lower levels skip the sharpest mip levels |
video.antialiasing | Off | Off, Fxaa | Edge smoothing; render scale above 100 supersamples as well |
video.sharpen | 0 | 0 to 1 | Contrast adaptive sharpening after anti-aliasing |
audio
Sound.
| Variable | Default | Values | Description |
|---|---|---|---|
audio.master | 0.75 | 0 to 1 | Master volume |
audio.sfx | 1 | 0 to 1 | Sound effects |
audio.spatializer | Hrtf | Hrtf, Pan | Spatial audio |
audio.reverb | true | Reverb | |
audio.radio | true | Play the music a server is streaming; off tells the server to send none of it | |
audio.radio_volume | 0.5 | 0 to 1 | How loud the server's station is |
audio.radio_duck | 0 | 0 to 1 | How far the station drops while a round is live; 0 leaves it alone |
profile
Player.
| Variable | Default | Values | Description |
|---|---|---|---|
profile.model | male | Character model: male or female | |
profile.hand | Right | Right, Left | Gun hand |
profile.emotes | [0, 1, 2, 3, 4] | list, 0 to 15 | Emote wheel slots |
profile.dances | [0, 1, 2, 3, 4] | list | Dance wheel slots |
profile.loadout | 12 entries | list | Weapon slots, three per preset |
profile.loadout_names | [Assault, Close, Long, Utility] | list | Preset names |
profile.loadout_pick | 0 | 0 to 3 | The preset in hand |
hud
Overlay.
| Variable | Default | Values | Description |
|---|---|---|---|
hud.show | true | Draw the HUD | |
hud.scale | 1 | 0.5 to 2 | Size of the overlay |
hud.max_hz | 0 | 0 to 1000 Hz | HUD updates per second; 0 sends one every frame |
hud.profile | default | HUD profile used where the game mode has none of its own |
crosshair
Crosshair.
| Variable | Default | Values | Description |
|---|---|---|---|
crosshair.style | Dot | Dot, Cross, CrossDot, Circle | Shape |
crosshair.size | 6 | 0 to 40 px | Arm length |
crosshair.gap | 4 | 0 to 40 px | Gap from the centre |
crosshair.thickness | 2 | 1 to 8 px | Line thickness |
crosshair.color | #e8f7ff | Colour as #rrggbb | |
crosshair.outline | true | Dark outline |
cosmetics
Cosmetics.
| Variable | Default | Values | Description |
|---|---|---|---|
cosmetics.preset | empty | Outfit preset | |
cosmetics.palette | empty | Outfit palette | |
cosmetics.parts | empty | list | Part overrides on top of the preset, one slot=id per entry; none empties an optional slot |
card
Playing card.
| Variable | Default | Values | Description |
|---|---|---|---|
card.slots | 4 entries | list | Card wheel slots, one id or id:foil per entry |
card.pick | 0 | 0 to 3 | The slot the card comes out of |
maps
Maps.
| Variable | Default | Values | Description |
|---|---|---|---|
maps.recent | empty | list | Maps a match was played on lately, newest first |
oiko
Crash reports.
| Variable | Default | Values | Description |
|---|---|---|---|
oiko.upload_crash_dumps | false | After a crash, send the minidump, the log and the build to the developers on the next launch |
net
Servers.
| Variable | Default | Values | Description |
|---|---|---|---|
net.favorites | empty | list | Servers starred in the browser; an entry is [label=]host:port |
net.history | empty | list | Servers connected to lately, newest first |
net.auto_replays | true | Save a replay of every match | |
net.auto_maps | true | Download a lobby's map when this client lacks it | |
net.upload_replays | true | Send a replay of every match you host to the backend |
discord
Discord.
| Variable | Default | Values | Description |
|---|---|---|---|
discord.presence | true | Rich presence | |
discord.lobby_invites | true | Lobby invites in presence |
watch
Spectator HUD layers.
| Variable | Default | Values | Description |
|---|---|---|---|
watch.hud | true | Game HUD while the replay controls are hidden | |
watch.team | false | Team panel | |
watch.player | false | Player panel | |
watch.feed | false | Kill feed | |
watch.scoreboard | false | Scoreboard | |
watch.minimap | false | Minimap | |
watch.stats | false | Stats block | |
watch.phase | true | Match phase |
console
Console.
| Variable | Default | Values | Description |
|---|---|---|---|
console.height | 0.45 | 0.2 to 1 | Fraction of the window the console covers |
console.vi | false | Vi editing on the prompt | |
console.font_size | 14 | 9 to 32 px | Font size |
console.opacity | 0.92 | 0.3 to 1 | Background opacity |
app
Application.
| Variable | Default | Values | Description |
|---|---|---|---|
app.version | Build version (read only) | ||
app.cloud_sync | false | Push config.cfg and hud_profiles.json to Steam Cloud on every save |
game
Lobby rules.
| Variable | Default | Values | Description |
|---|---|---|---|
game.map | The map the lobby is on (read only) | ||
game.mode | duel | duel, ffa, tag, race, gungame, horse, bomb, ctf | Game mode |
game.weapons | 15 entries | list | Guns the per-fight draw may hand out |
game.rounds | 0 | 0 to 30 | Round wins that take the match; 0 plays without a limit |
game.tag_time | 300 | 120 to 1200 s | How long a tag match runs |
game.tag_headshot | true | Only a headshot tags | |
game.bomb_plant | 3 | 1 to 600 s | How long planting the bomb takes |
game.bomb_defuse | 10 | 1 to 600 s | How long defusing it takes |
game.bomb_fuse | 40 | 1 to 600 s | How long a planted bomb burns for |
game.bomb_round | 180 | 1 to 600 s | How long a bomb round runs before the defenders take it |
game.ctf_time | 1200 | 60 to 3600 s | How long a capture the flag match runs |
game.ctf_respawn | 5 | 0 to 3600 s | How long a death costs in capture the flag |
game.ctf_return | 30 | 1 to 3600 s | How long a dropped flag lies before it goes home |
game.loadout_1 | [rifles, smgs, shotguns, snipers] | list | What the first loadout slot may hold: class plurals or weapon tags |
game.loadout_2 | [sidearms] | list | What the second loadout slot may hold |
game.loadout_3 | [grenade, shotgun_short] | list | What the third loadout slot may hold |
game.spares_1 | 2 | -1 to 99 | Spare magazines for the first slot; -1 leaves reloads unlimited |
game.spares_2 | 3 | -1 to 99 | Spare magazines for the second slot; -1 leaves reloads unlimited |
game.spares_3 | 1 | -1 to 99 | Spare magazines for the third slot; -1 leaves reloads unlimited |
game.visibility | private | private, friends, public | Who can find the lobby |
game.cheats | false | Noclip is allowed here (read only) | |
game.warmup_wait | 0 | 0 to 3600 s | Seconds a match waits in warmup before it may start; 0 means none |
game.max_players | 0 | 0 to 16 | Player cap; 0 means the mode's own |
sv
Server.
| Variable | Default | Values | Description |
|---|---|---|---|
sv.bind | 0.0.0.0:27960 | UDP address to listen on (restart) | |
sv.mode | game | What this server runs: ranked, race or game (restart) | |
sv.hostname | empty | The name the browser shows | |
sv.public | true | List this server on the backend directory | |
sv.backend | https://eds-backend.plus3.dev | Backend URL: the directory and the track registry (restart) | |
sv.public_addr | empty | The host:port players reach this server on, when the backend cannot tell | |
sv.password | empty | Players must give this to connect; empty means anyone | |
sv.admins | empty | list | Player ids that may use rcon; empty means only the local console and the host's own client |
sv.auth | required | Whether a UDP client must prove who it is: required, optional or off | |
sv.auth_keys | empty | list | kid:hex signing keys to trust; empty fetches them from the backend |
sv.cards | verified | Whether a card a player shows must be backed by a backend-signed entitlement: verified or trusted | |
sv.db | empty | The SQLite file for stats, ratings, bans and records; empty means eds-server.db (restart) | |
sv.snapshot_div | 1 | 1 to 16 | Ticks between snapshots to a player |
sv.spectator_snapshot_div | 4 | 1 to 64 | Ticks between snapshots to a viewer |
sv.spectator_delay_secs | 0 | 0 to 120 s | How far behind the match viewers see it; 0 is live |
sv.max_players | 16 | 1 to 16 | Seats in the rotation arena |
sv.max_viewers | 300 | 0 to 10000 | Viewers this server takes |
sv.default_map | empty | Map arenas start on; empty means the training range (restart) | |
sv.rotation | empty | list | Rotation entries: map or map:mode for a game server, track ids for a race server |
sv.tracks_dir | empty | Where a race server looks for .btrk files named by the rotation (restart) | |
sv.autostart_players | 2 | 2 to 16 | Seated players before a rotation match starts itself |
sv.warmup_secs | 20 | 0 to 600 s | Warmup before a rotation match starts |
sv.results_secs | 10 | 1 to 120 s | How long results stay up before the rotation moves on |
sv.mapvote | false | Players vote on the next rotation entry instead of it simply moving on | |
sv.mapvote_choices | 4 | 2 to 8 | Entries on the ballot, drawn from the rotation |
sv.mapvote_secs | 30 | 5 to 120 s | How long a vote runs after a match; it holds the results up for at least this long |
sv.mapvote_recency | 1 | 0 to 4 | How hard the ballot keeps off what was played recently; 0 ignores it |
sv.mapvote_popularity | 0 | -2 to 2 | How much winning votes change an entry's odds of being offered: above 0 favours the crowd-pleasers, below 0 spreads the load |
sv.rounds_to_win | 0 | 0 to 30 | Round wins that take a rotation match; 0 plays without a limit |
sv.weapons | empty | list | Guns the fights may draw from, by tag; empty means all of them |
sv.loadout_1 | empty | list | What the first loadout slot may hold: class plurals or weapon tags; empty means the shipped rule |
sv.loadout_2 | empty | list | What the second loadout slot may hold; empty means the shipped rule |
sv.loadout_3 | empty | list | What the third loadout slot may hold; empty means the shipped rule |
sv.spares_1 | -2 | -2 to 99 | Spare magazines for the first slot; -1 is unlimited and -2 means the shipped rule |
sv.spares_2 | -2 | -2 to 99 | Spare magazines for the second slot; -1 is unlimited and -2 means the shipped rule |
sv.spares_3 | -2 | -2 to 99 | Spare magazines for the third slot; -1 is unlimited and -2 means the shipped rule |
sv.tag_time_secs | 300 | 30 to 1800 s | Tag time limit |
sv.tag_headshot | true | Tag passes on headshots only | |
sv.late_join | false | Seat a player who joins during a match to sit out until the next fight; off has them watch until it ends | |
sv.bomb_plant_secs | 3 | 1 to 600 s | How long planting the bomb takes |
sv.bomb_defuse_secs | 10 | 1 to 600 s | How long defusing it takes |
sv.bomb_fuse_secs | 40 | 1 to 600 s | How long a planted bomb burns for |
sv.bomb_round_secs | 180 | 1 to 600 s | How long a bomb round runs before the defenders take it |
sv.ctf_time_secs | 1200 | 60 to 3600 s | Capture the flag time limit |
sv.ctf_respawn_secs | 5 | 0 to 3600 s | How long a capture the flag death costs |
sv.ctf_return_secs | 30 | 1 to 3600 s | How long a dropped flag lies before it goes home |
sv.ranked_max_matches | 4 | 1 to 64 | Ranked matches at once; queues wait when every arena is busy |
sv.ranked_rounds | 6 | 1 to 30 | Round wins that take a ranked match |
sv.ranked_window | 150 | 10 to 2000 | Rating gap the queue pairs across, widening with wait |
sv.ranked_widen_secs | [15, 45, 90] | list | Seconds queued before the window widens, one per stage |
sv.ranked_pause_secs | 30 | 0 to 300 s | How long a ranked match waits for a dropped player |
sv.ranked_warmup_wait_secs | 60 | 5 to 600 s | How long a ranked arena waits for everyone to arrive |
sv.ranked_warmup_players | 16 | 0 to 16 | Seats in the ranked warmup room players wait in; 0 opens none |
sv.ranked_tau | 0.5 | 0.1 to 1.2 | Glicko-2 volatility constraint |
sv.ranked_margin | true | Scale rating moves by the round margin | |
sv.race_track_secs | 900 | 0 to 86400 s | How long a race server stays on one track; 0 rotates by hand |
sv.race_rules | race | Run rules on a race server: race or practice | |
sv.heartbeat_secs | 30 | 5 to 600 s | How often the directory hears from this server |
sv.region | empty | Where this server is, for the browser | |
sv.tags | empty | list | Words the browser can filter on |
sv.official_bans | true | Refuse players on the official backend banlist | |
sv.banlist_sync_secs | 30 | 10 to 600 s | How often this server pulls banlist changes from the backend |
sv.upload_replays | true | Ship finished recordings to the backend | |
sv.record | true | Record every match (restart) | |
sv.record_dir | empty | Where recordings go; empty means the default replay directory (restart) | |
sv.download_mbits | 800 | 0 to 10000 Mbit/s | Upload the server will spend on map and replay downloads, shared between them; 0 turns downloads off |
sv.max_downloads | 32 | 1 to 1024 | Downloads at once |
sv.map_url | empty | Base URL clients try first for a map, as <url>/<name>.blvl; empty sends every map in-game | |
sv.map_url_only | false | Never send maps in-game; clients get them only from sv.map_url | |
sv.max_replays | 64 | 1 to 100000 | Recordings kept on disk |
sv.replay_keep_secs | 0 | s | Recordings older than this are dropped; 0 keeps them |
sv.cheats | false | Allow noclip in every arena | |
sv.radio | false | Run a station: stream the radio directory to everyone who asks for it (restart) | |
sv.radio_dir | empty | Where the songs and the .txt playlists live; empty means the radio directory beside the server (restart) | |
sv.radio_playlist | empty | The playlist to play, by file name without .txt; empty plays the whole library | |
sv.radio_shuffle | false | Play in a random order | |
sv.radio_mbits | 100 | 0 to 10000 Mbit/s | Upload the station may spend across all its listeners; 0 stops the audio but keeps the track information |
sv.radio_max_listeners | 64 | 0 to 1024 | Listeners the station takes at once |
sv.radio_buffer_secs | 5 | 2 to 30 s | How much audio a listener is sent ahead of the playhead; also how far behind the server they hear it |
sv.radio_gain_db | 0 | -24 to 6 dB | Level trim applied to every song |
sv.radio_art_px | 256 | 0 to 512 px | Longest side of the album art listeners are sent; 0 sends none |
sv.radio_scan_secs | 0 | 0 to 86400 s | Re-read the radio directory this often; 0 reads it on start and on radio rescan |
sv.scripts | empty | list | Scripts to run from sv.scripts_dir, by file name without .mjs or .js; take one out to stop it |
sv.scripts_dir | scripts | Where scripts live (restart) | |
sv.script_mem_mb | 16 | 1 to 256 MB | Memory each script may use; applies the next time it loads |
sv.script_budget_ms | 20 | 1 to 1000 ms | How long a script may run for one event, command or timer before it is stopped |
Console commands
Client
Commands that start with + are held actions for binds, listed under Default binds.
| Command | Arguments | Description |
|---|---|---|
admin | Open the admin panel | |
alias | [name] [command...] | Name a command line; alone, list aliases |
bind | [key] [command...] | Run a command when a key is pressed; alone, list binds |
binds | List every bound key | |
card | [id|next|prev [foil]|slot <1-4> [id] [foil]|pick <1-4>|give <id|all> [foil]|revoke all] | Fill a slot on the card wheel, or give and revoke cards in dev builds; alone, list the cards |
clear | Clear the console | |
connect | <host:port> | Create a lobby on a server |
create | Create a lobby | |
cycle | <var> | Move an enum variable to its next value |
dec | <var> [step] | Subtract from a number variable |
disconnect | Leave the lobby | |
echo | <text...> | Print text |
exec | <file> | Run every line of a config file |
get | <var> | Show a variable's value |
help | [name] | What a command or variable does; alone, list everything |
history | [count] | Show recent commands |
hud_edit | Move and resize the HUD, or leave the editor | |
hud_profile | [name|next|prev] | Show the HUD profiles or switch to one |
hud_profiles | [list|new <name>|duplicate <from> <to>|rename <from> <to>|reset <name>|delete <name>|mode <slot> [name]] | Create, copy, rename, reset, delete or assign HUD profiles |
inc | <var> [step] | Add to a number variable |
inventory_refresh | Fetch cards and entitlements from the backend again | |
join | <code> | Join a lobby by invite code |
log_level | [level|spec] | Show or set the log filter: error, warn, info, debug, trace, or an env_logger spec |
map | [name] | Change map; alone, list the maps |
mapdebug | Open the map debugger here, on this map, at this camera | |
quit | Leave the game | |
rcon | <line...> | Run a console line on the dedicated server |
record | Start recording the lobby on the server, warmup and all; owner or admin | |
reset | <var> | --all | Put a variable back to its default; --all resets everything including binds |
savereplay | Save the match so far to this machine | |
say | <text...> | Say something to the lobby |
screenshot | [clean] | Save a screenshot; clean drops the UI and the view model |
set | <var> <value...> | Set a variable |
status | What the game is doing: screen, connection and server | |
stop | Stop the recording record started and save it to this machine | |
thumbcam | Print this camera as a cameras/<map>.toml entry for the map's thumbnail | |
toggle | <var> | Flip a bool variable |
toggleconsole | Open or close the console | |
unalias | <name> | Remove an alias |
unbind | <key> | Free a key |
vars | [prefix] [--all] [--changed] [--table] | List variables and their values |
version | Show the game, gewy and protocol versions | |
vote | <n> | Pick an entry on the open map vote |
watch | <code> | Watch a lobby by invite code |
writeconfig | [file] [--changed] | Write the config file; --changed writes only what differs from the defaults |
Server
These run in a dedicated server's console: through rcon, the server panel, or the control API. set, get, vars, help and exec work there too.
| Command | Arguments | Description |
|---|---|---|
status | What this server is doing | |
players | Who is seated where | |
viewers | Who is watching | |
kick | <name|#id|playerid> | Drop a player or viewer |
ban | <name|#id|playerid> [secs] [reason] | Drop somebody and keep them out; no seconds means forever |
unban | <playerid> | Lift a ban |
bans | List the bans | |
banlists | The banlists this server keeps and follows | |
banlist | [list|new <name> [public]|rm <id>|add <id> <who> [secs] [reason]|del <id> <who>|find <id> <who>|sub <id>|unsub <id>|sync] | Manage the banlists on this server's backend key |
map | <map> | Put the rotation arena on a map now |
nextmap | Move the rotation on | |
rotation | [list|add <entry>|remove <n>|clear|shuffle] | Show or edit the rotation |
mapvote | [status|open|close|cancel|reset] | Show, run or drop the vote on the next rotation entry |
radio | [status|play|pause|skip|restart|playlist [name|none]|shuffle [on|off]|rescan|jump <n|text>|list [text]|playlists] | Show or drive the station |
start | Start the rotation arena's match | |
end | End the rotation arena's match | |
say | <text> | Say something to everyone |
tell | <name|#id|playerid> <text> | Send one player a private system line |
announce | <text> | Send everyone a system line |
lobbysay | <code> <text> | Send one lobby a system line |
script | [list|reload <name>|info <name>] | List, reload or inspect the scripts in sv.scripts |
ratings | [solo|duo] [page] | The ranked ladder |
records | [page] | The records on the current track |
log_level | [level|spec] | Show or set the log filter: error, warn, info, debug, trace, or an env_logger spec |
Developer
Everything on this page exists only in development builds. Release builds do not have these binds, variables or commands.
Binds
| Key | Name | Command | Action |
|---|---|---|---|
| F3 | F3 | noclip | Noclip |
| F2 | F2 | mapdebug | Map debugger |
| F4 | F4 | dump | Dump state |
| F5 | F5 | screenshot | Screenshot |
| F6 | F6 | toggle dev.third_person | |
| F8 | F8 | cycle dev.hitboxes | |
| F9 | F9 | dev | |
| F10 | F10 | dev camera |
Variables
profile
Player.
| Variable | Default | Values | Description |
|---|---|---|---|
profile.name | player | Display name |
net
Servers.
| Variable | Default | Values | Description |
|---|---|---|---|
net.backend | https://eds-backend.plus3.dev | Backend URL: the server list, invite codes and the race registry |
dev
Developer.
| Variable | Default | Values | Description |
|---|---|---|---|
dev.third_person | false | Chase camera | |
dev.cam_dist | 110 | 0 to 600 qu | Chase camera arm length |
dev.cam_shoulder | 18 | -200 to 200 qu | Chase camera shoulder offset, right is positive |
dev.cam_height | 0 | -100 to 200 qu | Chase camera focus height above the eye |
dev.cam_yaw | 0 | -180 to 180 deg | Chase camera orbit yaw; 180 puts it in front looking back |
dev.cam_pitch | 0 | -89 to 89 deg | Chase camera orbit pitch |
dev.cam_min | 24 | 0 to 600 qu | Closest the wall pull-in may bring the chase camera |
dev.cam_clearance | 16 | 0 to 200 qu | Gap the chase camera keeps off whatever it hits |
dev.cam_in_rate | 30 | 0 to 120 | How fast the chase camera pulls in |
dev.cam_out_rate | 6 | 0 to 120 | How fast the chase camera eases back out |
dev.cam_fov | 0 | 0 to 170 deg | Chase camera field of view; 0 keeps video.fov |
dev.cam_roll | 0 | -180 to 180 deg | Chase camera roll |
dev.cam_collide | true | Pull the chase camera in at walls | |
dev.hitboxes | Off | Off, Xray, Depth | Hit capsule overlay |
dev.reticle_ruler | false | Draw MOA circles about the crosshair | |
dev.shot_viewmodel | false | Keep the view model in clean screenshots | |
dev.hide_viewmodel | false | Hide the first-person view model | |
dev.style | Auto | Auto, Eds, Urt, Q3, Cs2, Val, Css, Csgo, Tf2, Ow2, Cod4, Halo2, Reflex | Renderer style |
dev.exposure_lock | false | Pin auto-exposure to the map's authored midpoint | |
dev.q3_overbright | -1 | idTech3 r_overBrightBits override; -1 keeps the map's | |
dev.q3_map_overbright | -1 | idTech3 r_mapOverBrightBits override; -1 keeps the map's | |
dev.q3_gamma | 0 | idTech3 r_gamma override; 0 keeps the map's | |
dev.src_hdr | true | Source 1 HDR path; off forces the LDR chain | |
dev.cod4_film | true | CoD4 film tweak | |
dev.cod4_glow | true | CoD4 glow | |
dev.light_styles | true | Animate the light style table | |
dev.halo2_lightmap_gain | 2 | 0 to 4 | Halo 2 lightmap modulate; 0 keeps the map's gain |
dev.halo2_detail | true | Halo 2 detail maps | |
dev.halo2_env | 1 | 0 to 4 | Halo 2 environment map scale |
dev.halo2_fog | true | Halo 2 atmospheric fog | |
dev.depth_prepass | true | Fill depth before shading the opaque world, so an overdrawn pixel is only shaded once | |
dev.gpu_timing | false | Timestamp every render pass so the HUD and timing can report per-zone GPU cost |
Commands
| Command | Arguments | Description |
|---|---|---|
achievement | [list|unlock <api>|reset] | List the Steam achievements, unlock one or reset them all |
cloud | [list|delete <file>] | List the files in Steam Cloud for this app, or delete one |
crash | [segv|abort] | Crash the client on purpose to test the minidump and the oiko upload |
dump | [player|probe|collision|pose] | Print the player, what the crosshair is on, the nearby collision and the pose |
noclip | Fly through walls | |
rig | [anim|pose|tp|cards] | Open the rig tool here, on this map; again to close and go back |
timing | [on|off] | Turn per-pass GPU timing on or off; alone, print the last frame's zones |