Contents

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

  • Play: servers, your own session, 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, the map and where you were standing, 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.

Your profile

Customize > Profile is your plate: a country flag, the modes you prefer, up to three playstyle tags, the times you are usually around, a short bio and up to three cards on show, over a plate style of your choosing. Edit profile leaves the plate where it is and makes it clickable: the flag, each card, the modes and the playstyle tags each open a picker, the style is a dropdown in the header, and an empty card slot shows a placeholder. Save writes it to your account, so it follows you to any machine you sign in on. Signed out, the plate is kept on this computer only and nobody else can see it.

While your profile is public, your name at the top of the plate opens your web page in a browser.

Right-clicking a player anywhere in the game offers View profile, which shows you theirs.

Crosshairs

The Crosshairs section is optional and off until you turn it on. While editing, it has a Hidden / Shown switch and three slots. Clicking a slot lists your saved crosshair profiles to pick from, with Empty slot to clear it. Each slot shows the crosshair's name and a drawing of it. While the switch is on Hidden the picks are kept but nobody else sees them, and the section does not appear on your plate.

On someone else's profile, Use under a crosshair saves it as a new crosshair profile with its name and switches to it. If you already have it saved, Use just switches to it, and the crosshair you are using shows Equipped instead. The website shows the same section with a copy code button under each, for pasting into Import.

Who can see your profile

The profile header has a Who can see this dropdown while you are editing, with two settings:

SettingWhat it means
PublicAnyone can see your plate, in game and on the web at eds.lol/u/<your steam id>. This is the default.
PrivateNobody else can see your country, preferred modes, playstyle, active times, bio, showcase cards or crosshairs. Other players see your name, and your outfit in matches. The web page shows nothing.

Private is about your plate, not your character. Your outfit is still drawn on you in matches and on the scoreboard either way, because that is what other players are looking at while they play. A private profile can still be reported, and moderators can still read it.

Changing this takes effect at once for anyone opening your profile fresh, though someone already looking at it may see the old version for up to a minute.

Play

  • Browse: dedicated servers run by other people. See Playing online.
  • Custom: host a session on this machine. See Local server.
  • Race: time trials against the clock and other players' ghosts. See Racing.
  • Join with a code, at the top, joins a session on Steam by its five character invite code.

Online play needs Steam running.

Racing

Play > Race has three tabs:

  • Official: the tracks with a leaderboard. Featured tracks come first and tracks made official in the last two weeks are marked new. Race starts a run for the leaderboard and Practice starts one without it. When the map a track is on is not installed, Race subscribes to it on the Workshop and starts once it has downloaded.
  • Records: every track you have a time on, with your leaderboard time and rank, your best local time, and the record. A green submit mark means your local best beats the time you have on the board.
  • My Tracks: your own tracks, tracks from the Workshop, and tracks carried by maps that are not official. Edit, publish to the race registry, publish to the Workshop and delete from here. Deleting a track offers to delete its saved runs and your best time with it.

The Workshop button opens the Workshop filtered to race tracks. A track subscribed there appears in My Tracks once it has downloaded, and the map it needs is subscribed with it.

A track's page and Esc > Race during a run show two lists side by side. You lists your best run and your last 25 finished runs on the track, and imported runs of yours. Leaderboard lists the board a page at a time and the runs of other players you have saved. Every row can be watched, raced against as a ghost during a run, exported to a .brep file, and a run of yours that beats your board time can be submitted. Import adds .brep runs from files; a run of a track you do not have installs its track too.

Finishing an official track with a time the leaderboard would take opens a prompt: Enter submits it, R or Esc races again. Settings > General > Race > Submit prompt turns it off, and the run can still be submitted from Esc > Race.

The track sets the loadout for a race and its checkpoints can change it. Your own loadout is not used while racing.

A run file is a .brep replay whose header names the track id and hash, the map name and hash, the build's sim hash, the player id and name, the finish time in ticks and the checkpoint splits, and carries the track itself. Anyone with the map can re-simulate it to check the time, which is what the official leaderboard does.

Game modes

ModeIdRules
DuelduelTwo teams. Win two fights to take a round. Each fight draws a gun from the session's pool.
Free-for-allffaEveryone for themselves. The last player standing takes the round.
TagtagOne player is it, with a revolver that reloads without limit. Shoot someone to pass it on. The least time spent as it wins. By default only a headshot tags.
RaceraceTime trials on a track.
Gun GamegungameKills move you up a ladder of guns.
HORSEhorseOne player throws a grenade and the mark goes where it explodes. Everyone has to reach it before time runs out: the first to arrive scores 3, the second 2 and everyone else 1, and the thrower loses a point if they miss it. The chase clock is a second shorter each turn, down to 12 seconds.
BombbombTwo 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. A bomb that goes off kills everyone on the map, and the round ends on a slow-motion replay of your death, or of whoever you were watching. With a round limit the sides swap once, at half time. Needs a map with bomb sites.
Capture the FlagctfTwo teams, two flags. Bring the enemy flag home while yours is on its stand. The dead respawn in waves, and each team's wave comes half a wave apart from the other's; the Respawn waves HUD element shows both. Needs a map with flag stands. Maps with two teams of spawns and no flags of their own, such as Counter-Strike maps, get a stand in each team's spawn.
ScriptscriptWhatever a server script is running. Everyone moves and shoots as in a free-for-all; the script keeps the score and says when a round is over. See Scripting.

Warmup and matches

A session starts in warmup. Everyone can move and shoot, and a death only costs a short respawn. In a session you host, start a match from Esc > Manage session > Match, which sets the mode, guns and round limit; the Maps page picks the map. If the owner leaves, the next player becomes owner, or a spectator when nobody is playing. A dedicated server starts matches itself, from its rotation.

Movement

  • Tap jump on the tick you land to bunny hop. Jumping skips ground friction. Nothing is buffered: a press in the air is gone by the time you touch down, so hold nothing and time it.
  • Strafe and turn in the air to gain speed.
  • Crouch above sprint speed to slide. Jump out of a slide to keep the speed. Sliding up a ramp keeps almost all of it.
  • Press jump in the air next to a wall to wall jump. Five in a row, and touching the ground or grabbing a ledge gives them back.
  • Hold forward into a ledge between waist and head height to climb it.
  • Face a ladder and hold forward to climb, and strafe to shuffle along it. Jump to get off.
  • Steps up to 18 units are climbed without jumping. Slopes steeper than 53 degrees are surfable.
  • A ledge only a few units wide will not hold you; you slip off it.

The training range is the default map. It has lanes and props for practicing each of these.

Two more built-in maps teach and test all of this. Tutorial is a course of ten stations, one trick each, with a holographic sign at every gate: gaps, bunny hopping, sliding, air strafing, a wall kick, a wall climb, edge climbs, the air jump, the air jump redirect, and the corner jump, where two wall jumps off the two faces of a corner stack into one big launch. Every station has its own practice track and the whole course is a track too. Gauntlet is a speedrun of three zones, easy, medium and hard, each with every trick at increasing tightness, with a track per zone and one for the full run.

Controls

Default binds

KeyNameCommandAction
WKeyW+forwardMove forward
SKeyS+backMove back
AKeyA+leftStrafe left
DKeyD+rightStrafe right
SpaceSpace+jumpJump
L CtrlControlLeft+crouchCrouch / slide
CapsCapsLock+crouchCrouch / slide
L ShiftShiftLeft+walkWalk
Mouse 1MouseLeft+fireFire
Mouse 2MouseRight+adsAim down sights
RKeyR+reloadReload
EKeyE+useUse / open door
TabTab+scoreboardScoreboard
XKeyX+mapMap
TKeyT+chatChat
GKeyG+emoteEmote wheel
FKeyF+danceDance wheel
EscapeEscape+menuMenu
VKeyV+resetReset / restart run
CKeyC+checkpoint_backBack to last checkpoint
F7F7toggle hud.show
F1F1hud_editEdit HUD
F2F2manage_panelManage panel
1Digit1+weapon_1Weapon slot 1
2Digit2+weapon_2Weapon slot 2
3Digit3+weapon_3Weapon slot 3
4Digit4+cardPlaying card
BKeyB+loadoutLoadout
HKeyHhighlightHighlight moment
BackquoteBackquotetoggleconsoleConsole

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 gun but a grenade, key 2 any pistol, and key 3 the grenade, the smoke or the C4. The C4 is thrown with the trigger, further the longer it is held up to a second, and sticks to walls and players, with at most 6 out per player before the oldest disappears; right-click with the C4 out sets off every one you have thrown, and each also goes off when shot, when caught in another blast or when you die. Carrying the RPG or the grenade launcher on key 1 leaves key 3 empty. Each gun carries its own reserve of rounds, scaled by the server's ammo setting. Servers set their own with sv.loadout_1 to sv.loadout_3, sv.loadout_lock_2, sv.loadout_lock_3 and sv.ammo; whoever manages a session moves the same values with the matching game.* vars. A rule is a list of words, where a plural is a whole class (rifles, smgs, shotguns, snipers, pistols, specials, grenades) and a singular is one gun by tag. A lock rule names the key 1 guns that empty that key, and none locks nothing. The ammo scale multiplies every gun's reserve; 0 leaves reloads unlimited.

The loadout screen shows the rules: each slot says what it takes, a slot emptied by your key 1 gun is greyed out and names that gun, 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 slot holding a gun the server will not take is edged in red and marked with a cross, with the gun you will actually spawn with shown small in its corner; hovering it names that gun. A preset with any such slot is flagged, with one button to move its guns onto keys that will take them. Any slot can be left empty: press X or Delete on a selected slot, or click the cross in its corner. With every slot empty you spawn holding your card.

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.

That table only covers the actions with a name, and only two keys each. For everything else there is the binds window: binds in the console, or the Advanced button beside the Binds title in Settings > Controls, which opens the window over the menu. It lists every key with the command it runs, sorted by whichever column you click, and filtered by the box at the top the same way the vars window is — key:mouse, cmd:weapon, is:changed, is:custom, is:unbound, - to exclude, /regex/. A filter typed after the command starts it narrowed: binds weapon.

Click a key to put the bind on a different one, right click it to free it, or type straight into the command column to change what it runs. Unbound actions sit in their own group at the bottom, and the row under the table adds a bind to a key nothing uses yet. Copy writes every bind out as bind lines; Reset all puts the keys back to their defaults, as does Reset on a single row.

From the console:

bind KeyG +emote
bind MouseMiddle "toggle hud.show"
unbind KeyG
binds

Key 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.

Display and Graphics hold your edits until you press Apply, so a window mode, a resolution or a quality preset never lands mid-drag. Revert puts them back, and leaving the page with edits waiting asks first. Every other page applies as you go.

Reset all, top right of the settings screen, restores every setting and bind to its default.

General

Gameplay

SettingDefaultValuesVariableDescription
Aim down sightsHoldHold, Toggleinput.ads_toggleThe aim key toggles the sights instead of being held
Map keyHoldHold, Toggleinput.map_toggleThe map key toggles the map overlay instead of being held
Gun handRightRight, Leftprofile.handGun hand

Discord

SettingDefaultValuesVariableDescription
PresenceOnOff, Ondiscord.presenceRich presence
Session invitesOnOff, Ondiscord.lobby_invitesShow your session and its invite code in presence so friends can join

Race

SettingDefaultValuesVariableDescription
Submit promptOnOff, Onrace.pb_promptAfter finishing an official track with a time the leaderboard would take, open a prompt to submit it

Privacy

SettingDefaultValuesVariableDescription
Streamer modeOffOff, Onprivacy.streamerMask addresses, Steam ids, invite codes and other identifying details on screen; click a masked value to copy it

Steam

SettingDefaultValuesVariableDescription
Keep settings and HUD layouts in Steam CloudOffOff, Onapp.cloud_syncPush config.cfg and hud_profiles.json to Steam Cloud on every save

Controls

Mouse

SettingDefaultValuesVariableDescription
Mouse sensitivity0.040.005 to 0.3input.sensitivityDegrees of view rotation per mouse count
Zoom sensitivity10.2 to 2input.zoom_sensMultiplier on the focal-length sensitivity scale through a magnified scope

Crosshair

The crosshair is built from three layers you turn on separately: lines, a centre dot and a circle. Lines take a length, an optional separate vertical length, a gap (below zero the arms overlap), thickness, rotation and a T-style that drops the top arm. Colour, opacity, outline width and outline opacity apply to the whole crosshair, and hit flash tints it a second colour when you deal damage. The panel has a live preview.

Crosshairs are kept as profiles, listed beside the settings, and the settings always edit the profile that is highlighted. Click a profile to switch to it. The game starts with Default, Cross, Cross + dot, Tight plus, T, Circle dot and X. New copies the profile you are editing, and each profile can be renamed, copied as a code or deleted; the last one cannot be deleted.

A crosshair code such as XH-12PZ1nZN8nC8H3kpWfjkXMam39GB holds every crosshair setting. The copy button on a profile puts its code on the clipboard. Import opens a box to paste someone else's code and optionally name it, shows a preview, and adds it as a new profile. A code with a typo is refused rather than applied. In the console, crosshair_code prints and copies yours, crosshair_import <code> adds one as a new profile, and copy_crosshair adds the crosshair of the player you're spectating or watching in a replay as a new profile. While spectating or watching a replay, the HUD shows the watched player's crosshair. The variables start at crosshair.lines.

HUD profiles

Overlay

SettingDefaultValuesVariableDescription
Show HUDOnOff, Onhud.showDraw the HUD
Scale10.5 to 2hud.scaleSize of the overlay
Update rate0 Hz0 to 1000 Hzhud.max_hzHUD updates per second; 0 sends one every frame

A profile is one HUD layout. The Profiles list shows every profile: Use makes it the default, and the buttons beside it rename, duplicate, reset or delete it. Profiles are stored in hud_profiles.json next to config.cfg. The game ships three: default; debug, which adds the full debug readout and a wall of performance, memory, movement, audio and network graphs down the right side; and replay, a lean layout for reviewing your own runs, built around the Keyboard board and the movement readouts and carrying no chat, minimap, scoreboard or map vote. replay is the profile a replay opens with unless the Replay row under Per mode names another. All three can be edited and reset but not renamed or deleted; hud_profile debug switches to it. The hud_profile and hud_profiles commands do the same from the console.

A HUD code starts with HUD- and holds one profile's layout. Copy code on a profile puts its code on the clipboard. Paste someone else's into the box above the list and press Enter to add it as a new profile. If the name is taken, a number is added to it.

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. F1 also works while watching a replay: it edits the profile the replay is showing, replay unless the Replay row under Per mode names another, and the replay bar steps aside until the editor closes. Panels on a layer that is turned off in the bar still show while editing, so they can be placed before the layer goes on.

Keyboard, under Movement in the add menu, draws a key board that lights as you move. Each cap is labelled with the key that action is bound to, so rebinding relabels the board, and its Rows setting turns off the weapon digits or the wide keys. In a replay it shows the player you are watching, and it stays on the last player you followed once the camera goes free. It is off in a live spectator view, where the server sends nobody's input but your own. It is on the shipped replay profile and is the Inputs layer in the replay bar.

Input log, also under Movement, lists the watched player's last few button presses in a replay, newest at the bottom: a cap labelled like the Keyboard board, the tick the key went down on, and how many ticks it was held, counting up while the key is down and freezing on release. Weapon swaps are listed with no hold length. Only presses that did something are listed: a jump press appears once it jumped, off the ground, a wall or the water, so a press in the air that went nowhere is left out; a fire press appears once a shot, a launch or a pin pull followed it, within the fire buffer, and a click on an empty magazine does not count; a reload press appears only if a reload started. Movement, crouch, walk, aim and use always list. It is built from the recording's own command bits and events, so it reads the same at any speed, follows scrubbing and single-stepping in either direction, and swaps to the new player when the camera does. Show picks which groups appear (movement, jump, crouch and walk, fire, aim, reload and use, weapon swaps), Rows how many lines it keeps, Grow whether new rows go up or down, and Hold length turns the tick count off. It draws nothing outside a replay. It is on the shipped replay profile and is the Input log layer in the replay bar, off until pressed.

Image, under Misc, shows a picture of your own. Put PNG, JPEG, GIF or WebP files in the hud_images folder next to config.cfg; Open folder in the Image panel creates and opens it, and Refresh picks up new or changed files, which the editor also does each time it opens. File picks the image. Transparency is kept and animated GIF and WebP files play. It starts at the image's own size; drag its edges or set Size to change that, and Fit decides how it fills a box of another shape: contain keeps the whole image, cover fills the box and crops, stretch fills it exactly. Scale and Opacity work as on any panel, and Rotate, Flip horizontal, Flip vertical and Pixelated (sharp edges when scaled up) change the picture itself. Files over 16 MiB or 4096 pixels on a side are not shown. The layout stores only the file name, so a HUD code or a Steam Cloud sync carries the placement but not the picture: on a machine without that file the panel is hidden in play and shows the missing name in the editor.

Per mode

The Per mode page picks the default profile and can assign a different one to each game mode, to spectating and to replays. The Replay row starts on the shipped replay profile; every other row starts on the default. Each row also takes a config file run when that mode starts. Point the Duel row at duel.cfg and its binds and settings are applied the moment a duel begins. The dropdown lists every .cfg beside config.cfg; pick Custom file to name one somewhere else. The setting is a variable per slot, so set cfg.duel duel.cfg does the same from the console.

Nothing is undone on leaving a mode. A config stays in force until something else changes it, so if one mode's config changes something you want back in another mode, set it again in that mode's config.

Display

Window

SettingDefaultValuesVariableDescription
Window modeBorderlessWindowed, Borderless, Fullscreenvideo.modeWindow mode
DisplayPrimaryPrimary or a monitorvideo.monitorDisplay to use; empty means the primary
Window width1600 px640 to 16384 pxvideo.widthWindow width in windowed mode; in fullscreen on Wayland, the width the scene renders at before scaling to the display
Window height900 px480 to 16384 pxvideo.heightWindow height in windowed mode; in fullscreen on Wayland, the height the scene renders at before scaling to the display
Display serverAutoAuto, X11, Waylandvideo.display_serverLinux only: which display server to open the window on; auto follows the session

Frame pacing

SettingDefaultValuesVariableDescription
V-syncOffOff, On, Fastvideo.vsyncOff presents as soon as a frame is done, On waits for the display, Fast keeps only the newest frame
Frame cap0 Hz0 to 1000 Hzvideo.fps_capFrame cap; 0 follows the display, rounded up to a whole multiple of its rate and never below 120
Low latencyOnOff, On, Boostvideo.low_latencyNVIDIA Reflex or AMD Anti-Lag when the driver offers it

View

SettingDefaultValuesVariableDescription
Field of view105 deg70 to 130 degvideo.fovHorizontal field of view
Render scale100%50 to 200%video.render_scaleScene resolution as a share of the window; above 100 supersamples

Image

SettingDefaultValuesVariableDescription
Brightness10.5 to 2video.brightnessExposure multiplier
Reticle brightness10.2 to 2.5video.reticle_brightnessHow bright a red dot, holo or scope reticle is drawn

Window width and height only apply in Windowed mode.

Graphics

Preset

SettingDefaultValuesVariableDescription
QualityMediumCompetitive, Low, Medium, High, Ultravideo.qualityRender preset; changing a detail below makes it Custom

Lighting

SettingDefaultValuesVariableDescription
ShadowsMediumOff, Low, Medium, High, Ultravideo.shadowsSun shadow resolution, reach and softness; Medium and up add shadows cast by players and props, Ultra sharpens the ones cast by realtime map lights
Ambient occlusionLowOff, Low, Medium, Highvideo.ambient_occlusionScreen space contact shading
Dynamic lightsOnOff, Onvideo.dynamic_lightsMuzzle flashes and explosions light the world

Surfaces

SettingDefaultValuesVariableDescription
Surface detailHighLow, Highvideo.surface_detailNormal, roughness, emissive and directional lightmap detail on surfaces
Texture detailHighLow, Medium, High, Ultravideo.texture_detailTexture sharpness: how many of the sharpest mip levels are kept, and how far anisotropic filtering goes at grazing angles
ReflectionsLowOff, Low, Highvideo.reflectionsReflection detail; Low refracts and reflects the scene in water, High adds screen space reflections and caustics

Image

SettingDefaultValuesVariableDescription
Anti-aliasingOffOff, FXAAvideo.antialiasingEdge smoothing; render scale above 100 supersamples as well
Sharpening00 to 1video.sharpenContrast adaptive sharpening after anti-aliasing
BloomOffOff, Onvideo.bloomGlow around bright light, where the map style uses it

Effects

SettingDefaultValuesVariableDescription
EffectsNormalMinimal, Normal, Enhancedvideo.effectsMuzzle flash, explosion and smoke detail; Minimal is the flat competitive look, Normal stirs smoke around players, Enhanced adds lingering smoke wakes and shadowed flashes; smoke shape and blocking are the same on every level
Physics propsOnOff, Onvideo.physics_propsBottles, crates and barrels react to the player, shots and blasts
Card effectsOnOff, Onvideo.card_effectsTrails, weather and pets following players holding a foil card
Smoke resolutionHalfFull, Halfvideo.smoke_halfRender smoke clouds at half resolution and upscale them, much faster inside and around smoke

Picking a Quality preset sets the detail rows under it. Changing one of those rows sets Quality to Custom.

Audio

Volume

SettingDefaultValuesVariableDescription
Master volume0.750 to 1audio.masterMaster volume
Weapons10 to 1audio.weaponsGunfire, explosions, reloads and weapon handling
Footsteps & movement10 to 1audio.movementFootsteps, jumps, landings, ladders, slides and water
World10 to 1audio.worldBullet impacts, breaking glass and walls, and doors
Voices10 to 1audio.voicesPlayer grunts, pain and death cries
Interface & cues10 to 1audio.interfaceHit markers, checkpoints and objective cues such as the bomb
Map ambience10 to 1audio.ambienceBackground sound a map plays
Map music10 to 1audio.musicMusic a map plays; the server station has its own volume

Spatial

SettingDefaultValuesVariableDescription
Spatial audioArcadeArcade, HRTFaudio.spatialArcade makes direction easy to hear on any headphones or speakers; HRTF simulates a listener's head for headphones
ReverbOnOff, Onaudio.reverbReverb

Radio

SettingDefaultValuesVariableDescription
Play the stationOnOff, Onaudio.radioPlay the music a server is streaming; off tells the server to send none of it
Local stationOffOff, Onaudio.radio_localRun a station from your radio directory on every session this pc hosts, alone or open to others
Station volume0.150 to 1audio.radio_volumeHow loud the server's station is
EqualizerOnOff, Onaudio.equalizerDraw the radio equalizer HUD element and the equalizer cards; off stops the audio analysis too

Network

Reporting

SettingDefaultValuesVariableDescription
Upload crash reportsOffOff, Onoiko.upload_crash_dumpsAfter a crash, send the developers a minidump on the next launch: the crashed process's memory, stacks, loaded modules and command line, plus the session log and the build. Environment variables are stripped; the log and the memory may still hold names, addresses and file paths

Content

SettingDefaultValuesVariableDescription
Download mapsOnOff, Onnet.auto_mapsDownload a session's map when this client lacks it

Connection

SettingDefaultValuesVariableDescription
Snapshot rate128 Hz32 to 128 Hznet.snapshot_rateSnapshots asked of the server each second: 128, 64 or 32. A server sends fewer on a poor connection or when its own upload is full

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.

  • help lists everything. help <name> explains one command or variable.
  • vars opens the variables window. vars video opens it filtered to one namespace. vars --changed shows only what differs from the defaults. The window stays on screen when the console closes, and takes the mouse again when it reopens.

Console size, font and opacity are the console.* variables, starting at console.height.

Cheats

Cheats are a session rule, not a build: the owner turns them on from Manage session > Match, or with game.cheats. While they are on, noclip, bookmark, teleport and the ballistics window work; with them off each one refuses and says so. A run made with cheats on never reaches a leaderboard.

bookmark saves where you are standing, with the direction you are facing and the speed you are carrying. teleport puts you back there. Neither takes a name unless you want one, and without one they use a slot called quick, which is what the default binds press. Name them, and you can keep as many as you like per map and bind a key to each: bind KeyH "bookmark jump3". bookmark list shows what this map holds and bookmark clear <name> drops one.

Bookmarks are saved per map by name, so a new bake of the same map keeps them. They live in bookmarks.json beside config.cfg, on this PC only.

KeyNameCommandAction
F3F3noclipNoclip
F8F8ballistics hitboxes
F11F11bookmarkBookmark here
F12F12teleportTeleport to bookmark
InsertInsertballisticsBallistics

Ballistics window

ballistics (Insert) opens a console window that records every shot, blast, surface hit, projectile step and other damage as the game resolves it. It works in dev builds and with cheats on, and records only while it is open. Online the server sends the record, so it covers every player and needs cheats on unless you host the game yourself. In replays it rebuilds your own shots from what the replay holds.

  • The list shows the newest records first: who fired, the weapon, what was hit and where, the damage dealt, or for a miss what it would have done at the impact point, how many surfaces the round crossed and why it stopped. Shotgun pellets from one trigger pull share a row. All or Mine narrows it to records you fired or took, and the kind boxes hide shots, blasts, surfaces or other records.
  • The detail pane shows the pick in full. For a shot, a line per hit like AK-47 head 111 × pen 0.71 × falloff 0.93 = 73 → dealt 73 · hp 100→27, then every surface crossed with its material, thickness, impact angle and damage kept, the hits with any lag compensation, each pellet, and the surfaces the shot wore down. For a blast, each player or dummy in reach with distance, the distance after walls, what walls let through, self damage, push and health. Copy puts the whole breakdown on the clipboard.
  • Overlays draw recent records in the world while the window is open, for as long as Keep says. Paths warm from yellow to red as a round loses damage, turn white inside a surface, and mark where it went in (green), came out (amber) and stopped (red). Labels put the damage and each surface's numbers beside them, and on the point where a round ends up, what it would still do to someone standing there, as 32 body · 64 head · 24 limb. Lag-comp draws the capsules the server tested a lagged shot against. Hitboxes draws every body's hit capsules, through walls or depth-tested, and stays on with the window closed; Blast falloff shades the damage disc around bodies and live grenades. The picked record is drawn on top and stays until you pick another.

Pause stops recording and freezes the overlays, and Clear empties the window. ballistics hitboxes, ballistics paths, ballistics pause and ballistics clear do the same from the console or a bind. Nothing draws in clean renders.

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 Mailbox is 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:

  1. The path in the EDS_SETTINGS environment variable.
  2. config.cfg in the working directory, if it exists.
  3. config.cfg next to the game executable, if it exists. Use this for a portable install.
  4. ~/.config/eds/config.cfg on Linux, %APPDATA%\eds\config.cfg on 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.
  • Steam: public sessions players host through Steam.
  • Direct: type host:port and press Connect or Watch. The port is required. The default server port is 27960.

Connect joins as a player when there is room, and otherwise as a spectator queued to play. 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

A dedicated server holds one session and plays its rotation for whoever joins. A player who joins while a match is running spectates until it ends, queued to play, or with sv.late_join on plays and sits out until the next fight.

A ranked server splits play across sessions of its own, so joining one puts you in its hub instead. The hub shows the sessions running and the ladder. Join warmup takes you into the warmup session while the solo or duo queue finds you a match.

Invite codes

A session opened to Steam friends or Steam public has a five character code. Type it into Join with a code on the Play screen, or use join <code> to play and watch <code> to spectate. The Esc menu and Manage session > Session show the code with a Copy button. A session open only on LAN has no code; players there connect to its LAN address.

Map downloads

If a session 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.

  • savereplay saves the current match so far.
  • record starts a server-side recording, including warmup. stop ends it and saves it here. Session owner or server admin only.
  • highlight, bound to H, marks this moment in the match's replay. Everyone in the session can, up to 6 a minute each, and only while the match is being recorded. The feed says whether it landed. A server turns them off with sv.highlights.

Highlights are kept in the replay file, so anyone who opens it sees them. The right rail lists them under Highlights, one group per player with yours first, and the scrub bar marks each one; yours stand taller. Clicking a time seeks to 5 s before it, since the key is usually pressed just after the moment. The replay page on the site marks them on its timeline and lists them per player below it.

Replay controls: Enter 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. Space is not a transport key here: it flies the free camera up.

The left rail holds the camera and the layers. Camera lists everyone in the match with First and Third beside each name, and Free, Director and Rig below them. Layers is what the game HUD draws over the replay: Game HUD turns the whole overlay off, and the buttons under it turn one part of it on or off. Inputs is the Keyboard board, which lights with the input of the player being watched, and Input log is the scrollback of their recent presses with the tick each landed on. The HUD stays up with the controls showing and insets itself clear of the rails, so a layer goes on or off in front of you.

Visuals, Render, Cinema, Tracks and Rig, in the top right, each open a window over the replay. Visuals holds the drawings a replay can add that the match itself never showed:

  • Card effects puts every player's card effect on from the first tick to the last, whatever the mode or phase, each with the trail, weather or pet they had equipped. Override forces one effect on everyone instead, by card, so a match of players who own no foil still gets ribbons.
  • Paths draws a ribbon along where each player went over the last few seconds, in the style of the map editor's run overlay: one colour per player, tinted by speed, fading towards the tail, broken across deaths and teleports. Window is how many seconds it covers, Width its thickness on screen, and X-ray draws it through walls. The first time Paths goes on for a replay it reads the whole file once in the background; scrubbing after that is free.
  • Thirds grid rules the frame into thirds as a framing reference while a shot is composed. It sits inside the letterbox, so with 2.39 on it covers the scope frame and not the bars, and it is authoring only: it never reaches a render.

All of these are watch variables, so they persist, and they never appear outside a replay. So are the layers: watch.hud and the rest.

Render is where a replay becomes a file: Track binds the camera to one of the replay's camera tracks, Ramp lets that track drive the replay speed, Go to start seeks to its first key, and Render… opens the render dialog.

Cinematic mode

Cinema, Tracks and Rig in the replay bar open panels over the replay: one for the look, one for camera tracks, and one for the camera rig. They are independent, so any of them can be up on its own. All are ordinary windows, as are Visuals and Render: drag the title bar to move them, the bottom right corner to resize, and they come back where you left them. Opening Cinema, Tracks or Rig turns the cinematic render path on; Visuals and Render leave it alone. The cinema console command toggles the look and the tracks together, and cinema visuals, cinema render, cinema mode, cinema tracks and cinema rig open one at a time, so each can be bound to a key.

Cinematic mode raises the render quality past what you play at and adds the film effects, so a replay can look its best at sixty frames a second rather than as fast as possible. Nothing it does touches your own video settings: turn it off and your settings are back.

The look

The Cinematic toggle turns the whole chain on. With it off every setting below is ignored.

  • Quality floor lifts shadows, ambient occlusion, reflections, water, textures and bloom to High or Ultra for the replay. It is a floor, not an override: anything you already run higher stays where it is.
  • Supersample renders the scene up to four times larger and samples it back down, on top of video.render_scale.
  • Depth of field blurs what is not in focus. Focus on a distance, or hold focus on a player and the camera keeps them sharp as they move. Aperture is how fast the world falls away; bokeh is how much a blurred highlight blooms.
  • Motion blur smears along camera movement. It reads best on a slow shot.
  • Film adds a vignette, grain and colour fringing, and can letterbox the frame to 1.85 or 2.39.
  • Grade sets shadows, midtones, highlights, colour and warmth.

Every one of these is a cine console variable, so a look can be kept in config.cfg or an .cfg file and executed. Reset puts the whole group back to its defaults.

Flying the camera

With the panels open the cursor stays free for them, and the right mouse button takes the camera:

  • Hold right mouse and move to look. This puts the replay on the free camera.
  • W A S D fly. Space or E moves up, Q moves down.
  • Hold Shift to fly fast.
  • Mouse wheel changes fly speed.

The same keys as the map editor, and the same reason: a shot is composed by flying it. Space flying up is why play and pause is Enter in a replay. Hide, or Escape, takes the panels down with the rest of the replay UI and hands the mouse straight to the camera, for anyone who would rather fly without holding a button. Escape again brings them back where they were.

The camera rig

Flying a shot by hand is not repeatable. The rig places the camera by numbers instead: pick a player and the camera holds a fixed offset from them, so the framing is the same every time and a slow pan does not depend on how steady your hand is. Rig, in the replay bar's Camera group, puts the camera on it, and Camera rig, under Cinema, is where it is tuned. Every control is a slider with a number box beside it, so a value can be dragged or typed.

Measured from is what the rig's rotation is read against, and it is the setting that decides how the shot behaves:

  • Player rides with the subject. Turn and the camera swings with them, like a third person view that never drifts.
  • Tripod holds a fixed bearing. The subject turns, runs and comes back, and the camera does not move: the shot is locked off.
  • Mouse hands the rotation to the right mouse button, but the distance stays locked, so you can rotate freely around a player without ever changing how far away you are.

Yaw and Pitch are the angles, and 180 yaw puts the camera in front looking back. Pan turns the rig by itself at a fixed number of degrees a second, which is how you get an even orbit without touching the mouse.

Distance is the arm length and is held exactly. Shoulder offsets the camera sideways, Height raises the point it pivots about. Wall pull-in is off by default, because a wall quietly dragging the camera in is the opposite of consistent placement; turn it on and Closest, Clearance, Pull in and Ease out say how far it may come and how fast.

Field of view and Roll are the lens. Field of view at 0 keeps video.fov.

Focus is the same depth of field as the Cinematic panel, brought here because focus is part of the shot. Hold it on a distance or on a player, and Rack rate eases focus to its target rather than snapping, so pulling focus from one subject to another is a move rather than a cut. At 0 it snaps, which is what it did before.

The rig is a live camera, so Add key in the camera track panel captures it exactly as it stands. A rigged shot can be rendered as it plays, with Render… and no track, or keyed into a track and rendered from that.

Every control is a rig console variable, so a rig can be kept in config.cfg or an .cfg file and executed, and Reset puts the whole group back to its defaults.

Camera tracks

A camera track is a list of keys. Each key holds a position, a direction, a roll, a field of view and a playback speed, and is pinned to a tick of the replay. Between keys all of that is interpolated, so the camera is a function of where you are in the replay: scrub and the shot scrubs with you, and the same track plays the same way every time.

To make one:

  1. Tracks opens the camera track panel, and the plus button starts a track.
  2. Hold right mouse and fly to where the shot starts. Add key.
  3. Seek to where the shot should be next, fly there, and Add key again. Repeat.
  4. Open Render from the top right and pick the track under Track. The camera snaps to it, the scrub bar shows its span, and the normal Play, seek and speed controls drive it. Go to start seeks to its first key.

Add key takes the camera exactly as it is now, so composing a shot is flying it. Recapture moves the selected key to where the camera is now, Go to seeks the replay to a key, and the fields under the timeline edit a key by hand. Drag a key along the timeline to move it in time. The track being edited in the panel and the track the camera is bound to are independent: you can keep editing one shot while another plays.

  • Linear, Smooth and Tight are how the path is drawn through the keys. Smooth arcs through them, Tight holds a straight line between them without overshooting, Linear is a straight line.
  • Look keyed aims the camera the way each key was pointed. Look at a player aims it at them instead, and it tracks them as they move.
  • Speed on each key is the replay speed at that key, from 0.02x to 8x. With Ramp on, in the Render window, the track drives the speed itself, so a shot can fall into slow motion over a kill and come back out of it. Ramp off leaves the speed to the replay bar.
  • Focus on a key holds the depth of field there, in units, and the camera racks focus between keys that have one. Focus here takes the current focus distance, whether that is a player or a set distance, and Clear focus lets the key follow the Cinematic panel again. A key with no focus leaves the panel in charge.
  • The coloured diamond at the left of a row turns that row on and off, and Rows, by the zoom buttons, lists the same switches. An off row is dimmed but keeps the keys it already has, and those keys still drive the camera; Key all and Select all skip it, so a shot that never wants a speed ramp can leave Speed off. The choice is the editor's rather than the track's: it holds for every shot until it is changed.

Pacing, next to the key buttons, draws the track in the world so a shot's movement can be judged before it is played. Speed tints the path by how fast the camera moves against the track's average, warm for faster and cool for slower, and Accel tints each stretch between keys by how much faster or slower it is than the stretch before. Dots land every half second of wall time, so even spacing is even movement, and every key gets a small frame showing where it points. With the free camera up, a line runs from the last key behind the playhead to the camera, coloured by the pace a key placed right now would give, and the spacing meter over the replay bar reads the same thing: centred to hold speed, left of centre to slow down, right of centre to speed up. The meter stays up with the controls hidden and while the camera is being flown, and it does not need Pacing on. The timeline colours the spans between keys the same way.

Save writes every track for this replay to one file. See Files and folders. Tracks whose replay is no longer on this machine are cleaned up when Watch is opened. A track file written by this build has a version older builds refuse; files from older builds still open.

Rendering to video

Render, in the Render window, writes the bound track to a video file at a fixed frame rate, with every frame rendered in full and read back, so the result never depends on how fast the machine runs. The replay advances exactly one frame's worth of time per frame, the track's speed ramp becomes slow motion, and the window keeps showing the frames as they are rendered with a progress bar over them. Authoring overlays stay out of the file: the camera path, its key frames, the pacing dots, the framing sphere, player paths and any debug draw are all dropped for the duration, so what is captured is the shot. Card effects are part of the shot and are kept. Escape or Cancel stops it and keeps what was written.

The dropdown beside Render picks the profile it uses, and the button next to it opens the dialog, where Video, Sound and Output hold the settings that profile saves. The panel under them reads out the frame count, duration, size, frame rate, bitrate and rough file size of what is about to be written.

With no track bound, or None picked as the dialog's Track, the render starts at the playhead and plays forward with the current camera, whether that is following a player, the director, the rig or the free camera, at the current replay speed. It runs until Stop or the end of the replay, and the sound ends with the picture. The free camera and a third-person orbit hold where they are, since nothing flies them during a render.

  • FPS, width and height are the file's. Scale renders the scene that many times larger than the file and resolves it down, on top of the Cinematic panel's own supersample. Shadows picks the shadow map size.
  • Samples above 1 renders that many sub-frames per frame, spread across the shutter, and averages them in linear light: real motion blur on players and projectiles, not just the camera, and anti-aliasing with it. The shutter is the Cinematic panel's motion blur setting, or half a frame when that is off; the camera-only blur is turned off while sampling so nothing is blurred twice.
  • Output is a .mov in DNxHR 444 10-bit through ffmpeg, which DaVinci Resolve reads on every platform including the free Linux build, which cannot decode H.264 or H.265. Give a folder instead of a file to get a PNG sequence, 16-bit when sampling, and that is also what you get when ffmpeg is not on the path (EDS_FFMPEG names it elsewhere). Renders default to the renders folder; see Files and folders.
  • Resolve's free timelines top out at 60 frames a second and Studio at 120; a faster clip is conformed or retimed through Clip Attributes, so render at the timeline's rate unless the plan is to slow it down in the edit.

The render console command does the same from the console or a bind: render <track> [fps] [WxH] [samples], render here … renders the current camera from the playhead, and render stop stops.

Hosting a server

Local server

Play > Custom starts a session on a server inside the game. It is yours alone until you open it from Esc > Manage session > Session, under Who can join:

  • Just me: nobody else can join.
  • LAN: players on your network connect to the LAN address shown there, from Browse > Direct. There is no code and no password.
  • Steam friends: your Steam friends join through Steam, and so does anyone with the invite code. No port forwarding is needed.
  • Steam public: anyone can join, and the session shows in Browse > Steam.
  • Invite friends sends invites through Steam.

Manage session is the owner's panel. Session lists everyone: drag a player between the teams, the players and the spectators, or kick them. Match sets the mode, guns, rounds, time limit and tagging, turns cheats on, picks the track for a race, and starts and ends the match; runs with cheats on never reach a leaderboard. Maps switches the map, Radio drives the station, and Vars lists every rule. If the owner leaves, the next player becomes owner.

Session rules are the game.* variables. See game. Set them from Manage session, or with set in the console while you own the session. sv.admins does nothing on a local server.

Dedicated server

eds --dedicated runs the dedicated server. Everything after --dedicated is the server's, so the game's own options cannot be mixed in ahead of it. In Steam, find the game 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 --dedicated --hostname "my server" --map downtown

On Windows it is eds.exe --dedicated, which attaches to the terminal that started it.

There is also eds-server, the same server as a standalone binary with no game attached. It is what the Docker image fetches and runs; the Steam package does not ship it. Both take the same flags and behave identically.

sv.mode sets what the server runs:

  • A game mode, ffa by default, or tag, gungame, horse, bomb or ctf: one session playing a rotation of maps and modes for whoever joins.
  • race: one session of time trials on a rotation of tracks, with server records.
  • ranked: a rated ladder with solo and duo queues, played across as many sessions at once as sv.ranked_max_sessions allows.

Settings apply in this order, later wins:

  1. server.cfg in the working directory.
  2. Environment variables.
  3. Command line flags.

Changes to sv.bind, sv.mode, sv.backend, sv.db, sv.default_map, sv.tracks_dir, sv.record, sv.record_dir, sv.radio, sv.radio_dir, sv.scripts_dir and the sv.ranked_* variables 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 ffa
set sv.hostname "my server"
set sv.region "eu-west"
set sv.password ""
set sv.admins [steam:76561198000000000]
set sv.rotation [downtown:ffa, downtown:gungame, downtown:tag]
set sv.max_players 16
set sv.warmup_secs 20
exec extra.cfg

Command line flags

FlagDoes
--bind <addr:port>Sets sv.bind.
--mode <mode|race|ranked>Sets sv.mode.
--hostname <name>Sets sv.hostname.
--password <text>Sets sv.password.
--auth <required|optional|off>Sets sv.auth.
--map <name>Sets sv.default_map.
--max-players <n>Sets sv.max_players.
--max-viewers <n>Sets sv.max_viewers, the spectator cap.
--public-addr <host:port>Sets sv.public_addr.
--privateSets 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-recordDoes not record matches.
--no-downloadsDoes not send maps or replays to clients.
--cheatsAllows noclip in every session.
--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-controlTurns the control API off.
-v, -vvMore logging.

Environment variables

VariableDoes
EDS_BINDSets sv.bind.
EDS_PUBLIC_ADDRSets sv.public_addr.
EDS_BACKENDSets sv.backend.
EDS_BACKEND_KEYSets sv.key.
EDS_MAPS_DIRMap folders, separated by : on Linux and ; on Windows. Default assets/maps.
EDS_REPLAY_DIRWhere recordings go.
EDS_RADIO_DIRWhere the station's songs and playlists live. Default radio beside the server.
EDS_CONTROL_SOCKETControl API address. tcp:<addr:port> or <ip:port> is TCP, anything else a unix socket path.

The Docker image

oci.oiko.lol/plus3/eds-server-images/images/eds-server runs a dedicated server in a container. Pull it with no account:

docker run -p 27960:27960/udp -v eds-data:/data \
  oci.oiko.lol/plus3/eds-server-images/images/eds-server:latest --hostname "my server"

The image holds only the updater. It fetches the server, the shipped maps and the character art on its first start, about 100 MB, and keeps them in /data. Mount /data on a volume: without one the container fetches the lot again every time it is recreated, and it has nothing to fall back on if a fetch fails.

Everything after the image name goes to the server, so the flags above all work. docker/compose.yaml in the source tree is a worked example.

Updates

The image updates itself. It reads the published version when it starts and every EDS_UPDATE_CHECK_SECS after that, fetches only the files that changed, and then waits: by default it restarts the server the moment it is empty, so nobody is thrown out of a match. A server that never empties is never updated unless EDS_UPDATE_DEADLINE_SECS says otherwise.

An update found when the image starts is applied before the server starts, since nobody can be on it yet.

If an update starts and then dies within EDS_UPDATE_PROVE_SECS, the server goes back to the version it was on and stays there until a newer one is published.

VariableDoes
EDS_AUTOUPDATE0 installs once and never checks again. The first install still happens: the image carries no server.
EDS_SERVER_VERSIONRun this version and no other. Empty follows the published one.
EDS_UPDATE_WHENempty waits for nobody to be on the server, idle waits for the match to end, now restarts straight away. Default empty.
EDS_UPDATE_CHECK_SECSHow often to look for a new version. Default 60, and never less than 30.
EDS_UPDATE_DEADLINE_SECSUpdate anyway once an update has waited this long. Default 0, which waits.
EDS_UPDATE_PROVE_SECSAn update that dies inside this many seconds is rolled back. Default 60.
EDS_UPDATE_DIRWhere the server and its assets are kept. Default /data/server.
EDS_UPDATE_URLWhere to fetch from. Point it at a mirror of the published files to update a server with no route to the internet.

Waiting needs the control API, which the image has on a socket in the container. With --no-control the server cannot say whether a match is running, so an update is applied as soon as it is fetched.

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.password makes players enter a password to connect.
  • sv.auth is required by default: players must be signed in through Steam. optional and off relax it.
  • sv.admins lists admin player ids, like steam:76561198000000000. Find your Steam ID in Settings > About. Admins manage the server. An empty list means nobody is admin; the server console and the control API still work. A lone * hands admin to every client that connects, whether or not sv.auth verified them, which is meant for a server you are testing on.

members lists everyone on the server, playing or spectating, each with a #member number. kick, ban, tell, kill, loadout and score take a player's name or that #member.

explode, kill, loadout and score reach into the match itself, and any admin may run them. explode 512 64 -900 3 sets off a blast three times a grenade's size at that point, and explode <player> 3 puts one at their feet; intensity scales the damage, the reach and how it looks and throws, and stops at 20. kill <player> drops somebody where they stand, and kill <player> 4 blows them apart. loadout <player> bow revolver grenade hands over those three whatever the session offers, none in place of a gun empties that slot, loadout <player> shows what they carry and loadout <player> reset puts them back. score prints the standing, score --json prints it as one line a script can read, and score <player> 7, score <player> kills +2 and score team 0 3 write it. Two modes read that per-player number as something else: gun game keeps the ladder rung there, so writing it moves the player's gun, and tag counts time there, which score takes and prints in seconds.

Admins get Manage server from the Esc menu, and from the hub on a ranked server. Overview shows the server, who is on it and what is playing, with Start, End and Next. Session is the member board: drag players between the teams, the players and the spectators, kick or ban. Match, Maps and Rotation set what is played. Players lists everyone on the server with kicks and bans. Radio, Vars (every game.* and sv.* variable), Bans, Banlists and Boards do what they say. A ranked server's sessions take no commands, so there Overview is read-only and Session, Match, Maps and Rotation are gone. 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.

With sv.map_url set, the server also reads <url>/index.json when it starts and lists the maps published there. maps prints the maps here and the ones only on the map server, maps refresh reads the index again, and map <name> on a listed map fetches it first and switches once it is in. Manage > Maps offers the listed maps too, with a <name>.jpg published beside <name>.blvl as the thumbnail. A fetched map is kept in ~/.local/share/eds/server/maps (EDS_SERVER_MAP_CACHE), so it is a local map from then on; a map already in a map folder is never replaced by the map server's copy.

Rotation, ranked and race

  • Rotation servers: sv.rotation lists map, map:mode, map:mode:variant,variant or map:mode:variants:file.cfg entries; the third form turns on the named map variants and the fourth also runs a server profile. Rotation modes are ffa, tag, gungame, horse, bomb and ctf. A match starts once sv.autostart_players players are playing. sv.warmup_secs and sv.results_secs set the pauses. Use rotation add, rotation remove, nextmap and map to change it live.
  • Map voting: sv.mapvote true puts 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 the vote command. sv.mapvote_choices is how many entries are offered and sv.mapvote_secs how 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 by sv.mapvote_recency (how hard it keeps off what was played lately) and sv.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|reset drives it by hand; reset forgets what has been played and what has won.
  • Ranked servers: set sv.mode ranked. The sv.ranked_* variables set how many sessions run at once, rounds, queue widening, warmup and pauses. Ranked sessions take no commands from anyone.
  • Race servers: set sv.mode race. sv.rotation lists track ids: map/id or id for a track one of the server's maps carries, else a .btrk in sv.tracks_dir, else a track the backend knows. sv.race_track_secs sets how long each track runs. With sv.race_rules practice, a runner who falls goes back to their last checkpoint instead of restarting.

Server profiles

A rotation server can run extra config for the mode or the map it is on. Put mode-<mode>.cfg or map-<map>.cfg beside server.cfg -- mode-ctf.cfg, map-downtown.cfg -- and it runs whenever the session lands on that mode or map, whether the rotation moved it there, an admin ran map, or a vote picked it. A rotation entry can also name a file of its own as a fourth field, downtown:ffa::sniper.cfg, with the variants field left empty if there are none; that file runs for that entry only, and a missing one is logged.

They are ordinary console scripts, the same syntax as server.cfg. They run in the order mode, map, entry, so a later one wins where they disagree, and they run once the map is in and no match is running. status lists the ones that ran last.

Nothing is undone on leaving a map or mode. A profile stays in force until something else changes it, so if one profile changes something you want back elsewhere, set it again in that profile or in the ones that follow. writeconfig writes the live values, profile changes included.

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 true

Every 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.

Nobody listening. With no listeners the station stops rather than plays to an empty room: no decoding, no encoding, and the playhead stays where it is, so the next person to listen picks up the song the last one left rather than arriving somewhere in the middle of the library. radio status and the Radio page of Manage call this idle. It is not the same as radio pause: a pause is yours and outlives an empty room, so a station you paused stays paused when somebody starts listening.

Driving it. radio on the console, or the Radio page of Manage:

radio status
radio skip
radio pause
radio play
radio playlist chill
radio shuffle on
radio list drive
radio jump 41
radio rescan

radio 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.

Playing locally. The game's own server plays songs from radio in its data directory: ~/.local/share/eds/radio on Linux (or $XDG_DATA_HOME/eds/radio) and %APPDATA%\eds\radio on Windows. EDS_RADIO_DIR points it somewhere else. It is off until you turn on audio.radio_local (Settings > Audio > Local station, or Station on this pc on the Radio page of Manage session). With it on and that directory present, every session the game hosts plays the station exactly as a dedicated server would: a race or a map test on your own, and a session you open to LAN or Steam streams it to everyone who joins. radio on the console drives whichever station you are on.

Control API

--control-socket serves a JSON API for scripts and panels: server status, sessions, console lines and events. Whoever can open the socket controls the server, so set its file permissions with care.

GET /sessions lists the sessions and GET /sessions/<id> shows one, with its members. POST /sessions/<id>/<action> runs start, end, map, mode, weapons, kick or role on it, naming members by their member number. The server's own session is 1. A ranked server's sessions refuse every action.

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 local 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 by saying what it will use. There are two lists, and a script may have either or both, in either order, with nothing but comments before them:

export const commands = ["radio skip", "announce", "tell"];
export const capabilities = ["npc", "map.light", "player.disguise"];

commands names the console lines the script may run. capabilities names the parts of the API it may call: see The API. A capability is a namespace, which covers everything in it, or one call in that namespace, which covers only itself: "map" allows every map call, "map.light" allows only the light switch. A capability that names no real call stops the script loading, so a typo is caught rather than quietly doing nothing.

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" allows announce with anything after it.
  • "radio skip" allows radio skip and nothing else from radio.
  • Variables must be named: "set sv.warmup_secs" or "get sv.rotation". A bare set is 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 both lists before enabling somebody else's script. Every command a script runs is written to the server log, and script info <name> prints what a running script may run and may call.

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 !name to chat. The line is not shown to other players. The handler gets session, player, name, args, raw and reply(text), which sends the player a private line and needs tell in 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, warn and console.log write 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 number of the session it happened in as session: 1 is the server's own session, a ranked server numbers its matches from there, and 0 is the ranked hub:

EventFields
player_joinplayer, watching
player_leaveplayer, reason: left, kicked, timeout or closed
chatplayer, text; ! commands are not included
killkiller (null for a fall or the world), victim, weapon
match_startmap, mode
match_endmap, mode, result
round_wonwinner, tally
map_changedmap
session_opened
session_closedreason
map_loadedmap, modes, and how many zones, props, lights, doors, smokes and explosions the map offers
player_spawnplayer, pos
player_deathplayer, killer, pos
damageplayer, attacker, amount, part: head, body or limb
zone_enterplayer, zone, tags
zone_exitplayer, zone, tags
surface_brokensurface, tags, cause (bullet, blast, contact, touch, underfoot, linked, auto or script), player (null when nobody caused it)
surface_damagedsurface, tags, health from 0 to 1, player: a named surface wore down a stage without breaking
npc_killedid, tag, killer
npc_goneid, tag, landed, pos
signalname, arg, player (null when nobody caused it): the map's automation emitted a signal, or one was sent to it

A player is { ref, id, name, member, manager }. ref is # and their member number; use it to name them in commands like tell and kick. manager is true for an admin. Events from the API carry more: slot, alive, hp, team, pos, yaw, kills, deaths and the prop they are wearing.

tell <player> <text> and announce <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 server's session.

A gamemode cannot afford to miss an event. The ones a match turns on -- match_start, match_end, round_won, map_loaded, player_spawn, player_death, zone_enter, zone_exit, npc_killed, npc_gone, surface_broken and signal -- queue behind a script that is running slow rather than being dropped. Everything else is dropped the moment the scripts fall behind, and script list says how many went that way.

The API

Console lines say some things badly. Launching a target on an arc, reading where sixteen players are standing, or putting somebody in a crate are not command lines, so scripts call them instead:

export const commands = ["announce"];
export const capabilities = ["npc", "map", "player.disguise"];

import { map, npc, on, player } from "eds";

const id = await npc.launch({ from: "skeet_launch", to: "skeet_target", tag: "clay" });
await map.lights.set({ tag: "room=gallery" }, false);
await player.disguise("#3", "crate");

Every call is a round trip to the server and lands between ticks, so the API is shaped to be asked once rather than in a loop: world.read() hands back every player, target, door and light in one go, and a selector reaches a set of the map's things at once. A selector is a name ("gate"), a tag ({ tag: "room" } for anything carrying the key, { tag: "room=arena" } for that value) or "*" for all of them.

NamespaceCalls
worldread(), players(), player(who)
playerdisguise, teleport, freeze, team, loadout, damage, kill, score, model
npclaunch, spawn, kill, clear, list
mapmeta, zones, zone, props, lights.list/set/toggle, doors.list/open/close/release/lock/unlock, surfaces.list/break/restore/damage, smoke.list/set/toggle/tune/spawn/remove/cloud, sound.list/set/toggle/play, explosions.list/trigger/at, signal(name, arg?, player?)
hudset(key, value), clear(), mode(name)
gamestart, end, mode, rules

A call rejects with the reason when it is refused or cannot be made: a capability that was not asked for, a prop the map does not have, a player who is not in the match.

npc.launch throws a body from one place to another and both the server and every client fly the same arc from the same numbers, so a target costs its launch and nothing more. from and to are zone names or coordinates; gravity below 1 makes it glide rather than fall, arc lifts the throw over the straight line, and tag is a name of your own that comes back on npc_killed. Eight may be in the air at once.

player.disguise puts somebody in one of the map's props: a block the map already carries, so there is nothing extra to download. They still move and are still shot at as a body -- what changes is what everyone else sees.

hud.set puts a named value on everyone's HUD, up to six rows, and hud.mode names the mode for the HUD and the server browser. Neither reaches into the page: the script publishes values and the HUD renders them.

mode script puts a session in a script's hands. It plays as a free-for-all -- everyone moving and shooting, nobody's round won for them -- and the script keeps the score with player.score and ends rounds with game.end.

What a map offers a script

A map says what it carries, and the editor's Window > Script sets it. A script reads it with map.meta() and on map_loaded:

  • Modes are names a script offers, so a script can tell whether the map it just loaded is one it can run.
  • Tags are key=value pairs, on the map itself and on blocks, models, lights, script zones, smoke generators, sound emitters, projectors, explosions, signs, jump pads and teleporters. They are how a script finds things without hard-coding names.
  • Script zones are named boxes placed from the Markers palette. They mean nothing on their own: they are where a script throws a target from, where it scatters people, and what zone_enter fires for.
  • A block tagged prop=1 becomes a disguise, named by the tag's value or by the block's own name.
  • A light or a door with a name or tags is one a script can reach. An unnamed one cannot be switched, which is what keeps a map with a thousand lights off the wire. Only a Dynamic light changes on screen when a script switches or tints it; a static one is baked into the map's lighting, and the server logs a warning when a script touches it.
  • A breakable block or model with a name or tags is a surface. map.surfaces.list() gives each one's name, tags, ballistic profile, debris kind, whether it is broken and its health from 0 to 1, and map.surfaces.break(sel), .restore(sel) and .damage(sel, amount) act on every surface a selector matches and resolve to how many moved. A block made of several pieces, and blocks that share a name and tags, are one surface.
  • A smoke generator or an explosion with a name or tags is one a script can reach. map.smoke.list() gives each generator's name, tags, position, whether it is on and its look; map.smoke.set(sel, on), .toggle(sel) and .tune(sel, { color, size, rate, ... }) act on every one a selector matches. map.smoke.spawn({ at, tag, ...look }) puts down a generator of the script's own at a zone or a point and resolves to an id that names it from then on (map.smoke.set(id, false), .remove(id)); sixteen may be up at once, and they stay through round resets until the script removes them or the map changes. map.smoke.cloud(at) pops a smoke grenade's cloud instead, the kind that blocks sight. map.explosions.list() gives the placed explosions and map.explosions.trigger(sel, { scale, damage, ... }) sets them off with any of their looks overridden; map.explosions.at(spot, opts) sets one off anywhere, a grenade's look unless told otherwise. damage is 0 for a show and 1 for a grenade's blast, and player names who the blast is credited to. Eight can go off in one tick.
  • A sound emitter with a name or tags is one a script can reach. map.sound.list() gives each one's name, tags, position, whether it is on, how it plays and whether it is heard everywhere; map.sound.set(sel, on) and .toggle(sel) switch every one a selector matches, and .play(sel) plays each once, and all resolve to how many moved.
  • A projector with a name or tags is one a script can reach. map.projector.list() gives each one's name, tags, position, whether it is on, and what it shows now; map.projector.set(sel, on) and .toggle(sel) switch it, .text(sel, "...") puts up text of up to 256 bytes in place of the map's, .image(sel, name) shows another of the map's images by its asset name, and .reset(sel) goes back to what the map gave it. Text and images a script puts up stay through round resets until the map changes, reach players who join later, and are recorded in replays.
  • Signals are what the map's automation emits and listens for (see Automation). A script hears them as signal events and sends one with map.signal; a name the map does not know is rejected.

A light switched off in the inspector still has its place in the map, so a script can switch it back on. What the lighting bake will not give back is its bounce, so put a light meant to be switched where its bounce is not holding the room up.

TypeScript and examples

sdk/script/eds.d.ts types the whole API, and just check-sdk checks the examples against it. sdk/script/examples has three scripts:

  • skipsong.js lets anyone skip the radio song with !skipsong, with a cooldown for each player.
  • skipvote.js ends the match when three players type !skip, which opens the map vote on a server with sv.mapvote true.
  • sandbox.mjs runs three rounds on the sandbox map -- prop hunt, skeet shoot and lights out -- one for each thing the API can do. just demo-map builds the map it needs.

The server runs JavaScript only, so compile TypeScript first. tsc keeps the commands and capabilities lists at the top of the file. A bundler may move exports to the end, so with esbuild put them in --banner:js= instead.

Map editor

Opening

  • Maps > Launch Editor opens the editor on a starter map with a floor and a player start, and shows the Start window.
  • Maps > select a map > Edit opens it.
  • File > Start… in the editor shows the Start window again.

The Start window lists the common ways in on the left, and the maps you opened, copied or saved in the editor lately on the right; click one to open it. The actions are:

  • New map: Blank starts over on a starter map, Copy writes a copy of a block map into the custom maps folder and opens it, and Simplify rebuilds any map from a file as editor blocks.
  • Open map: pick a block map to edit.
  • New track: pick a map, then start a blank track or duplicate one of that map's tracks.
  • Open track: pick any track.
  • Debug map: open any map in the map debugger.

Simplify runs in the background with a progress bar and can be cancelled until it starts writing the file. It saves the result into the custom maps folder as <map>_simple and opens it. It rebuilds the map's shape only: textures and lighting don't carry over, and it skips the movement check that eds-bake --blockify runs. Opening anything from the Start window replaces the map you are editing, so save first.

Any map that carries editor blocks can be edited: maps made in the editor, and maps rebuilt from a bake by Simplify or eds-bake --blockify. Saving a map that came from elsewhere writes a copy into the custom maps folder, and that copy stands in for the original from then on; delete it on the Maps screen to get the original back. Maps without blocks open read-only in the map debugger. Opening the editor closes a session you host; on somebody else's server, leave first.

Camera

  • Hold right mouse and move to look.
  • W A S D fly. E or Space moves up, Q moves down.
  • Hold Shift to fly fast.
  • Mouse wheel changes fly speed. While you hold a gizmo handle it nudges the drag by one unit per notch instead -- a degree per notch on a rotate ring -- for fine placement on top of the grid snap; in Scale mode the wheel also takes an object below the grid size, down to one unit.
  • F focuses the selection.

Window > Camera sets the fly and sprint speeds, the look sensitivity and the speed the wheel multiplies, and shows the camera position and angles to read or type into. It also holds the outline settings: how thick and how opaque a selected item is outlined, in what colour, how thick the outline under the cursor is, and whether the outline is kept while a gizmo handle is held. By default it is dropped, along with the face highlights, so the geometry under it stays clear while you line a piece up; a door being posed keeps its outline either way. The grid, snap and light guide toggles sit in the same window. Everything but the wheel multiplier is kept between sessions.

Settings

Window > Settings holds what the editor keeps between sessions and does not need while you are placing things: the frame cap and quality preset the editor renders at, the layout helper line width and distance labels, bake on save, and a button that puts every window back where it started. The editor never runs above 120 fps or above video.fps_cap, and it renders at its own preset, Low unless you raise it; Game settings follows your graphics settings instead. Test runs use the game's graphics settings and frame cap. The camera and outline settings stay in the Camera window.

Performance

SettingDefaultValuesVariableDescription
Frame cap120 Hz30 to 120 Hzeditor.fps_capFrame cap while editing; the editor never runs above this or above video.fps_cap
QualityLowGame settings, Low, Medium, Higheditor.qualityRender preset while editing; Game settings follows the graphics settings

Layout helpers

SettingDefaultValuesVariableDescription
Line width2 px0.5 to 6 pxeditor.guide_widthThickness of the layout helper lines
Distance labelsOnOff, Oneditor.guide_labelsDraw distance labels on rulers, measurements and selection dimensions

Saving

SettingDefaultValuesVariableDescription
Bake on saveOffOff, Oneditor.bake_on_saveBake the map in the background every time it is saved in the map editor

Test runs

SettingDefaultValuesVariableDescription
Real-time lightingOnOff, Oneditor.test_lightingLight test runs with the editor's live lighting when the map's bake is out of date

Library

SettingDefaultValuesVariableDescription
Import threads00 to 64editor.library_threadsThreads library imports share; 0 picks from the CPU count
Jobs at once21 to 8editor.library_jobsLibrary jobs that can run side by side

Git

SettingDefaultValuesVariableDescription
Map repositoriesOffOff, Oneditor.gitUse git for map repositories; the editor only looks for git once this is on and the editor is open
Git programemptyeditor.git_pathPath to the git program; empty finds it on its own
Check for updatesOnOff, Oneditor.repos_auto_fetchCheck map repositories for changes from others every few minutes

Selecting and editing

  • Left click selects. Shift adds, Ctrl toggles. Drag on empty space to box select.
  • Clicking a piece of a group selects the whole group, and so does box select. Hold Alt to pick the single piece instead. Double-click steps one level into the group, so the next click takes the sub-group or piece under the cursor; Esc steps back out a level at a time. Shift and Ctrl add and toggle whole groups the same way they do single items.
  • Ctrl+G groups the selection and Ctrl+Shift+G ungroups it. Grouping groups nests them. Ungrouping a single piece picked with Alt moves it out one level. A group with nothing left in it is removed. Groups are saved with the map, survive copy, paste and duplicate, and a selected group draws a thin box around everything in it. Track items cannot be grouped. A group can carry a colour label and be marked Noclip, which every block inside it inherits.
  • G moves, R rotates, T scales. Shift+R turns the selection 90 degrees at a time. Tab switches between move, rotate and scale, and on to door posing when one door is selected.
  • The white box at the middle of the gizmo is a handle too. In move it drags the selection freely across the view, snapping to the grid. In scale it scales the whole selection uniformly about its centre: drag right or up to grow, left or down to shrink, and the wheel nudges a unit per notch. The arrows and cube handles still move or scale along one axis at a time.
  • With one block selected, click it a second time to pick a side. The scale gizmo then shows a single handle on that side, following the block's yaw and tilt; drag it to push or pull that face alone with the opposite face fixed. Set Editing back to All in the inspector, or click empty space, to get the axis handles back.
  • The rotate gizmo draws three rings, one per axis. Drag a ring to turn the selection about the centre it is drawn at; with snap on it steps 15 degrees at a time, and the wheel nudges the drag a degree per notch. A ring is drawn grey and cannot be grabbed when the selection has nothing to turn about that axis: a spawn or a sign only turns about the vertical, and a bomb site or a point light does not turn at all. Several items turn together about the middle of the selection.
  • H hides the selection, Shift+H shows everything. View > Layers hides whole kinds of thing at once (clip, glass, water, ladders, doors, fences, spawns, sites, pads, signs, dummies, lights, script zones); Alt+1 to Alt+9 toggle the first nine layers and the status bar shows how many are hidden. Window > Layers lists every layer with its count: the eye hides or shows it, Solo hides every other layer (again shows them all), Select selects everything in it (Shift adds), and the foot shows how many items are hidden with H and unhides them. Layers are a view filter and are not saved with the map; variants are the map's own and are.
  • Ctrl+C, Ctrl+V and Ctrl+D copy, paste and duplicate.
  • Delete or Backspace removes the selection.
  • [ and ] change the grid size. Snap in the top bar turns grid snapping on and off.
  • Ctrl+Z undoes. Ctrl+Y or Ctrl+Shift+Z redoes. Window > History (or Edit > History…) lists every step since the map was opened, newest at the bottom: the current step is highlighted, undone steps are greyed out and the saved one is marked. Click a step to go back or forward to it; a new edit while rewound drops the greyed steps.
  • Ctrl+K or Ctrl+Enter opens the quick switcher: type part of a window's name and press Enter to open it. With nothing typed, the windows you opened most recently come first. Start with ! to search the File and Edit actions instead: !bake bakes, !run starts a test run, !save saves. Start with / to list the commands: /model (or /m) searches the models and /block (or /b) the Blocks panel, and Enter places the pick in front of the camera, resting on the floor below where you are looking and selected. Tab completes a command's name.

Every block, model, light, script zone, smoke generator, explosion, sign, jump pad and teleporter has a Name and a Tags field. Tags are key=value pairs on one line, separated by spaces, and a bare word is a tag with no value: prop=1 room=gallery solo. Automation's By name and By tag sources and server scripts read them. Window > Search finds them, with tag: for the field and is:tagged for anything carrying one.

The inspector edits the selection: position, size, rotation, name, tags, label, shape, colour and glow, and whether a block is a ladder, water, glass, see-through, a door or noclip. A noclip block is drawn like any other but players and shots pass straight through it; a clip block is the opposite, a wall nobody sees. A full clip stops everything; a player clip stops bodies alone, and shots, grenades and arrows carry on through it. Every block, marker and group takes a colour label from the Label row or the right-click menu; labels mean nothing to the game and are there to find things by in the Objects window and in Search (label:red). The Ballistics row gives the block a ballistic profile, which decides whether it breaks, lets rounds through and passes blasts; its list ends with the built-in templates the map does not carry yet, and picking one adds it. Glass makes a block see-through, with a pane look, opacity and a grid or clear texture; picking a pane look also assigns the profile that goes with it. Glow makes a block's colour emit light, and a glowing block also lights the room around it: Glow light sets how strongly (0 keeps the glow but casts no light), Reach how far (0 picks a reach from the block's size), Glow behaviour picks Static or Dynamic, and Animation, shown only on a Dynamic glow, makes the glow and its light pulse, flicker, strobe or burn like a candle. The Material section picks a material for the whole block or for one side: click a face to choose the side. The material button opens a picker with thumbnails and a filter; with no filter the materials you picked most recently in this map come first, then the most used. Below it, Mapping, Repeat every, Shift, Rotate and Colour are per-face overrides of the material's own settings: a row that still follows the material is dimmed, and the ↺ button beside an overridden row puts it back. Changing one of them overrides that face alone, so editing the material still reaches every face that never disagreed. With several blocks selected the inspector shows the rotation and the settings they all share; a setting whose value differs between them is marked mixed, and changing it sets it on every selected block as one undo step. Every inspector section (Transform, Look, Surface, Material, a light's Aim or Animation, and so on) has copy and paste buttons on its header: copy takes that section's settings, and paste applies them to the current selection as one undo step. Paste only lights up on the same kind of section, and a material pasted into another map is left out.

Window > Objects shows everything in the map as a tree, in the order you arrange it, each row with its kind icon, colour label and name; rows that were never moved list groups first, sorted by name, then the loose objects. The arrow opens a group and the count is how many objects it holds; a group is tinted when only part of it is selected. Badges on a row say that it is noclip, hidden, or what a variant does to it. Click selects a group or an object, Shift adds, Ctrl toggles, double-click jumps the camera to it. Drag a row above or below another row to put it there, onto the middle of a group to move it in, or onto the strip at the bottom for the top level. The order is saved with the map, new and pasted objects go to the end of their group, and a new group takes the place of what was grouped. Holding over a closed group opens it, dragging near the top or bottom edge scrolls, and dragging a selected row moves the whole selection. While a filter is on, a row can only be dropped into a group or onto the top level. The filter box takes the same words as Search (is:glass name:door label:red), and the three menus under it narrow the tree to a kind, to what one variant changes, or to a label; while a filter is on, only matching objects and the groups above them are listed. The right-click menu renames, labels, groups, ungroups, sets Noclip on a group, and carries the Variants menu. When exactly one whole group is selected the inspector gains a Group section with its name, label and Noclip. A template dropped into the map arrives as one group named after it, and a template saved from groups keeps them.

Window > Search finds anything in the map. Pick All, Blocks, Lights or Markers (or Track in the track editor), then type: words match the type, name, detail, material, tags and id, type: name: shape: tex: tag: bal: and variant: filter one column (type:light name:door tex:brick, tag:prop, bal:drywall, variant:night; the word explosive finds what explodes), is: filters by fact (is:light, is:hidden, is:selected, is:clip, is:pclip, is:noclip, is:glass, is:breakable, is:wallbang, is:door, is:textured (has a material), is:off, is:script, is:tagged, is:variant, is:labeled and more), label: filters by colour label, - excludes and quotes make a phrase. Click a row to select it, Shift click to add, double-click to jump the camera to it; Select selects every match, which helps with blocks buried inside other blocks. Columns sort when clicked.

Placing

The left panel has blocks, markers and colours. Click an entry, then click in the world to place it, or drag it straight out of the panel. Shift click keeps placing. Esc or right click puts the tool down.

The Models window (Shift+B) places models the same way. Type in its search box to find a model by name, folder or tag. The filter button beside it narrows the list to one folder, collection, tag or source, or to the models already in the map or not yet in it; a number on the button counts the filters in use, and Reset clears them.

Whatever you place lands against the face under the cursor: on a floor, under a ceiling, flat against a wall. The grid snaps it across that face, never into or out of it, so the touching side stays flush at any grid size. Sloped faces rest it on the nearest axis instead of tilting it.

  • Blocks: box, floor, wall, platform, pillar, wedge, ramps at 15, 30 and 45 degrees, a 60 degree surf ramp, stairs, ladder, water, glass panes and other breakables and wall-bangable walls, pipes, sandbags, a jersey barrier and an awning.
  • A block turns on all three axes, so walls can lean and beams can brace. A block left upright collides exactly as it always has; a tilted one is collided as the shape it now is, which costs a little more, so tilt what the map wants seen rather than whole floors. Two things do not follow a tilt: a ladder past about 17 degrees off vertical cannot be grabbed, and a tilted staircase changes the height of each step, so keep those upright.
  • Doors: swinging, sliding and garage doors, and a double door. See Doors.
  • Fences & grates: chain-link, bars, a railing, lattice, a picket fence and a grate floor. They are see-through and stop players; the chain-link lets shots through, and the inspector's Shots toggle sets that per fence.
  • Markers: player start, deathmatch spawn, red and blue team spawns, red and blue flag stands, bomb site, sign, projector, dummy, dummy rail, script zone, smoke generator and explosion. A script zone is a named box that means nothing on its own: what it is for is whatever a server script reading the map decides. See Scripting.
  • A smoke generator puffs a stream of smoke from where it stands, aimed the way it was dropped against a face (turn it with the rotate gizmo, or type its yaw and pitch). The inspector sets its colour, the size a puff is born at and how many times bigger it grows, how many puffs a second, how fast they rise, how wide they spread, their opacity and how long each lives. It can start off, and the map's automation or a server script switches it and retunes it (see Automation and Scripting). The smoke is a look only: it stops no shots and hides nobody from the bots. A map carries up to 48.
  • An explosion is a spot the map's automation or a script sets off. Size is a grenade's fireball at 1, and Damage is 0 for a show and 1 for a grenade's blast, hurting players and breaking surfaces in reach and credited to whoever tripped it. The rest of the inspector shapes the look: fire and smoke colours, how long the fire and smoke last, a second fireball, sparks, chunks, the ring across the ground, the scorch left behind and the flash's reach, brightness and duration.
  • Lighting: point light, spot light, area light, laser, a glowing light panel and a neon strip. A light has a colour, an intensity and a reach, measured from the light's surface. Falloff shapes the pool of light: 0 fills evenly out to the reach, 1 is a tight hotspot. Source size softens the light up close and widens its highlights, Spread wraps light around surfaces until it splashes all round, and Highlights sets how strongly it shows on glossy floors. A spot light has a direction (point it with the rotate gizmo, or type its yaw and pitch) and an inner and outer cone; an area light is a rectangle lit on one side, with a direction, width and height. A spot or area light dropped in the world starts aimed away from the face it lands on. Behaviour is Static or Dynamic: a static light is baked into the map's lighting and costs almost nothing to draw, while a Dynamic light is drawn live and is the only kind that can animate or be switched, tinted or hidden by automation and scripts. Automation that changes a static light is flagged with a warning. Keep lights static unless they have to change. Animation, shown only on a Dynamic light, pulses, flickers or strobes a light, makes it burn like a candle, or walks its colour round the wheel as a rainbow, with a speed, an amount and an offset so neighbouring lights fall out of step. Shadows is Off, Baked (walls and blocks stop the light, from the lighting bake) or Realtime (sharp shadows that players and doors cast too, where the Light shadows setting allows, falling back to baked). Lights can be switched off in the inspector. A laser is a beam rather than a pool: point it with the rotate gizmo, and set its Length, Thickness and how strongly it lights smoke. It stops at the first thing it meets, so a door closing across it cuts it short, and it lights whatever it passes rather than casting a baked shadow. In Scale mode the gizmo handles set a light's reach, an area light's width and height, or a laser's length.
  • Templates: ramp and landing, stair tower, bhop gates, doorway, garage, catwalk, crate stack, I-beam and lamp post.
  • A sign is a holographic text panel. Its text is uppercase, | breaks a line, and the inspector sets the glyph height and colour. Shift+R turns it by 90 degrees.
  • A projector shows text or one of the map's images. Shows picks which: text is typed in the inspector, a new line breaks it, and Font picks one of six faces (sans, sans bold, condensed, mono, display and terminal); an image is any texture in the map's Assets window. Projects is Floating screen, a panel hanging in the air at Distance with a Screen width (or a Letter height, for text, that sizes the panel to the words), or Onto surfaces, which throws the picture across whatever the beam hits out to Distance, spread over Spread degrees, wrapping over corners and props and stopping at the first wall. Aspect 0 keeps the content's own shape. It is aimed the way it was dropped against a face (turn it with the rotate gizmo, or type its yaw and pitch); one dropped on a ceiling hangs from a ceiling mount. Body is how the projector itself looks, or Hidden. Colour tints the picture, Brightness sets how strongly it shows, Backdrop puts a tinted panel behind text, Beam sets how much the cone of light from the lens stands out and Beam softness how soft its edges are, and Flicker, Scanlines and Jitter add hologram noise. Casts light turns the beam into a Dynamic spot light, with Realtime shadows if asked. It can start hidden, and the map's automation or a server script shows and hides it. In Scale mode the gizmo sets its distance and screen width. A map shows up to 64.
  • A dummy is a target. Killable dummies take damage. A dummy rail moves a dummy along a path.
  • Capture the flag needs one red and one blue flag stand. Bomb needs at least one bomb site. Bomb sites are boxes: scale them with the gizmo, and Shift+R swaps their width and depth. New bomb sites are named A, B, and so on.

Environment and lighting

Window > Script says what the map offers a server script: the modes it can be played as, separated by spaces, and the map's own tags. Underneath it counts what a script has to work with -- script zones, disguise props, named lights, doors, smoke generators and explosions -- worked out the same way the bake does, so what the window says is what the server will see. See What a map offers a script.

Window > Environment sets the sky and fog: a day sky with a sun direction (Sun from camera points it where you are looking), sun and horizon colours, zenith brightness and fog density, or a starry night with stars, twinkle, Milky Way, moon and shooting stars. The Fog section adds a start distance, a cap and height fog. Window > Lighting has presets (Day, Dusk, Night, Indoor) and sliders for brightness, sun, ambient, ground, shadow strength, glow and local lights (every placed light at once), tint colours, and how bright actors and the viewmodel are. Post sets exposure, bloom and the brightness bloom starts at. Edits show live and a slider drag, here or in the inspector, undoes as one step. The same settings apply from the command line with eds-bake --env <map> <day|night|dusk|indoor|env.json>.

The editor bakes the map's lighting in the background a moment after each change: how much sky each spot sees, so rooms and tunnels go dark while open ground stays lit; where the sun reaches; where walls stop each light; and light bouncing off lit surfaces. The Baked lighting section sets how strongly sky occlusion darkens covered places, how much bounce light there is, a floor of indoor ambient so nothing goes pitch black, the bake's detail in QU and the number of bounces, and shows the bake's progress. A quick preview arrives first and a full bake follows once edits stop; Bake lighting starts the full bake at once, and Auto bake turns the background bake off. Save does not store the lighting; File > Bake… does, finishing the full bake first if it has not run. Up to eight lights that overlap each get their own baked shadows; past that, overlapping lights share them, so walls still stop every light but shadows go softer where they overlap, and the status line says how many lights share.

View > Lighting debug, or the View section at the top of Window > Lighting, turns on light guides (L), which draw each light's reach and hotspot, cones and area outlines; they are off by default. The same menu shows the lighting alone on grey surfaces, the sky occlusion, ground light, bounce light, sun visibility, baked light shadows in red, or the direct light from placed lights on its own.

Variants

A map can carry named alternate versions of itself. A variant is a set of changes layered over the base map -- blocks and markers it adds or takes away, materials it swaps, a sky of its own -- and it ships inside the same map file, so the map keeps one name and one download.

Window > Variants (V) adds, groups and shows them. A variant may sit in a group, of which exactly one member is on at a time, with one marked default: time: day | night is a group, and a lone variant with no group is a toggle that is on or off on its own. A map holds at most 32 variants.

Showing a variant is editing it. The eye on a row shows it -- the viewport then draws the map exactly as the game would under that selection -- and everything placed or pasted from then on belongs to it, the Environment, Lighting and Materials windows edit that variant's own, and everything already in it is outlined. Shift+V cycles the first group, Alt+Shift+1 to Alt+Shift+9 toggle one, and Base goes back to the plain map, which is what to show to build the geometry every variant shares. Default shows what the map loads with, editing the base. Ghost draws what the selection leaves out as flat wireframes, which stay clickable. The status bar says what is being edited.

The pencil on a row opens that variant's settings in their own window: its name -- the id a server, a rotation entry and a track address it by -- its label, its group, the game modes that turn it on, whether it carries its own environment, which automation pages it runs, and the arrows that reorder it and the button that deletes it, both of which renumber the map's variants in one undo step. Select there selects everything the variant adds or hides. The pencil on a group opens the group's own settings.

File > Bake… lights every combination of variants the map can be played under. The default combination is stored whole and every other one only where its lighting differs, so a variant that changes one room costs about one room of lighting, and switching variants mid-session swaps only those parts. A variant with its own environment changes the light everywhere and costs a whole bake. Past 64 combinations free toggles stop being lit separately and share the lighting of the nearest lit combination; the Problems list warns when a map gets there.

The inspector says which variants a piece stands in: the base map, which every piece starts as, a variant it is hidden in, or a variant it exists in alone, changed from a base piece. The right-click Variants menu, in the world or on an Objects row, edits that for the whole selection: Present in and Hidden in tick the variants directly, and Hidden in is what makes a variant a delta, taking a base piece out without the base having to name every variant that keeps it. Editing a base piece while a variant is shown leaves the base alone and puts a changed copy in the variant. Changes in a variant then offers, for the selection: Move to another variant, Reset to base, which drops the change and shows the base piece again, Apply to base, which makes the base piece the changed one, and Take from base, which copies the base piece back over the changed one. Objects filtered to a variant lists everything it touches, with + for a piece only it has, ~ for one it changed and - for one it hides; the +n and -n chips in the Variants window open that list.

Which variants a session runs is the server's to decide, not the player's. The map's defaults come first, then whatever the mode being played binds, then game.variants; a track being raced overrules all three. A rotation entry may name them too, as map:mode:variant,variant.

Doors

A door is a block that moves. Turn a block into one with the inspector's Door toggle; the cog beside it opens the rest of its settings. Or place one from the Doors category. A glass pane can be a door too: it swings or slides like any other and still breaks by its glass rules. Doors swing on a hinge (left or right edge), slide along one of their own axes, or tilt up like a garage door. A door opens when a player walks up to it or, with Opens on set to the use key, when they press E within reach; it waits the given seconds and closes, or stays open with a wait of -1. With Opens on set to automation it ignores players entirely and only an Automation Door node moves it. Locked doors never open. Rests: open makes the open pose the resting one. Opening, closing, starting and stopping to slide can each play one of the map's sounds; one left empty falls back to another of the door's, then to the built-in sound.

The open pose is drawn as a blue ghost with an orange hinge line. K (or Tab past scale) enters pose mode: drag the ghost along an axis to make the door slide that way by that far, R turns a sliding door into a swinging one or reverses a swing, and Shift+R moves the hinge to the other edge. Two door leaves that touch open together as one doorway; keep unrelated doors more than a couple of units apart.

Automation

Window > Automation is a node graph that runs inside the map: it hears what happens on the map and answers by switching lights, tinting them, dropping collision, taking blocks away, breaking glass, driving doors, switching and retuning smoke generators, switching and playing sound emitters, setting off explosions and sending signals. It runs in the simulation on the server and on every client, so what it does is predicted, replicated and recorded in replays like anything else that moves.

A node has pins on its left (inputs) and right (outputs). Square pins carry exec: an impulse that runs whatever is wired to it, left to right. Round pins carry a value: a number, an integer, a yes/no, a colour or a player. Orange diamond pins carry objects: a set of things on the map. Right-click the canvas or press Add to place a node, drag from a pin to a pin to wire them, drag a node to move it, drag on empty canvas to select several, and scroll to zoom. Delete removes the selection, Ctrl+D duplicates it and F frames the graph. Right-click a pin to disconnect it. A node's settings sit on the node: pick from its list, tick its box, and double-click a number or a name to type one.

  • Events start a run: On start, Every N ticks, On break and On surface damaged (any surface whose ballistic profile breaks; On break gives the cause as a number, 0 bullet, 1 blast, 2 grenade contact, 3 body, 4 underfoot, 5 its group, 6 automation, 7 script, and On surface damaged gives the health left from 0 to 1), On zone (script zones from the Markers palette; it has an Enter and an Exit pin, so one node covers both ways), On shot and On use (a block, a model or a group acting as a button; use is E within reach), On signal, On round (round start, round end, round reset or match end), the bomb events, and On spawn and On death. Most carry the player who caused them and their team, and a team filter narrows them to red or blue. On bomb planted and On bomb exploded carry the bombsite and can be narrowed to one site by name, and On break can be narrowed to one cause. The events that watch something -- On break, On surface damaged, On shot, On use and On zone -- also carry the object that set them off, on an Object pin.
  • The rest of the game modes have events of their own, and fire only while that mode is being played. On run follows a track run and picks one of armed, start, checkpoint, finish, reset and lap: it gives the runner, an Index and a Time in seconds, which on a checkpoint are its number from 0 and the split, on a finish the number of checkpoints and the run, on a reset the checkpoint the runner went back to, or -1 from the start line, and on a lap the lap now started and the split. It is the one event that works in a time trial on your own, where there is no match at all. On horse picks one of turn start, mark laid, mark reached, turn lost and round over: it gives the setter, except on mark reached where it gives the chaser who got there, with a Count of how many have made it. On flag picks one of taken, dropped, returned and captured, and gives the player, their team and a Flag of 1 for red and 2 for blue, and can be narrowed to one flag; a returned flag names no player, since the map cannot tell a player from the return timer. On tagged gives the new it and who they took it from, and On gun advanced the player and the rung they reached. On gun advanced runs on the server alone, so what it changes arrives with the next update instead of being predicted.
  • Flow routes a run: Sequence, Branch, Delay, Timer, Gate, Once, Toggle and Counter. A delay or a timer counts in simulation ticks, so it lands on the same tick for everyone.
  • Data nodes are read when something asks for them: constants (including Team, Bombsite and Break cause, which give the same values as an event's Team, Site and Cause pins, to compare against), compare, and/or/not, maths, remap, clamp, select, colour mix, ramp and scale, and readings from the match such as Match clock (round elapsed, round left or bomb left), Match phase, Mode is (true when that game mode is being played, so one graph can carry several), Run time (how long a player has been on their run, 0 when they are not), Players in zone, Team of, Is alive, Light is on, Smoke is on, Sound is on, Door is open, Door is locked, Is broken and Surface health (the lowest health among its targets, 0 to 1). Remap turns its own range off with Clamp, which also lets it carry past the ends. Colour is set from a swatch that opens a colour wheel, or by typing a hex value. A player pin left unwired means the player the run started from.
  • Actions change the map: Set light, Set visibility, Set collision, Set surface, Set door open, Set door locked, Set smoke, Set sound, Play sound, Tint light, Tune smoke, Explode, Damage surface and Emit signal. The eight that drive a state take a Mode of On, Off, Toggle or Value, and Value reads the yes/no wired into the Value pin. On means lit, the block there, the block solid, the surface broken, the door open, the door locked, the smoke generator puffing and the sound emitter playing; Set door open also takes Auto, which hands the door back to the game. Set visibility takes a block, a model, a sign, a projector, a jump pad or a teleporter away altogether: it is not drawn, nothing collides with it, and a hidden jump pad or teleporter does nothing. Set collision only makes a block or a model passable and leaves it drawn. Neither acts on doors. Tint light clears its tint with Mode set to Clear. Tune smoke changes a generator's colour, rate, puff size and opacity to whatever is wired into those pins and leaves the rest alone; Clear puts the look back the way the map authored it. Explode sets off the explosions on its Target pin, with its Scale and Damage pins standing in for theirs when wired; the player who started the run is credited for what the blast kills. Play sound plays a sound emitter's sound once, whatever it is set to do on its own. Smoke generators, sound emitters and projectors the graph drives go back to how the map authored them when the round resets.
  • Sources give objects: Picked objects, By type (which also offers Breakable, Wall-bangable, Smoke, Explosion, Sound, Model, Sign, Jump pad, Teleporter and Projector), By material, By ballistic profile, By group, Group of, By name and By tag.

A node that acts on the map has a Target pin on its left. Wire a source into it; several wires add up. Picked objects holds things you choose: press Pick on the node to take the world selection, or with nothing selected click things in the world or on Objects rows. A click on something already picked removes it, Alt picks one piece of a group, and Esc ends picking. The button beside Pick names what is picked and opens it, to select one in the world or drop it. Right-click a Target pin for Add picked objects. A picked object brings its copies in other variants with it. The By sources match the whole map, or only what is wired into their From pin, so chaining them narrows a set. A target keeps only what fits its node: Set light fed a whole group takes the group's lights. Sources are worked out when the map is baked.

An event's Object pin is how a run reaches back to the thing it happened to. Group of takes objects and gives the group they sit in, so On break -> Object -> Group of -> By type set to Light -> Set light turns off the lights in the broken pane's own group, written once for every pane on the map. Group of gives nothing for an object in no group, and nothing at all when its From pin is unwired, unlike the By sources. Level picks where to start, Innermost at the group the object is directly in or Topmost at the outermost one, and Steps walks from there: Innermost with 2 steps is two groups above the one the object sits in, Topmost with 1 step is the one just inside the outermost. A walk that runs off either end stops at the last group it reached.

A node fed that way is baked once per object the event watches, and so is everything between the event and that node. A Delay, Once, Gate or Counter in that stretch gets a copy per object, so Once means once per pane rather than once for the map -- to count across all of them, send an Emit signal and do the counting off an On signal. Feeding one target from two different events' Object pins is listed in Problems, as is a graph that copies out to more nodes than a map bakes; either way that event falls back to giving everything it watches.

Everything the graph changes goes back to how the map was built when the round resets. Lights the graph touches are put on the wire like named lights, and a map may carry at most 64 of those.

Pages split the graph into tabs. + adds one, double-click renames, and right-click duplicates, moves or deletes. Wires do not cross pages; signals do. A variant switches pages off from its settings, which stops every node on them; a tab struck through is one the variants being shown switch off.

Signals are names of your own. Emit signal sends one, On signal hears one, and both reach past the map: a server script hears every signal as a signal event and sends one back with map.signal(name, arg), and the signal console command sends one from the console, on a local game directly and on a server through rcon. automation list prints the graph's nodes and signals and automation state what is armed right now. A wire that points at something gone, a target with nothing wired or nothing that fits, or a loop with no delay in it is listed in Problems. So is a node that can never run because nothing that fires is wired into its In pin, an event with nothing wired to its Out pin, a Gate that starts closed and that nothing opens, and a node whose outputs lead nowhere. Only events and a Timer set to start on its own set a chain running.

Ballistic profiles

A ballistic profile says how a surface answers guns, explosions and bodies. A map carries its own list, separate from its materials, and a block or a placed model points at one from the Ballistics row of the inspector. The row is a list of the map's profiles with a button that opens the chosen one for editing, and under it a line works out what the profile means for that block at its real thickness: how many rifle rounds break it, how much of a rifle round crosses it, and how much blast passes. The right-click menu of a block or a model carries the same list under Ballistics. An object with no profile stops every round and every blast and never breaks.

  • Breaking: Health is how much damage breaks it and Hits is how many hits do, whichever comes first; with both at 0 shots never break it. Body break speed is how fast a player has to run into it, and Underfoot makes it give way to someone standing on it. Bullet damage taken and Blast damage taken scale what each does to its health, so a metal door at 0% bullets and 100% blasts only goes to explosives, and Grenade contact damage is what a thrown grenade or a rocket does by hitting it.
  • Penetration: a surface that lets rounds through takes Damage lost on entry off the round, then Resistance for every unit of material it crosses, divided by the weapon's caliber, so a rifle loses less than a pistol in the same wall and a thick wall costs more than a thin one. Thickest it lets through stops the round outright past that depth. Walls with the same profile standing against each other count as one. Nothing is lost in open air, and a round that loses more than 95% stops. A round crosses at most four surfaces.
  • Explosions: Blast let through is how much blast damage passes, and Blast reach behind it shortens how far the blast carries on the far side. A surface shields from the blast that breaks it. Explodes when broken turns it into a barrel: 1 is a hand grenade, the Fuse delays it, and the blast sets off other barrels in reach.
  • Sounds plays the map's own sounds on the surface: footsteps, landings, jumps, bullet hits, breaking and a round coming out the far side. Built-in footsteps picks which of the game's own footsteps, jumps and landings it has when those are left empty: Concrete, Metal, Wood, or From the debris, where wood, cloth and drywall debris sound like wood and metal like metal.
  • Debris picks how it breaks and sounds, and Grouping makes every object in the same group with the same profile break together when one of them does. A block made of several pieces always breaks as one, and a model and a block in the same group with the same linked profile break together too.

Map > Ballistic profiles lists them as cards with three gauges (toughness, how much of a rifle round crosses 8 units of it, and how much blast passes), badges, and how many objects use each; an unused one is dimmed. Assign to selection puts the selected profile on every selected block and model as one undo step, Select users selects what uses it, Show on map outlines every object in its profile's colour, and hovering a card outlines its users. Deleting a profile in use asks first and clears it from those objects. The Ballistics row of the inspector lists only the map's own profiles; templates live in this window.

Edit, or double-clicking a card, opens the profile in its own window, which follows whichever card is selected. The top holds the name, the gauges and a Template list that resets the profile to one of the built-in templates; changing any setting afterwards turns it back into a custom profile. Settings holds the groups above. Weapons works out, from the game's own weapons and the thickness slider, what each weapon's body shot does after crossing it, which weapons it stops, and how many shots and seconds each takes to break it. Explosions does the same for a grenade, a launcher round and a rocket. Paint onto objects, in either window, turns the cursor into a brush: click a block or a model to give it the profile, Shift click to clear it, and the selection is left alone.

Import and Export all in the library, and Export on a card, read and write .ebal files, which hold one or more profiles as text. Importing skips profiles the map already has and gives the rest free names, as one undo step.

Create opens a wizard: pick what it is on the left (breakable glass, a breakable surface, a wall-bangable wall, an explosive barrel, a blast shield, or custom) and one of that kind's template cards on the right, each with its own gauges, tune the few settings that matter for that kind with the Weapons and Explosions tabs beside them, then name it and optionally assign it to the selection. The new profile opens in its editing window. The Breakables category of the palette holds ready-made panes, boards, panels, a crate, a metal door, a grate, a barrel, drywall, sheet metal, brick and cloth; placing one adds its profile to the map in the same undo step.

Maps from before ballistic profiles open with each glass pane on the profile of its old preset, and panes whose settings had been changed share a custom profile; the library says how many panes it converted until the map is saved and reopened. Reinforced glass now takes 60 damage and armoured glass 400 and stops rounds until then. Problems flags a block thicker than its profile lets through, a linked profile on a block in no group, an explosive profile nothing can break, underfoot on a wall, and unused or duplicate profiles. A map holds up to 512 profiles.

Ballistics tools

Test > Ballistics tools measures a map with the same code the game runs, against the map as it stands in the editor.

  • Shot probe draws a line from the camera through the crosshair. Each surface it crosses is marked with a white stretch through the material and a box where it goes in and comes out, the line warms as the round loses damage, and a red cross marks where it stops. The list names every surface crossed with its thickness and what is left after it, and the table below gives every hitscan weapon's body and head damage at the far end and how many surfaces it got through. Pin here freezes the line so you can fly around it.
  • Blast probe drops an orb at the cursor, or in front of the camera when the cursor is on nothing. It draws the kill and reach radius, a fan of rays coloured by the damage that arrives after whatever they cross, a red box on every surface the blast would break and an amber one on those it only damages, with the list giving the damage each takes. Stand a dummy here puts a player-sized box at the cursor and reports what it would take. The explosion can be a grenade, a launcher round, a rocket or a double charge. Rings on the floor under the orb are coloured the same way by the damage reaching that spot, and the Nudge buttons move the orb 16 units along an axis.
  • Wall-bang coverage outlines every block that has a profile by how much of the chosen weapon's damage crosses its thinnest side: green over 80%, yellow over 40%, orange under that and red when it stops the round.

In Test > Runs, Shots and blasts shows what a test run fired: each shot as a line that warms after a surface and turns white inside it, a ring for each explosion at its full reach, and a box where a surface broke. The from and to sliders beside it narrow that to a stretch of the run.

Materials, textures and paint

A material is what a surface is made of. It names an image and carries everything else about the look: how the image lays out (Tile repeats it across the surface, Stretch fits one copy to each face like a poster, with a repeat size, shift and rotation), a colour it is multiplied by and whether the block's own colour tints it, Reflectivity and Gloss, a glow and its colour, extra maps (normal, occlusion/roughness/metal, glow, detail), filtering (clamped or repeating edges, mip maps, and Smooth, Sharp or Pixels), and a surface type (Solid, Cut-out, Transparent, Decal or Glow) with two-sidedness. Reflectivity and Gloss are the friendly face of the raw metallic and roughness values, which the PBR section still shows; reflections themselves need Reflections set to High in the video settings, and below that a reflective material looks matte.

Window > Materials lists the materials the map carries. Pick one to edit it on the right, rename it, duplicate it, or delete it (a material in use asks first, and deleting it puts those faces back on the checker). Assign to side and Assign to block put it on the selection, and Brush turns it into a tool: click a face to paint it, Ctrl click for the whole block, Shift click to clear. Every material edit is one undo step, and a slider drag is one step rather than one per frame.

Create opens a wizard that makes a material from nothing, from a texture or from the built-in set. Blank gives an untextured material to point at a texture later. From a texture offers this map's textures and every texture-pack texture; a pack PBR set wires the whole set up, with the normal and glow maps in their slots and separate occlusion, roughness and metalness images fused into the single ORM image the renderer reads. Built-in is what the editor generates itself, so a fresh map has something to build with before importing anything: three grid densities in each of the seventeen block colours, a dark grid, the five fence cut-outs, a grid that follows the block's own colour, and a plain white -- a whole colour set shares one image, so a map greyboxed entirely in tinted grids still carries a single texture. The last step names the new material.

Export… writes the selected material to an .emat file holding its settings and a copy of every image it uses, so the file carries the whole material and needs nothing else where it lands. Import… reads one back into the map, reusing an image the map already has rather than adding a second copy. Both dialogs start in your materials folder.

Window > Textures is the layer underneath: the images themselves. The pills pick where to look -- This map, the texture folder on disk, All packs, or one pack. A map texture can be renamed, exported, duplicated or deleted, and New material… takes it into the wizard; a pack texture is added to the map with Add to map, or taken into the wizard the same way. Import… brings in a PNG or JPEG with a file dialog, the path box at the bottom takes a typed path, and the folder pill lists what is sitting in the texture folder (Reveal folder opens it, Rescan lists it again).

A texture pack is a .zip of PNG or JPEG images: each folder becomes a category (images at the top are filed under General), and each file name becomes the texture's name, so Metal/rusty_plate_2k_basecolor.png shows as "Rusty plate" under Metal. Resolution tags like 2k and albedo tags like _basecolor, _albedo, _diffuse or _color are dropped from the name, and the other maps of a PBR set (_normal, _roughness, _ao, _orm, _height and so on) join their colour map rather than standing on their own, which the tile badges pbr. A pack.ron at the root of the zip can name textures and set their categories instead. The built-in packs are always there: Default (brick, stone, concrete, plaster, wood, metal, tile, interior, roof and ground) and Prototype (grid and blockout textures in six colours); Add pack… copies zips into your packs folder (Reveal folder opens it), and Rescan picks up zips dropped in by hand. More packs are on the Steam Workshop, and a pack of your own can go there too: see Steam Workshop. The map refers to pack textures by pack and name and copies the current pack image in when it is saved or test run, so a saved map still carries every texture it uses, even if the pack is later removed; duplicating a pack texture makes an ordinary copy.

Textures are capped at 4096 pixels a side, 32 MiB a file, 256 per map and 512 MiB in total, travel with the map, and are fetched with it by other players. Texture detail in the video settings also applies to them: Medium and Low load them at half and quarter size. Maps made before materials existed open with one material per texture, named after it, and look exactly as they did.

Window > Paint (or P) colours the cells of a face while keeping the checker look: pick a colour, a cell size of 8, 16 or 32 units and a brush (cell, fill or rectangle), then drag over a face. Hold Alt or turn on Erase to clear cells. Clear side and Clear block wipe the paint off the selection. Painted cells replace the block's colour in that cell and keep the checker lines.

Library

The Library is where models, materials, templates and sounds live between maps. It is the Library tab next to Edit, Tracks and Debug, the Asset library card on the Start window, or Ctrl+L, which opens it on whatever is selected in the map. Show in Library on a block's or model's right-click menu and Edit in Library in the Materials, Models and Assets windows do the same for one asset. The map stays loaded the whole time; Esc or Ctrl+L goes back to it.

The left column picks what to look at: Everything, My library, one kind, a collection, a folder, a tag, or an installed source. The middle is the assets themselves, with a search box that also takes kind:, tag:, folder:, src: and id:, and is:mine, is:installed, is:inmap and is:legacy, a sort and a card size. The right column shows the picked asset: a preview, what you can do with it, its settings, and what it uses and what uses it.

  • Click picks one, Ctrl click adds or drops one, Shift click picks a run, and Ctrl+A picks everything shown. The arrow keys move the pick.
  • The Library does not put anything in the map. Models are placed from the Models window, and materials and sounds are added from the Materials and Assets windows.
  • F2 renames, Ctrl+D duplicates, and Delete on the right-click menu removes it from the Library. Maps that already use it keep their copy.
  • Ctrl+Z and Ctrl+Y undo and redo edits to names, folders, tags, notes and settings.
  • Folders and tags are for your own sorting. Move to on the right-click menu files a pick, and a tag typed in the right column goes on every picked asset.

Import… takes models (glTF, GLB, FBX, OBJ), images (PNG, JPEG, TGA), .emat materials, sounds (WAV, OGG, FLAC, MP3, AIFF) and asset packs, and lists what it found before anything is added. Models take the same scale, up axis, collision and material settings they always have. Images become materials: maps named like brick_albedo, brick_normal and brick_roughness join into one Brick material, with the occlusion, roughness and metal maps fused into the one image the renderer reads. Sounds are turned into Ogg Vorbis at 48 kHz. Each gets a category (effect, impact, footstep, voice, UI, ambience or music), picked in the import or guessed from its name, which only decides the volume slider it follows. A sound can run up to 5 minutes. The import also sets whether it keeps stereo, how it is levelled (left as is, peaked at -1 dB, or to a loudness in LUFS), its quality, and whether silence at the ends is trimmed. Numbered files like step_01 and step_02 become takes of one sound. The import runs in the background; the chip in the bottom corner shows it, and cancels it.

The preview is the asset in a small room lit like the game. Drag to turn it, Shift drag or the middle button to move, the wheel to zoom, and double click to put the camera back. The buttons under it turn it slowly, show the floor, the bounds and a model's collision, light it with the studio light or like the open map, and show a material on shapes, a floor or a wall. Models show their base colour only, as they do in a map; a material's other maps show on the blocks.

What can be edited depends on the kind:

  • A material has every setting the Materials window has, and its maps. Pick an image for a slot or clear it.
  • A model keeps its import settings, and changing one imports it again from the stored file. It also has a footstep surface and, for each of its material slots, a Library material to use in place of the one it came with.
  • A sound has its category, volume, pitch, how much the pitch and volume vary from one play to the next, whether it loops, which volume slider it follows (left alone, the one its category suggests), how far it stays at full volume, how far it carries, how soon it can play again and how many can play at once. The wave shows under it; Play, Random take and Loop try it out, and the takes list plays, reorders and removes takes. Keep stereo, Level and Quality re-encode every take from the original files in the background; sounds imported before the library kept originals re-encode from their compressed copy. Space plays and stops it.
  • A template shows its blocks and markers. Placing one adds the materials and models it uses to the map. A template saved before this carries no materials of its own and uses whatever the map has at the same slots, which the Library says; place it and save it again to fix that.

A map remembers which Library asset each material, model and sound came from. The Materials window marks those, and when the Library copy has changed since, Update brings the map's copy in line. Save to library on a map material or model adds it to the Library. Saving a template from a selection adds anything it uses that the Library does not have yet.

The built-in materials and every texture pack's textures are in the Library too, under Installed, as are the assets of installed asset packs. They are read-only: Duplicate to edit copies one into My library.

Collections

A collection is a set of assets to hand to someone else as one asset pack, such as a kit of materials, models, templates and sounds for one theme. Make one with the plus by Collections, from the right-click menu's Add to collection > New collection, or with the plus while assets are picked, which puts them in it. Add to collection puts the picked assets in an existing one, and Remove takes them out; nothing is deleted from the Library either way.

Open a collection to see its assets and a panel above them with its name, what it holds, and how big it is. The arrow next to the name shows its description, credit, version and tags. The panel warns about:

  • Assets the collection needs but does not list, such as a template's materials or a model's slot materials. They go in the pack anyway; Add them lists them.
  • Assets that came from somebody else's pack. Only pass them on if their licence allows it.
  • Texture-pack materials, which are copied into the pack.
  • Assets that are gone from the Library, which stop it being exported until Take them out removes them.

Export pack… writes the collection to a .zip. Publish… puts it on the Steam Workshop as an asset pack: see Publishing an asset pack. An asset pack added with Import…, or subscribed to on the Workshop, shows under Installed, with its assets read-only.

The Library is the library folder in the custom maps folder. The first time it opens it takes in the old model library, saved .emat materials and templates, and leaves the old folders as they were.

Sounds

A map plays its own sounds in three ways, all from the sounds in its Assets window. They go out with the map like its textures, and a map whose sounds have not arrived yet still loads and plays silent until they do.

  • A sound emitter, from the Markers palette, plays a sound where it stands. Plays is Loops, Every so often (a random wait between At least every and At most every), or When automation says, which plays it only from a Play sound node or a script. At round start says whether it starts playing or waits to be switched on. Heard from here fades it with distance: it is at full volume up to the inner ring and silent past the outer one, which default to the sound's own settings, and walls muffle it. Everywhere plays it at the same volume wherever the listener is, for music and a map-wide bed. Sounds longer than 8 s are streamed rather than held in memory, and stereo ones heard everywhere stay stereo. Automation and scripts switch emitters on and off, and that is replicated and recorded in replays.
  • A surface profile or a door can play the map's sounds in place of the built-in ones: see Ballistic profiles and Doors.
  • Map-wide replacements, at the bottom of the Sound window, swap a built-in sound for one of the map's everywhere it plays: footsteps, jumps and landings on each surface, bullet hits, rounds coming out of a wall, breaking, doors, ladders, water, jump pads and teleporters. A profile's or a door's own sound wins over a replacement. A replaced sound keeps how the game plays the one it replaces, such as how far it carries and which slider it follows.

Problems lists a sound a profile, a door or a replacement names that the map no longer has, one longer than 30 s in one of those roles (it never plays there), and an emitter with no sound.

Test > Sound shows how a sound travels through the map as it stands. Place source and Place listener set where it starts and who hears it; with no listener placed the camera is the listener. Sound picks what kind of sound it is, from a gunshot to a crouched step. At the listener gives what the listener hears: the level, what comes straight through the walls, what goes around corners, the cutoff and the wall loss on the line. Field colours the floors around the source by how loud it is there (Loud), how muffled (Muffle) or how much of it arrives around corners rather than through walls (Around), out to Radius, sampled every Spacing. Rays draws the lines the sound is traced along with each wall's loss, and Probe graph the points it finds its way around corners by; a map without acoustics baked only goes through walls, and Build acoustics works them out. Play live plays the sound at the source and you hear it through the camera; Play at listener plays exactly what the listener hears. Play while editing, under Map sounds, plays the map's emitters while you edit. The Sound window is in the map debugger too.

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.

Layout helpers

Window > Layout helpers holds the tools for lining things up. View > Layout helpers has the same toggles.

  • Measure (N): click two points for the length, the flat length and the difference on each axis, in units and metres. A point lands where the cursor is, pulled onto a block corner or edge when it is near one; hold Ctrl to snap to the grid instead. Pin as ruler keeps the measurement in the world as a ruler with a tick every grid step. Right click or Esc drops the point, then the tool.
  • Grid (Shift+N): pick a cell size and a size in cells, then click a face to drop a grid there. It lies on the face it was dropped on and its lines fall on multiples of its own cell size. Shift keeps the tool for the next one.
  • With Snap to helpers on, moving with the gizmo or placing from the palette pulls the selection's min, centre or max onto a grid's cell lines, a grid's own plane or a ruler end when it comes within most of a grid step, and the helper lights up white. Helpers win over the grid.
  • Each placed helper can be hidden or removed, and a grid's cell size changed, from the Placed list.
  • Selection dimensions draws the selection's size on each axis, and with two pieces selected the gap between them.

Align, distribute and mirror are on the right-click menu under Layout. Align min, centre and max line the selection up on an axis; Distribute gaps and centres space three or more pieces evenly between the outer two; Mirror and Mirror copy flip across the selection's own centre. A whole group moves as one piece and each is one undo step. Doors swap their hinge side and hulls and prisms are flipped; face paint moves with its side but is not itself mirrored.

Grids and rulers are saved with the map's source file and never reach the baked map. They are not part of undo. Helpers saved by an earlier build are dropped when the map is opened. editor.guide_width sets how thick they are drawn and editor.guide_labels turns the distance labels off.

Playtesting

Window > Playtesting reads the recordings made while people played the map and draws what happened, so a map can be read from its play rather than from memory. M toggles the overlay.

Recordings lists what it found: saved matches, race runs and sessions for this map, and anything added with Add files… or Add folder…. Recordings of this map are ticked to start with. A recording made on another version of the map is still worth reading and is kept, marked "other bake"; one made on a different map is left out unless Other maps is on. Process reads the ticked ones in the background, and the bar says how far along it is. Reading is per recording: one that cannot be read is listed with the reason and the rest still load.

A recording made by an older build of the game is read here even though it cannot be watched. Where a player stood is still true across a build, so heatmaps and paths hold; it is marked "recorded by another build". A recording in an older file format cannot be read at all and says so.

View is what the layers are drawn from. Live only counts the rounds and leaves out warmup, which otherwise dominates everything; recordings that never reach a live round say so rather than drawing nothing. Alive only and On ground only drop dead bodies and airborne ticks. Paths draws each player's route, coloured per player and tinted by speed, in the style of the run overlay. Through walls draws every layer with no depth test, so the whole map reads at once. Side keeps one team; Role keeps the attacking or defending side of a bomb round and only appears for recordings that have one. Players picks who counts, and unticking the last one is refused. Every layer obeys the same filter, so the pivot is set once.

Style draws the heats either as a relief surface draped over the floor or as columns standing on it, and Relief sets how tall they get. Heat is collected per column of the map rather than per cell, so a balcony reads apart from the floor under it.

Layers are toggled one at a time, and a layer with nothing in it for this set is not listed:

  • Presence: Occupancy shades the ground by how long players spent on it, Coverage shows only whether anywhere was entered at all, so the parts of the map nobody reaches show as holes, and Speed shades by how fast they were moving there, in QU/s.
  • Movement: Jump heat, and Jump marks and Landings as individual marks. A wall jump is marked apart from a standing one, and a landing is coloured and sized by how hard it was, so the drops that hurt stand out. Traversal marks slides, climbs, ladders, jump pads, teleports, water entries and broken surfaces, one colour per kind, and Spawns marks where people came back.
  • Combat: Shots from and Shots at as separate heats, since where people shoot from and what gets shot are different questions. Fire lanes shades every cell a shot passed through, so the corridors being covered show up rather than only their ends, and Damage shades by how much damage landed where. Sightlines draws every shot from muzzle to impact, Kill vectors draws killer to victim, and Death spots marks each death in the dying player's colour, raised and brighter for a headshot. Wall-bang exits marks where each round came out of a surface, from yellow for a round that kept most of its damage to red for one that kept little, Explosions rings every blast at its reach, and Breaks marks each surface that broke.
  • Objective: Carry heat and Carry routes follow the bomb and the flags. Plants are coloured by what happened to them -- red exploded, green defused, grey unresolved -- and Bomb drops, Flag drops, Flag returns, Captures and Tags mark the rest in team colours. These appear only for recordings that have them.

The legend under the layers reads the first heat layer shown: the colour ramp from nothing to its top value, with the unit.

Charts is the third tab, reading the same filter as the layers. Above them sit the totals: time played, players, how much ground was covered, the median speed, the busiest single spot and the death count, plus the objective tally for a bomb, CTF or tag set. Below, one chart per question: time on the map per player, how fast the map is played, which heights get used, the range fights are won at, and when in a recording people die. A chart with nothing in it is left out, so a set of race runs shows the movement charts and none of the combat ones.

Scale reports the grid, how much is being drawn, how often the recordings were sampled and how much is held in memory. Focus moves the camera to cover everything the filter selects. Clear set drops it all.

Nothing is written to disk: the reading is held in memory for as long as the editor is open, and picking a different set reads again.

Saving and testing

Ctrl+S or Save writes the map to the custom maps folder as <name>.elvl, with the pictures it uses beside it as <name>.bass. That pair is the map: the blocks, the materials, the environment, what a bake of it should contain and the last thumbnails taken of it. Map names use lowercase letters, digits, _ and -. See Installing a map.

Saving is instant and does not make a playable map. Baking does: it turns the map into a <name>.<id>.blvl next to it, which is the file the game loads and other players download. A bake is worked out entirely from the map, so it can be thrown away and made again at any time, and baking again replaces the one before it rather than piling up. Saving with nothing changed leaves the files alone.

Bake on save, in the File menu, starts a bake in the background every time you save. Editing carries on over it and a panel in the bottom right shows how far along it is, with the map's name, the step it is on and how long it took. Saving again while one is running queues exactly one more, for whatever the map looks like when the running one finishes. It does not take thumbnails -- that needs the map loaded and the camera pointed at it, which would interrupt you -- so the bake keeps the ones the map already had, and File > Bake... is still how new ones are taken.

Test run (Ctrl+R) plays the map right away without saving, with exactly the variants the editor is showing rather than the map's defaults; a track being tested still picks its own. Esc returns to the editor. The next test run without a track starts where you left off; Test from spawn starts at the map's start spawn instead, and Test run here, in the right-click menu, drops you at the spot under the cursor facing the way the camera faces, with any loaded track set aside. Leaving with unsaved changes asks to save, discard or keep editing, and Save saves then carries on leaving.

Edit tracks opens the track editor on the same map.

Embedded tracks

A map can carry its race tracks inside itself, and the maps that ship with the game carry theirs this way. Map > Embedded tracks lists them: each row has an eye that shows or hides the track's overlay, a colour swatch, the number of checkpoints and a count of anything that keeps it from being run. Every embedded track is drawn over the map in its colour, dimmed, so a course can be judged against the geometry while blocks are moved. Edit opens the track in the track editor and Back to map returns; New adds an empty track to the map and opens it; Embed takes one of the map's loose track files into the map; the download button writes a loose copy to the tracks folder; × removes a track from the map.

Embedded tracks are saved with the map and baked into it, and they are part of the map's name on the wire: changing one is a new bake, like moving a block. Records set on the previous bake stay on the leaderboard under the same track, so a course that got easier or harder keeps its history. A map opened from a bake with no map of its own shows its tracks read-only; save it as a copy to change them.

Baking

File > Bake… writes the map with the extras a finished map carries. Ctrl+B or File > Bake bakes right away with the choices the map already has. Tick what goes in:

  • Acoustics: room reverb and how sound travels through the map.
  • Minimap: the top-down map, at the resolution you pick.
  • Final lighting: the full lighting bake. The bake waits for it to finish.
  • Flythrough: a camera path over the map. Stops, street dips, shortest and longest length, speed, height above roofs and field of view shape it; Reset puts them back. Only the main-menu map plays its flythrough.
  • Thumbnails: pictures for map tiles and the Workshop preview, at Thumbnail (512x288), Wide (1920x816) or UHD (3840x2160). UHD adds a few MB to the map, and the Workshop takes the widest of them that fits its 1 MB limit. The camera is Automatic, framed from the spawn, or Custom: Use editor view takes the view the editor camera had, and Pick view… hides the dialog so you can fly to a view and press Use this view. Esc goes back to the dialog.

Each extension shows whether the map file already has it, or has it from an older version of the map. Bake saves unsaved changes as part of the bake. Baking gives the map a new name on the wire, so its tracks are restamped. Cancel before the map is written changes nothing; after that it stops before the flythrough and thumbnails. The choices are remembered in the map, not in the bake, so they survive a rebake.

A bake carries the map it was made from, which is what lets anyone who has it open it in the editor -- the training range and the other maps that ship with the game included. Publishing to the Workshop offers to leave that out, for a map you would rather people played than built on. Leaving it out does not change the map's name on the wire: it is the same map either way.

Performance

Map > Performance shows how heavy the map is, one bar per measure, with ticks for the Low (L), Medium (M), High (H) and Ultra (U) graphics budgets and a red line where a hard limit sits. The badge says the lowest quality the map fits: all, a tier and up, over, or over limit. The Map section updates as you edit: placed model triangles, the heaviest model, physics props, blocks, lights, realtime-shadow lights, smoke, sounds and asset counts. The Renderer section comes from the last bake and says so when the map has changed since: world triangles and draw batches, prop draws and triangles, texture memory at each quality, lighting memory, reflection probes, the most lights reaching one spot or one batch, realtime shadows in reach of one place against the shadow slots each quality has, fog volumes and colliders. Click a row to list what costs the most; click an entry to select it and frame it. Problems lists a measure over its Low budget as a note, and over Ultra or a hard limit as a warning.

File sizes

Map > File sizes lists the map's files -- the working bake, the map source, its asset blobs and any released bakes -- with each one's sections, how much each takes on disk and unpacked, and its share of the file. Sections marked • are part of the map's name on the wire. Adding thumbnails or a flythrough after a bake leaves unused space behind in the bake; Compact rewrites the file without it. The map keeps its name on the wire, and nothing in it changes. The map source and its blobs are rewritten whole on every save, so they have nothing to compact.

Map repositories

A map repository is a git repository of maps, for keeping a set of maps in sync with other people and tracking every change. Window > Map repositories lists them; File > Add map repository… adds one.

Git and Git LFS have to be installed. Git for Windows includes Git LFS; on Linux install git and git-lfs from the package manager. The editor finds git on its own, or set Settings > Git > Git program. Signing in to the server uses git's own credentials: Git Credential Manager on Windows, or an SSH key.

A repository keeps maps in maps/ and loose tracks in tracks/<map>/. Its maps show up in the Open window and the Maps screen with the repository's name, and saving one writes it back into the repository. A map with no bake can be opened and edited but not played; bake it, or use Bake out-of-date maps in the Changes tab.

  • Add a repository: Clone from a link, pick a folder that already holds one, or make a new one. New repositories get the folder layout and Git LFS set up for map files.
  • Sync: saves nothing by itself. It brings in other people's changes and sends yours. File > Sync changes… commits the maps you tick with a message, then syncs.
  • Changes groups files by map. Discard puts a map back to its last committed version; the discarded files go to Recover.
  • Branches: create, switch to, merge into the current one, or delete a merged branch.
  • Conflicts: when a map changed on both sides, pick Keep mine, Use theirs, or Keep both (theirs is saved as <map>_theirs), then Finish merge. Stop merge puts everything back as it was.
  • History lists every version, and Save as copy brings back an old version of a map under a new name.
  • Recover lists the backups taken before every merge, branch switch and discard, and the discarded files.
  • Settings: the server address, whether bakes are kept in git, Git LFS repairs, and the name and email your commits carry.

A map that is open with unsaved changes is saved before anything changes its files, and it reloads after a sync brings in a new version of it. Nothing here force-pushes, resets or deletes a branch that is not merged.

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. Test > Sound maps how sound travels through it: see Sounds.

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.
  • Play > Race > My Tracks > Edit on a track.
  • New track or Open track in the map editor's Start window.
  • 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.

KeyTool
1Start
2Checkpoint
3Finish zone
4Reset zone
5NPC
6Path
7Teleport
8Trail
9Arrow
Barrier
  • Start sets where runs begin and which way the runner faces.
  • Checkpoints must be touched in order. PgUp and PgDn move 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.
  • A path is a route for NPCs to walk, and runners never see it. The first click places it and every click after adds a point, until Esc or another tool. Clicking a point selects that point, clicking between points selects the whole path. Insert after, in the inspector, adds a point after the selected one. Deleting the last points of a path deletes the path.
  • A teleport zone sends whoever enters it to its exit, facing the exit's yaw and keeping their speed. The exit is a handle of its own: select it and move it like anything else.
  • Trails, arrows and barriers only guide the runner. A trail is a line of moving chevrons runners see, drawn and edited like a path. An arrow is a solid arrow turned any way with the rotate gizmo or its Rotation fields; Aims at can instead point it at the runner's next checkpoint, at one chosen checkpoint, or at the finish, keeping only its roll. A barrier is a see-through wall that grows clearer as you get close; Solid makes it block players too.

Zones, teleports and barriers are boxes. Set their center and half size in the inspector.

Checkpoints

A selected checkpoint's inspector sets what reaching it does:

  • Set health puts the runner's health at that number, up to 999. 0 leaves it alone.
  • Refill ammo fills every magazine and the spare magazines.
  • Change loadout swaps the runner's guns for the ones listed from then on. With every slot empty the runner is unarmed from then on.
  • Needs every spawned npc dead holds the checkpoint back until the NPCs that are up have been killed.
  • Lap loops back to: with Laps above 1 in Track settings, reaching this checkpoint starts the next lap, and the runner heads back to the chosen checkpoint, or through the start zone first when it is the start. On the last lap the loop is ignored and the run carries on to the next checkpoint or the finish.

Going back to a checkpoint in practice restores the health and loadout it set.

NPCs

An NPC stands still or walks a path. A path turns back at its end, loops to its first point, or stops there, and each point can hold the NPC there for a few seconds or change its speed to the next point. Run plays a running animation instead of walking.

In a time trial NPCs can also wait to appear. Spawns at picks the run start, reaching a checkpoint, or a kill group being cleared, and Delay adds seconds on top. Again every lap brings a dead NPC back each time its trigger fires again. Kill order puts NPCs in groups: an NPC with a higher number is shielded, shown by a glow and its number over its head, until every lower group is dead. 0 means any time. In a race with other players every NPC is up from the start and none is shielded.

Visibility

Trails, arrows and barriers have Shown from and Shown until: they appear only while the runner's next checkpoint lies between the two, and Only on lap limits them to one lap. A solid barrier only blocks while it is shown, so a wall can close a route once the runner is past it.

Track settings

Track > Settings sets the name, id, author, laps, start health, variants and loadout. The loadout is the guns the track hands out, with spare magazines per slot; the runner's own loadout is never used. With every slot empty runners start unarmed. -1 magazines means unlimited reloads. Laps above 1 need a checkpoint that loops back. Start health 0 leaves the runner on the usual 100.

If the map has variants, Track settings picks which of them the track is raced on, and a race on the track runs exactly that configuration whatever else the server is set to. A run set with the night wing open is not the same track as one set with it closed, so each selection keeps its own records. The panel warns when the start or a zone sits inside geometry the chosen variants leave out.

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, and every zone has a size. Save still works on an unfinished track and lists what is missing. Test run refuses until it is fixed.

Photo

The Photo part of the track panel takes the picture that track lists, the track page and the Workshop show for the track. Set from camera keeps where the editor camera is looking, Go to camera flies back there, and Field of view sets how wide it sees. Preview switches the world between the editor overlays and what a racer sees: checkpoint curtains, start and finish zones, trails, arrows and barriers. Take photo renders a 512x288 thumbnail and a 1920x816 still from the photo camera with the race look, and Clear removes them. The photo is saved in the track file and does not change the track's identity, so retaking it keeps its runs and leaderboard. A track with no photo shows its map's picture.

Saving and publishing

Ctrl+S saves the track as <tracks folder>/<map>/<id>.btrk. See Files and folders. File > Test run plays it.

A track opened from the map's Embedded tracks list has no file of its own: Ctrl+S keeps it in the map and saves the map, which rebakes it when Bake on save is on. New track makes a loose file unless it is started from the Embedded tracks window.

To share a track, open Play > Race > My Tracks. The upload button publishes it to the race registry after one proving run, where an admin can make it official. When a published track's photo changes, the upload button comes back and sends the new photo. The Workshop button publishes it to the Workshop on its own; its map must be one that ships with the game or is on the Workshop, and whoever subscribes gets the map with it.

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
  • --map names the map inside the game files. --out is the file to write.
  • steam in place of a path finds the game in your Steam library, where supported.
  • --fast does a quick bake in seconds to check that a map loads.
  • blvl list with a frontend flag lists the maps it can find.
  • blvl info <file.blvl> and blvl probe <file.blvl> --problems check a baked map.
  • blvl help prints every option.

A bake also writes a .bsym file next to the map. It is a local debugging aid for the map debugger, not part of a map: keep it beside the .blvl while you work, and ship only the .blvl.

Rebaking a block map

eds-bake reworks a map made in the editor in place: --env <map> <day|night|dusk|indoor|env.json> changes its sky and lighting, --env-json <from> <out.json> writes the settings out to edit, --textures-export <map> <dir> writes its custom textures out as image files, and --textures-import <map> <dir> pulls every PNG and JPEG in a folder in, replacing textures of the same name. Each of these rebakes the map, so its name on the wire changes, its tracks are restamped, a flythrough has to be flown again with --fly, and the lighting has to be baked again with --light. They keep the map's File > Bake… settings, which is the in-editor way to store lighting, a flythrough and thumbnails, and the tracks the map carries. --tracks-list <map> prints those tracks, --tracks-export <map> <dir> writes them out as .btrk files, --tracks-embed <map> <track.btrk|dir>... puts tracks into the map and --tracks-drop <map> <id>... takes them out; embedding and dropping change the map's name on the wire but keep its lighting, thumbnails and flythrough.

eds-bake --light <map>... bakes a block map's lighting and stores it in the map without changing its name on the wire; --light-preview bakes the quicker editor quality. eds-bake --light-report <map> lists what the map's lights cost to draw: how many overlap in each 2 m cell, each light's radius and how far it really reaches, and the largest textures. --thumb-out <dir> writes a thumbnail to a folder instead of storing it, from the map's own camera or from --thumb-pose.

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 custom map with the same name as a shipped one stands in for it.

Subscribing on the Steam Workshop does all of this for you.

Maps on servers

A custom map is only on your machine. To play it with others, start a session on it and open it to LAN or Steam, or put it in a dedicated server's map folder. Players download it when they join. See Maps on a server.

Steam Workshop

The Workshop is where maps, texture packs and asset packs are shared. It needs Steam running. A build without Steam has no Workshop, and custom maps still work by hand: see Installing a map.

The Workshop window

Maps > Workshop opens it. Browse is everything published, Subscribed is what you have taken, and Mine is what you have published. Sort by Trending, Popular, Newest, Recently updated or Top rated, filter to Maps, Texture packs or Asset packs, and search by name; searching ranks by how well things match, so it stands in for the sort. Fifty items to a page.

A row shows the picture, the title, who made it, its score, and whether you are subscribed, whether it is installed and whether an update is waiting. Play starts an installed map, Open in Steam opens the item's page, and the pencil on one of your own reopens the publish dialog to edit the listing.

Subscribing

Subscribe takes the item and Steam downloads it in the background. A subscribed map joins the Maps screen once Steam has it and goes when you unsubscribe. Race tracks published with a map show up under it, a subscribed texture pack appears in the editor's Packs pane, and a subscribed asset pack appears in the Library under Installed; maps that already use its textures or assets keep them either way.

Updates look after themselves: the game notices a new version and fetches it. Update on the row does it by hand.

A map you already have wins over a subscribed one of the same name, so a shipped map or one of your own is never pushed aside by a Workshop copy.

Publishing a map

Publish from the upload button on the map's card on the Maps screen, or File > Publish… in the map editor. Save first, as the editor's entry is greyed out while there are unsaved changes. What goes up is the bake, so the map has to be baked: see Baking.

The dialog asks for:

  • Title and description, filled in from what the map says about itself.
  • The picture, which starts as the widest of the map's own thumbnails that fits Steam's 1 MB limit. Retake from here takes a fresh 1920x816 shot from where you are standing, so the map has to be loaded; the shot is squeezed until it fits.
  • Which race tracks ride along. Tracks the map carries always do; loose tracks set on this bake can be included, and one set on an older bake is listed but cannot be, until it is set again on this one.
  • Let others open this map in the editor, on by default. It is only offered for a map whose bake carries the map it was made from; a bake that does not, such as one downloaded from a server, has nothing to open. See Baking for what leaving it out means.
  • Tags: Duel, Race, Free-for-all, Remake, Original, Small, Large.
  • Visibility: Public, Friends only, Unlisted or Private.

Publishing packs the map's images into it first, so the item stands on its own. A map downloaded from a server keeps its images in the shared image store rather than in the map, and not all of them are necessarily here: any that are missing are fetched from where the map came from before it goes up, which the dialog says up front and shows the progress of. A map whose missing images cannot be fetched -- nowhere to ask, or the repository does not have them -- cannot be published whole, and the dialog says so before you fill it in. When it is done you get a link to the item.

Publishing a texture pack

Pick a pack in the editor's Packs pane and press Publish…. The picture is made from the pack's own textures and cannot be retaken, and the tags are their own set: Photoreal, Stylised, Retro, Urban, Industrial, Nature, Interior, Sci-fi.

You have to confirm you have the right to share the textures before Publish will do anything, because textures from a pack are copied into every map that uses them and go to other players with it. Only publish textures you made, or whose licence allows that, such as CC0. Workshop… in the same pane opens the Workshop on texture packs.

Publishing an asset pack

Open a collection in the Library and press Publish…. What goes up is the same .zip Export pack… writes. The picture is a sheet of the assets' thumbnails and cannot be retaken, the tags are the texture pack set, and one tag for each kind of asset in it is added without asking. The dialog shows what the pack holds.

As with texture packs, you have to confirm you have the right to share what is in it, because the materials, models and sounds from a pack are copied into every map that uses them and go to other players with it. Publishing the collection again updates the same item, and raising its version in the collection panel tells the two apart.

Updating and removing

Publishing something you have published before updates that item in place rather than making a new one, and asks for a change note. The game remembers which item each of yours belongs to in workshop.json in the custom maps folder; lose that and the next publish makes a new item. Delete, on your own item in the Mine tab, takes it off the Workshop.

When the Workshop is unavailable

With Steam not running the window says so and publishing is off. A build without Steam has no Workshop at all.

Steam asks you to accept the Steam Workshop agreement once before anything you publish is visible to anyone else. Until you do, your items show "Workshop agreement pending" with an Open button that takes you to it.

Files and folders

On Linux, data goes under ~/.local/share/eds and settings under ~/.config/eds. On Windows both go under %APPDATA%\eds.

WhatDefault locationOverride
Settings~/.config/eds/config.cfgEDS_SETTINGS
Startup scriptautoexec.cfg next to config.cfg
Mode configsany .cfg next to config.cfg
HUD profileshud_profiles.json next to config.cfg
HUD imageshud_images folder next to config.cfg
Bookmarksbookmarks.json next to config.cfg
Console historyconsole_history next to config.cfg
Loglatest.log in the game folder, or eds.log next to config.cfgEDS_LOG
Custom maps~/.local/share/eds/mapsEDS_CUSTOM_MAPS_DIR
Published Workshop itemsworkshop.json in the custom maps folderEDS_WORKSHOP_REGISTRY
Downloaded maps~/.local/share/eds/servermapsEDS_SERVER_MAPS_DIR
Tracks~/.local/share/eds/tracksEDS_TRACKS_DIR
Runs~/.local/share/eds/runsEDS_RUNS_DIR
Replays~/.local/share/eds/replaysEDS_REPLAY_DIR
Camera tracks~/.local/share/eds/cineEDS_CINE_DIR
Screenshots~/.local/share/eds/screenshotsEDS_SCREENSHOT_DIR
Renders~/.local/share/eds/rendersEDS_RENDER_DIR
Shipped mapsassets/maps in the game folderEDS_MAPS_DIR
Map repositories~/.local/share/eds/repos for clones
Discarded repository files.git/eds/trash in the repository

EDS_SERVER_MAPS_CACHE_MB caps the downloaded map cache, 4096 MB by default.

Command line

eds

OptionDoes
--maps-dir <dir>Adds a map folder. Repeat for more.
--map-repo <dir>Adds a map repository for this run: its maps count as shipped maps, and it shows in Map repositories. Repeat for more.
--bake-maps <dir>Bakes every map source in a folder without opening a window, then exits. --out <dir> writes the bakes elsewhere, --only a,b picks maps, --stale-only skips maps whose bake is current, and --check only reports which bakes are current.
--createStarts a session on this machine on start.
--join <code>Joins a Steam session by invite code on start.
--spectate <code>Spectates a Steam session by invite code on start.
--server <host:port>Connects to a server on start.
--replay <file.brep>Opens a replay file.
<file.brep>Opens a replay file, or imports it if it is a race run. Double-clicking a .brep file does the same.
--display <name>Opens the window on this monitor.
--dedicatedRuns the dedicated server instead of the game. Every later option is the server's.
-v, -vvMore logging.

In Steam, set these under the game's Properties > Launch options.

eds --dedicated

See Command line flags under Hosting a server. The standalone eds-server binary takes the same flags.

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 session rules. Whoever manages the session sets them: its owner on a local server, an admin on a dedicated server.
  • sv.* variables belong to dedicated servers. Set them in server.cfg, or over rcon as an admin.

input

Mouse and keys.

VariableDefaultValuesDescription
input.sensitivity0.040.005 to 0.3Degrees of view rotation per mouse count
input.ads_togglefalseThe aim key toggles the sights instead of being held
input.map_togglefalseThe map key toggles the map overlay instead of being held
input.zoom_sens10.2 to 2Multiplier on the focal-length sensitivity scale through a magnified scope

video

Display and renderer.

VariableDefaultValuesDescription
video.modeBorderlessWindowed, Borderless, FullscreenWindow mode
video.monitoremptyDisplay to use; empty means the primary
video.width1600640 to 16384 pxWindow width in windowed mode; in fullscreen on Wayland, the width the scene renders at before scaling to the display
video.height900480 to 16384 pxWindow height in windowed mode; in fullscreen on Wayland, the height the scene renders at before scaling to the display
video.display_serverAutoAuto, X11, WaylandLinux only: which display server to open the window on; auto follows the session
video.steam_overlay_bridgetrueLinux only: on a Wayland window, feed keys and mouse to the Steam overlay through a hidden Xwayland window so Shift+Tab works; turn off to leave the overlay without input; needs Xwayland
video.vsyncOffOff, On, MailboxOff presents as soon as a frame is done, On waits for the display, Fast keeps only the newest frame
video.fps_cap00 to 1000 HzFrame cap; 0 follows the display, rounded up to a whole multiple of its rate and never below 120
video.low_latencyOnOff, On, BoostNVIDIA Reflex or AMD Anti-Lag when the driver offers it
video.fov10570 to 130 degHorizontal field of view
video.render_scale10050 to 200%Scene resolution as a share of the window; above 100 supersamples
video.brightness10.5 to 2Exposure multiplier
video.reticle_brightness10.2 to 2.5How bright a red dot, holo or scope reticle is drawn
video.qualityMediumCompetitive, Low, Medium, High, Ultra, CustomRender preset; changing a detail below makes it Custom
video.shadowsMediumOff, Low, Medium, High, UltraSun shadow resolution, reach and softness; Medium and up add shadows cast by players and props, Ultra sharpens the ones cast by realtime map lights
video.ambient_occlusionLowOff, Low, Medium, HighScreen space contact shading
video.dynamic_lightstrueMuzzle flashes and explosions light the world
video.surface_detailHighLow, HighNormal, roughness, emissive and directional lightmap detail on surfaces
video.texture_detailHighLow, Medium, High, UltraTexture sharpness: how many of the sharpest mip levels are kept, and how far anisotropic filtering goes at grazing angles
video.reflectionsLowOff, Low, HighReflection detail; Low refracts and reflects the scene in water, High adds screen space reflections and caustics
video.antialiasingOffOff, FxaaEdge smoothing; render scale above 100 supersamples as well
video.sharpen00 to 1Contrast adaptive sharpening after anti-aliasing
video.bloomfalseGlow around bright light, where the map style uses it
video.effectsNormalMinimal, Normal, EnhancedMuzzle flash, explosion and smoke detail; Minimal is the flat competitive look, Normal stirs smoke around players, Enhanced adds lingering smoke wakes and shadowed flashes; smoke shape and blocking are the same on every level
video.physics_propstrueBottles, crates and barrels react to the player, shots and blasts
video.card_effectstrueTrails, weather and pets following players holding a foil card
video.smoke_halftrueRender smoke clouds at half resolution and upscale them, much faster inside and around smoke
video.smoke_color#a8a5a0Colour of smoke grenade clouds where they are fully lit
video.smoke_brightness10 to 4Brightness of smoke grenade clouds, 1 shows the chosen colour as picked

audio

Sound.

VariableDefaultValuesDescription
audio.master0.750 to 1Master volume
audio.weapons10 to 1Gunfire, explosions, reloads and weapon handling
audio.movement10 to 1Footsteps, jumps, landings, ladders, slides and water
audio.world10 to 1Bullet impacts, breaking glass and walls, and doors
audio.voices10 to 1Player grunts, pain and death cries
audio.interface10 to 1Hit markers, checkpoints and objective cues such as the bomb
audio.ambience10 to 1Background sound a map plays
audio.music10 to 1Music a map plays; the server station has its own volume
audio.spatialArcadeArcade, HrtfArcade makes direction easy to hear on any headphones or speakers; HRTF simulates a listener's head for headphones
audio.reverbtrueReverb
audio.radiotruePlay the music a server is streaming; off tells the server to send none of it
audio.radio_localfalseRun a station from your radio directory on every session this pc hosts, alone or open to others
audio.radio_volume0.150 to 1How loud the server's station is
audio.equalizertrueDraw the radio equalizer HUD element and the equalizer cards; off stops the audio analysis too
audio.radio_duck00 to 1How far the station drops while a round is live; 0 leaves it alone

profile

Player.

VariableDefaultValuesDescription
profile.modelmaleCharacter model: male or female
profile.handRightRight, LeftGun hand
profile.emotes[0, 1, 2, 3, 4]list, 0 to 15Emote wheel slots
profile.dances[0, 1, 2, 3, 4]listDance wheel slots
profile.loadout12 entrieslistWeapon slots, three per preset
profile.loadout_names[Assault, Close, Long, Utility]listPreset names
profile.loadout_pick00 to 3The preset in hand

hud

Overlay.

VariableDefaultValuesDescription
hud.showtrueDraw the HUD
hud.scale10.5 to 2Size of the overlay
hud.max_hz00 to 1000 HzHUD updates per second; 0 sends one every frame
hud.profiledefaultHUD profile used where the game mode has none of its own
hud.map_introtrueShow a 3D overview of the map and its objectives when joining a server

cfg

Mode configs.

VariableDefaultValuesDescription
cfg.duelemptyConfig file run on entering a duel
cfg.ffaemptyConfig file run on entering a free-for-all
cfg.tagemptyConfig file run on entering a game of tag
cfg.raceemptyConfig file run on entering a race
cfg.gungameemptyConfig file run on entering gun game
cfg.horseemptyConfig file run on entering HORSE
cfg.bombemptyConfig file run on entering a bomb round
cfg.ctfemptyConfig file run on entering capture the flag
cfg.spectateemptyConfig file run on starting to spectate
cfg.replayemptyConfig file run on opening a replay

crosshair

Crosshair.

VariableDefaultValuesDescription
crosshair.linesfalseDraw the four arms
crosshair.dottrueDraw the centre dot
crosshair.circlefalseDraw a ring around the centre
crosshair.t_stylefalseLeave out the top arm
crosshair.size60 to 40 pxArm length
crosshair.splitfalseGive the vertical arms their own length
crosshair.size_v60 to 40 pxVertical arm length when split is on
crosshair.gap4-10 to 40 pxGap from the centre
crosshair.thickness20.5 to 8 pxArm and ring thickness
crosshair.rotation00 to 45 degArm rotation
crosshair.dot_size21 to 12 pxCentre dot diameter
crosshair.radius102 to 40 pxRing radius
crosshair.color#e8f7ffColour
crosshair.alpha1000 to 100%Opacity
crosshair.outline10 to 4 pxDark outline width; 0 turns it off
crosshair.outline_alpha850 to 100%Outline opacity
crosshair.hit_flashfalseFlash the hit colour when you deal damage
crosshair.hit_color#ff4040Hit flash colour

crosshairs

Crosshair profiles.

VariableDefaultValuesDescription
crosshairs.saved7 entrieslistCrosshair profiles, one id, code and name per entry
crosshairs.activexhDeftId of the crosshair profile being edited

cosmetics

Cosmetics.

VariableDefaultValuesDescription
cosmetics.presetemptyOutfit preset
cosmetics.paletteemptyOutfit palette
cosmetics.partsemptylistPart overrides on top of the preset, one slot=id per entry; none empties an optional slot
cosmetics.laser#ff2214Colour of the laser on a gun that carries one, as everyone sees it; dark colours are brightened

card

Playing card.

VariableDefaultValuesDescription
card.slots4 entrieslistCard wheel slots, one id or id:foil per entry; random_favorite pulls a random favorite
card.favoritesemptylistFavorite cards, one id or id:foil per entry
card.pick00 to 3The slot the card comes out of
card.accent_1#ff0000First card accent colour, as everyone sees it; the speed card trail, the first alpha tester strand and the developer card 0s
card.accent_2#00ff00Second card accent colour; the second alpha tester strand and the developer card 1s
card.accent_3#0000ffThird card accent colour; the third alpha tester strand
card.trail_light1000 to 100%How brightly the speed and alpha tester card trails light the world; each colour lights about as much at the same setting
card.trail_length10010 to 100%Speed and alpha tester card trail length as a share of the longest

maps

Maps.

VariableDefaultValuesDescription
maps.recentemptylistMaps a match was played on lately, newest first
maps.favoritesemptylistMaps starred as favorites

editor

Map editor.

VariableDefaultValuesDescription
editor.recentemptylistMaps opened, copied or saved in the map editor lately, newest first
editor.sel_width1.250.25 to 5 pxThickness of the selection outline in the editor
editor.sel_alpha8210 to 100%Opacity of the selection outline
editor.sel_color#ffdc3cColour of the selection outline
editor.hover_width10.25 to 5 pxThickness of the outline under the cursor
editor.drag_outlinefalseKeep the selection outline and face highlights drawn while a gizmo handle is held
editor.show_gridtrueDraw the ground grid in the map and track editors
editor.fps_cap12030 to 120 HzFrame cap while editing; the editor never runs above this or above video.fps_cap
editor.qualityLowGame, Low, Medium, HighRender preset while editing; Game settings follows the graphics settings
editor.guide_width20.5 to 6 pxThickness of the layout helper lines
editor.guide_labelstrueDraw distance labels on rulers, measurements and selection dimensions
editor.fly_speed70050 to 4000Editor camera fly speed
editor.fly_sprint2200100 to 12000Editor camera fly speed with Shift held
editor.look_sens10.05 to 4Multiplier on mouse sensitivity for the editor camera
editor.bake_on_savefalseBake the map in the background every time it is saved in the map editor
editor.test_lightingtrueLight test runs with the editor's live lighting when the map's bake is out of date
editor.library_threads00 to 64Threads library imports share; 0 picks from the CPU count
editor.library_jobs21 to 8Library jobs that can run side by side
editor.reposemptylistMap repositories added to the map editor, by folder
editor.repos_trustedemptylistMap repositories trusted although another user owns their folder
editor.gitfalseUse git for map repositories; the editor only looks for git once this is on and the editor is open
editor.git_pathemptyPath to the git program; empty finds it on its own
editor.repos_auto_fetchtrueCheck map repositories for changes from others every few minutes

oiko

Crash reports.

VariableDefaultValuesDescription
oiko.upload_crash_dumpsfalseAfter a crash, send the developers a minidump on the next launch: the crashed process's memory, stacks, loaded modules and command line, plus the session log and the build. Environment variables are stripped; the log and the memory may still hold names, addresses and file paths

net

Servers.

VariableDefaultValuesDescription
net.favoritesemptylistServers starred in the browser; an entry is [label=]host:port
net.historyemptylistServers connected to lately, newest first
net.auto_mapstrueDownload a session's map when this client lacks it
net.snapshot_rate12832 to 128 HzSnapshots asked of the server each second: 128, 64 or 32. A server sends fewer on a poor connection or when its own upload is full

discord

Discord.

VariableDefaultValuesDescription
discord.presencetrueRich presence
discord.lobby_invitestrueShow your session and its invite code in presence so friends can join

race

Race mode.

VariableDefaultValuesDescription
race.pb_prompttrueAfter finishing an official track with a time the leaderboard would take, open a prompt to submit it

privacy

Privacy.

VariableDefaultValuesDescription
privacy.streamerfalseMask addresses, Steam ids, invite codes and other identifying details on screen; click a masked value to copy it

watch

Spectator HUD layers.

VariableDefaultValuesDescription
watch.hudtrueGame HUD in a replay
watch.inputstrueKeyboard and mouse input overlay for the player being watched
watch.inputlogfalseLog of the watched player's recent button presses in a replay
watch.teamfalseTeam panel
watch.playertruePlayer panel
watch.feedtrueKill feed
watch.scoreboardfalseScoreboard
watch.minimapfalseMinimap
watch.statsfalseStats block
watch.phasetrueMatch phase
watch.effectsfalseCard effects on every player in a replay whatever the mode or phase, each with the effect they had equipped
watch.effectemptyForce one card effect on every player in a replay, by card id; empty leaves each player's own
watch.pathsfalsePath ribbons in a replay: where each player went over the last watch.path_window seconds
watch.path_window60.5 to 30 sSeconds of travel a path ribbon covers
watch.path_width31 to 8 pxPath ribbon width on screen
watch.path_xrayfalseDraw path ribbons through walls
watch.hitboxesfalseHitbox wireframes on every living player in a replay, coloured by body part and drawn through walls
watch.lagviewServerServer, ClientWhose view of the other players a replay draws: Server where the server had them, Client where the watched player saw them after lag compensation
watch.lagcompfalseHitbox wireframes of the other lag comp view on every other player, with a line joining the two, and the capsules each shot was tested against
watch.fly_speed30010 to 8000 qu/sFree camera speed in a replay
watch.fly_boost240050 to 20000 qu/sFree camera speed in a replay with the walk key held
watch.fly_accel121 to 60How quickly the replay free camera reaches its speed; lower glides more
watch.fov00 to 170 degReplay free camera field of view; 0 keeps video.fov
watch.orbfalseA translucent sphere around every player, as a placement and distance reference
watch.orb_radius25616 to 4096 quRadius of the framing sphere
watch.orb_alpha0.250.05 to 1How solid the framing sphere is
watch.orb_color#8cbeffFraming sphere tint
watch.thirdsfalseA rule of thirds grid over the frame while a shot is composed; authoring only, never in a render

rig

Rigged replay camera.

VariableDefaultValuesDescription
rig.aimPlayerPlayer, Tripod, MouseWhat the rig's rotation is measured against: Player rides with the subject's facing, Tripod holds still as they turn, Mouse follows the look keys
rig.yaw0-180 to 180 degOrbit yaw; 180 puts the camera in front looking back
rig.pitch10-89 to 89 degOrbit pitch
rig.spin0-90 to 90 deg/sConstant pan; the tripod turns by itself at this rate
rig.dist1600 to 4096 quArm length: how far the camera sits from the subject
rig.shoulder0-400 to 400 quLateral offset, right is positive
rig.height0-200 to 400 quPivot height above the subject's eye
rig.collidefalsePull the camera in at walls; off keeps the placement exact
rig.min240 to 600 quClosest the wall pull-in may bring the camera
rig.clearance160 to 200 quGap the camera keeps off whatever it hits
rig.in_rate300 to 120How fast the camera pulls in
rig.out_rate60 to 120How fast the camera eases back out
rig.roll0-180 to 180 degCamera roll
rig.fov00 to 170 degRigged camera field of view; 0 keeps video.fov
rig.focus_rate00 to 20How fast focus racks to its target; 0 snaps

cine

Cinematic mode.

VariableDefaultValuesDescription
cine.onfalseThe high quality replay render path; the panels turn this on
cine.qualityHighOff, High, UltraDetail floor cinematic mode holds whatever video.quality is; Off keeps your settings
cine.supersample11 to 4Scene resolution multiplier on top of video.render_scale
cine.doffalseDepth of field
cine.focus00 to 8192 quFocus distance; 0 focuses on whatever the camera is pointed at
cine.focus_slot-1-1 to 15Hold focus on a player slot; -1 uses cine.focus
cine.aperture0.40 to 1How fast the world falls out of focus
cine.bokeh10.25 to 3How much a blurred highlight blooms
cine.motion_blur00 to 1Shutter angle as a share of the frame
cine.grain00 to 1Film grain
cine.vignette00 to 1Darkening towards the corners
cine.aberration00 to 1Colour fringing towards the edges
cine.bars00 to 3Letterbox aspect; 0 is off, 2.39 is scope
cine.lift0-0.5 to 0.5Grade: shadows
cine.gamma10.25 to 4Grade: midtones
cine.gain10 to 4Grade: highlights
cine.saturation10 to 2Grade: colour
cine.temperature0-1 to 1Grade: cool to warm
cine.paceOffOff, Speed, AccelPacing overlay on the camera track being edited: Speed tints the path by speed against the track's mean, Accel by the change from the segment before

console

Console.

VariableDefaultValuesDescription
console.height0.450.2 to 1Fraction of the window the console covers
console.vifalseVi editing on the prompt
console.font_size149 to 32 pxFont size
console.opacity0.920.3 to 1Background opacity

perf

Profiler.

VariableDefaultValuesDescription
perf.max_frames00 to 1000000Frames a capture records before it stops itself; 0 for no frame limit
perf.max_secs301 to 1800 sSeconds a capture records before it stops itself
perf.max_events10000000100000 to 50000000Spans, counters and marks a capture holds before it stops itself
perf.max_packets2000001000 to 5000000Packets a capture holds before it stops itself
perf.cputrueRecord the CPU track
perf.gputrueRecord the GPU track
perf.nettrueRecord the network track
perf.gewytrueRecord the gewy UI track
perf.servertrueRecord the listen server's track
perf.servo_constellationfalseAlso record servo's constellation spans, which are most of its instrumentation and rarely the cost
perf.max_view_spans300000010000 to 20000000Spans the viewer loads before it truncates the tail of a capture

app

Application.

VariableDefaultValuesDescription
app.versionBuild version (read only)
app.cloud_syncfalsePush config.cfg and hud_profiles.json to Steam Cloud on every save

game

Session rules.

VariableDefaultValuesDescription
game.mapThe map the session is on (read only)
game.modeduelduel, ffa, tag, race, gungame, horse, bomb, ctf, scriptGame mode
game.variantsemptylistMap variants to turn on by name; -name turns one off, and the map's own mode bindings pick the rest
game.weapons27 entrieslistGuns the per-fight draw may hand out
game.rounds00 to 30Round wins that take the match; 0 plays without a limit
game.tag_time300120 to 1200 sHow long a tag match runs
game.tag_headshottrueOnly a headshot tags
game.bomb_plant4.51 to 600 sHow long planting the bomb takes
game.bomb_defuse5.51 to 600 sHow long defusing it takes
game.bomb_fuse401 to 600 sHow long a planted bomb burns for
game.bomb_round751 to 600 sHow long a bomb round runs before the defenders take it
game.ctf_time120060 to 3600 sHow long a capture the flag match runs
game.ctf_respawn70 to 3600 sHow long a death costs in capture the flag
game.ctf_return301 to 3600 sHow long a dropped flag lies before it goes home
game.ctf_wave150 to 3600 sCapture the flag respawn wave: each team's dead come back together every this many seconds, the two teams half a wave apart; 0 respawns each player on their own ctf_respawn
game.freeze_time30 to 30 sHow long everyone is frozen at the spawns before a fight goes live
game.round_end_delay2.50.5 to 15 sHow long a finished fight is held before the next one sets up
game.fights_per_round21 to 10Fights that win a duel round
game.warmup_respawn20 to 60 sHow long a warmup death costs
game.time_limit00 to 3600 sMatch clock for the modes that run without one -- duel, free-for-all and gun game; 0 plays without a clock
game.ctf_pickup_delay30 to 60 sHow long the player who dropped a flag must wait before taking it again; anyone else may take it at once
game.ctf_touch_radius4816 to 256 quHow close a player has to be to touch a flag
game.bomb_rounds_per_half51 to 30Rounds a half runs for before the sides swap, when the match has no round limit
game.bomb_pickup_radius4816 to 256 quHow close an attacker has to be to pick a dropped bomb up
game.bomb_defuse_radius1616 to 256 quHow close a defender has to be to the planted bomb to defuse it
game.tag_respawn10 to 60 sHow long a tag death costs
game.tag_it_respawn3.50 to 60 sHow long the new it waits before respawning
game.gg_respawn20 to 60 sHow long a gun game death costs
game.horse_set103 to 120 sHow long the setter has to throw the grenade
game.horse_chase205 to 120 sHow long the chasers have to reach the mark on the first turn; each turn after takes a second off, down to 12
game.horse_mark1.50 to 30 sHow long the round pauses once a mark is laid
game.horse_results51 to 60 sHow long a horse round's results stay up
game.horse_mark_radius328 to 256 quHow close a chaser has to get to a mark to hit it
game.race_overtime200 to 600 sHow long the rest of the field has once the first racer finishes
game.race_results61 to 120 sHow long a race's results stay up
game.loadout_16 entrieslistWhat the first loadout slot may hold: class plurals or weapon tags
game.loadout_2[pistols]listWhat the second loadout slot may hold
game.loadout_3[grenades]listWhat the third loadout slot may hold
game.loadout_lock_2emptylistFirst-slot guns that leave the second slot empty
game.loadout_lock_3[grenade_launcher, rpg]listFirst-slot guns that leave the third slot empty
game.ammo10 to 10Scale on every gun's reserve ammo; 0 leaves reloads unlimited
game.visibilityprivateprivate, lan, friends, publicWho can find the session
game.race_rulesracerace, practiceRun rules on a track: race keeps records and restarts a fall, practice resets to the last checkpoint
game.cheatsfalseNoclip is allowed here
game.competitivefalseThis server enforces the competitive ruleset (read only)
game.warmup_wait00 to 3600 sSeconds a match waits in warmup before it may start; 0 means none
game.max_players00 to 16Player cap; 0 means the mode's own

sv

Server.

VariableDefaultValuesDescription
sv.bind0.0.0.0:27960UDP address to listen on (restart)
sv.modeffaWhat this server runs: ranked, or the game mode its rotation plays such as ffa, duel, tag or race (restart)
sv.hostnameemptyThe name the browser shows
sv.publictrueList this server on the backend directory
sv.backendhttps://backend.eliteduelspeed.comBackend URL: the directory and the track registry (restart)
sv.public_addremptyThe host:port players reach this server on, when the backend cannot tell
sv.passwordemptyPlayers must give this to connect; empty means anyone
sv.adminsemptylistPlayer ids that manage this dedicated server and may use rcon; empty means nobody but the server console and the control API, and a lone * means every client that connects, verified or not. An id only counts when sv.auth verified it, so this does nothing while sv.auth is off. A remote admin cannot run writeconfig, alias, bind, script or history, cannot list vars, and cannot read or set server secrets. A local server ignores it: its session owner manages
sv.authrequiredWhether a UDP client must prove who it is: required, optional or off. Off means no identity is verified, so sv.admins grants nothing
sv.auth_keysemptylistkid:hex signing keys to trust; empty fetches them from the backend
sv.cardsverifiedWhether a card a player shows must be backed by a backend-signed entitlement: verified or trusted
sv.dbemptyThe SQLite file for stats, ratings, bans and records; empty means eds-server.db (restart)
sv.snapshot_div11 to 16Fewest ticks between snapshots to a player; a player may ask for fewer snapshots and a poor connection is given fewer
sv.spectator_snapshot_div41 to 64Ticks between snapshots to a spectator
sv.petstrueWhether pet cards spawn a pet
sv.pet_div81 to 64Ticks between pet updates to a client
sv.spectator_delay_secs00 to 120 sHow far behind the match spectators see it; 0 is live
sv.max_players161 to 16Players the session takes; anyone past it joins as a spectator, queued to play
sv.max_viewers3000 to 10000Spectators this server takes
sv.waiting_max00 to 256Players a full server holds in a line, let in as seats free; 0 turns the line off and a full server turns them away
sv.default_mapemptyMap a session starts on; empty means the training range (restart)
sv.rotationemptylistRotation entries: map, map:mode, map:mode:variants or map:mode:variants:file.cfg, or track ids (map/id or id for a track a loaded map carries, else a file in sv.tracks_dir, else a backend track) when sv.mode is race
sv.tracks_diremptyWhere a race server looks for .btrk files named by the rotation (restart)
sv.autostart_players22 to 16Players before a rotation match starts itself
sv.warmup_secs200 to 600 sWarmup before a rotation match starts
sv.results_secs101 to 120 sHow long results stay up before the rotation moves on
sv.mapvotefalsePlayers vote on the next rotation entry instead of it simply moving on
sv.mapvote_choices42 to 8Entries on the ballot, drawn from the rotation
sv.mapvote_secs305 to 120 sHow long a vote runs after a match; it holds the results up for at least this long
sv.mapvote_recency10 to 4How hard the ballot keeps off what was played recently; 0 ignores it
sv.mapvote_popularity0-2 to 2How 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_win00 to 30Round wins that take a rotation match; 0 plays without a limit
sv.weaponsemptylistGuns the fights may draw from, by tag; empty means all of them
sv.loadout_1emptylistWhat the first loadout slot may hold: class plurals or weapon tags; empty means the shipped rule
sv.loadout_2emptylistWhat the second loadout slot may hold; empty means the shipped rule
sv.loadout_3emptylistWhat the third loadout slot may hold; empty means the shipped rule
sv.loadout_lock_2emptylistFirst-slot guns that leave the second slot empty; empty means the shipped rule, none locks nothing
sv.loadout_lock_3emptylistFirst-slot guns that leave the third slot empty; empty means the shipped rule, none locks nothing
sv.ammo10 to 10Scale on every gun's reserve ammo; 0 leaves reloads unlimited
sv.tag_time_secs300120 to 1200 sTag time limit
sv.tag_headshottrueTag passes on headshots only
sv.late_joinfalseA player who joins during a match plays, sitting out until the next fight; off has them spectate, queued to play when it ends
sv.bomb_plant_secs4.51 to 600 sHow long planting the bomb takes
sv.bomb_defuse_secs5.51 to 600 sHow long defusing it takes
sv.bomb_fuse_secs401 to 600 sHow long a planted bomb burns for
sv.bomb_round_secs751 to 600 sHow long a bomb round runs before the defenders take it
sv.ctf_time_secs120060 to 3600 sCapture the flag time limit
sv.ctf_respawn_secs70 to 3600 sHow long a capture the flag death costs
sv.ctf_return_secs301 to 3600 sHow long a dropped flag lies before it goes home
sv.ctf_wave_secs150 to 3600 sCapture the flag respawn wave: each team's dead come back together every this many seconds, the two teams half a wave apart; 0 respawns each player on their own ctf_respawn
sv.freeze_time_secs30 to 30 sHow long everyone is frozen at the spawns before a fight goes live
sv.round_end_delay_secs2.50.5 to 15 sHow long a finished fight is held before the next one sets up
sv.fights_per_round21 to 10Fights that win a duel round
sv.warmup_respawn_secs20 to 60 sHow long a warmup death costs
sv.time_limit_secs00 to 3600 sMatch clock for the modes that run without one -- duel, free-for-all and gun game; 0 plays without a clock
sv.ctf_pickup_delay_secs30 to 60 sHow long the player who dropped a flag must wait before taking it again
sv.ctf_touch_radius4816 to 256 quHow close a player has to be to touch a flag
sv.bomb_rounds_per_half51 to 30Rounds a half runs for before the sides swap, when the match has no round limit
sv.bomb_pickup_radius4816 to 256 quHow close an attacker has to be to pick a dropped bomb up
sv.bomb_defuse_radius1616 to 256 quHow close a defender has to be to the planted bomb to defuse it
sv.tag_respawn_secs10 to 60 sHow long a tag death costs
sv.tag_it_respawn_secs3.50 to 60 sHow long the new it waits before respawning
sv.gg_respawn_secs20 to 60 sHow long a gun game death costs
sv.horse_set_secs103 to 120 sHow long the setter has to throw the grenade
sv.horse_chase_secs205 to 120 sHow long the chasers have to reach the mark on the first turn; each turn after takes a second off, down to 12
sv.horse_mark_secs1.50 to 30 sHow long the round pauses once a mark is laid
sv.horse_results_secs51 to 60 sHow long a horse round's results stay up
sv.horse_mark_radius328 to 256 quHow close a chaser has to get to a mark to hit it
sv.race_overtime_secs200 to 600 sHow long the rest of the field has once the first racer finishes
sv.race_results_secs61 to 120 sHow long a race's results stay up
sv.ranked_max_sessions41 to 64Ranked sessions at once; queues wait when every one is busy (restart)
sv.ranked_rounds61 to 30Round wins that take a ranked match (restart)
sv.ranked_window15010 to 2000Rating gap the queue pairs across, widening with wait (restart)
sv.ranked_widen_secs[15, 45, 90]listSeconds queued before the window widens, one per stage (restart)
sv.ranked_pause_secs300 to 300 sHow long a ranked match waits for a dropped player (restart)
sv.ranked_warmup_wait_secs605 to 600 sHow long a ranked session waits for everyone to arrive (restart)
sv.ranked_warmup_players161 to 16Players the ranked warmup session holds while they wait for a match (restart)
sv.ranked_tau0.50.1 to 1.2Glicko-2 volatility constraint (restart)
sv.ranked_margintrueScale rating moves by the round margin (restart)
sv.race_track_secs9000 to 86400 sHow long a race server stays on one track; 0 rotates by hand
sv.race_rulesraceRun rules on a race server: race or practice
sv.heartbeat_secs305 to 600 sHow often the directory hears from this server
sv.regionemptyWhere this server is, for the browser
sv.tagsemptylistWords the browser can filter on
sv.official_banstrueRefuse players on the official backend banlist
sv.banlist_sync_secs3010 to 600 sHow often this server pulls banlist changes from the backend
sv.upload_replaystrueShip finished recordings to the backend
sv.recordtrueRecord every match (restart)
sv.highlightstruePlayers can highlight moments into the match's replay
sv.record_diremptyWhere recordings go; empty means the default replay directory (restart)
sv.download_mbits8000 to 10000 Mbit/sUpload the server will spend on map and replay downloads, shared between them; 0 turns downloads off
sv.max_downloads321 to 1024Downloads at once
sv.map_urlemptyBase URL clients try first for a map, as <url>/<name>.blvl; empty sends every map in-game
sv.map_url_onlyfalseNever send maps in-game; clients get them only from sv.map_url
sv.max_replays641 to 100000Recordings kept on disk
sv.replay_keep_secs0sRecordings older than this are dropped; 0 keeps them
sv.cheatsfalseAllow noclip in every session
sv.competitivefalseEnforce the competitive ruleset: forced graphics, no overlays, no injected modules
sv.competitive_secure_bootoffSecure Boot a competitive client must have: off, windows or all
sv.competitive_overlaysknownOverlays a competitive client is refused for: known, or strict to also refuse any Vulkan layer we do not recognise
sv.radiofalseRun a station: stream the radio directory to everyone who asks for it (restart)
sv.radio_diremptyWhere the songs and the .txt playlists live; empty means the radio directory beside the server (restart)
sv.radio_playlistemptyThe playlist to play, by file name without .txt; empty plays the whole library
sv.radio_shufflefalsePlay in a random order
sv.radio_mbits1000 to 10000 Mbit/sUpload the station may spend across all its listeners; 0 stops the audio but keeps the track information
sv.radio_max_listeners640 to 1024Listeners the station takes at once
sv.radio_buffer_secs52 to 30 sHow much audio a listener is sent ahead of the playhead; also how far behind the server they hear it
sv.radio_gain_db0-24 to 6 dBLevel trim applied to every song
sv.radio_art_px2560 to 512 pxLongest side of the album art listeners are sent; 0 sends none
sv.radio_scan_secs00 to 86400 sRe-read the radio directory this often; 0 reads it on start and on radio rescan
sv.scriptsemptylistScripts to run from sv.scripts_dir, by file name without .mjs or .js; take one out to stop it
sv.scripts_dirscriptsWhere scripts live (restart)
sv.script_mem_mb161 to 256 MBMemory each script may use; applies the next time it loads
sv.script_budget_ms201 to 1000 msHow 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.

CommandArgumentsDescription
adminOpen the admin panel
alias[name] [command...]Name a command line; alone, list aliases
automation[list|state]List the map's automation nodes and signals, or show their state
ballistics[hitboxes [off|xray|depth]|paths|pause|clear]Open the ballistics window: shots, penetration, impacts, damage and blasts; dev builds or cheats
bind[key] [command...]Run a command when a key is pressed; alone, list binds
binds[filter]Open the binds window: every key, what it runs, and how to change it
bookmark[name|list|clear <name>]Save where you are on this map so teleport brings you back; alone, the quick slot
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
changelogOpen the changelog
cinema[visuals|render|mode|tracks|rig]Open or close a replay panel: the visuals, the render setup, the look, the camera tracks, or the camera rig
clearClear the console
connect<host:port>Connect to a server
copy_crosshairAdd the crosshair of the player you're spectating or watching in a replay as a new profile and use it
createStart a session on this pc
crosshair_codePrint your crosshair as a share code and copy it to the clipboard
crosshair_import<code>Add the crosshair from a share code as a new profile and use it
cycle<var>Move an enum variable to its next value
dec<var> [step]Subtract from a number variable
disconnectLeave the session
echo<text...>Print text
exec<file>Run every line of a config file
feedbackOpen the feedback form
get<var>Show a variable's value
help[name]What a command or variable does; alone, list everything
highlightMark this moment in the match's replay; everyone's highlights show on the replay timeline
history[count]Show recent commands
hud_editMove 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_refreshFetch cards and entitlements from the backend again
join<code>Join a session by invite code
log_level[level|spec]Show or set the log filter: error, warn, info, debug, trace, or an env_logger spec
manage_panelOpen or close the server or session manage panel
manualOpen the manual
map[name]Change map; alone, list the maps
mapdebugOpen the map debugger here, on this map, at this camera
mixerOpen the sound mixer: bus meters, live voices and propagation tuning
networkNetworking: the link, this machine's address, Steam and the backend
noclipFly through walls
perf[view|toggle|start [label]|stop|status|abort|save [name]|export [name]|load <file>]Record a profiler snapshot of the CPU, GPU, network and UI, then save or export it
quitLeave the game
radio[action] [args...]Run the station you are listening to: status, play, pause, skip, restart, playlist, shuffle, rescan, jump, list or playlists
rcon<line...>Run a console line on the dedicated server
recordStart recording the session on the server, warmup and all; owner or admin
render<track|here|stop> [fps] [WxH] [samples]Render a camera track, or the current camera with here, to a video file; render stop stops
reset<var> | --allPut a variable back to its default; --all resets everything including binds
savereplaySave the match so far to this machine
say<text...>Say something to the session
screenshot[clean]Save a screenshot; clean drops the UI and the view model
set<var> <value...>Set a variable
signal<name> [arg]Send a signal to the map's automation; on a server, through rcon
statusWhat the game is doing: screen, connection and server
stopStop the recording record started and save it to this machine
teleport[name]Go back to a bookmark on this map, with the aim and speed it was saved with; alone, the quick slot
thumbcamPrint this camera as a cameras/<map>.toml entry for the map's thumbnail
toggle<var>Flip a bool variable
toggleconsoleOpen or close the console
ui_resetRelease stuck UI input and reload the HUD
ui_restartRestart the UI process
unalias<name>Remove an alias
unbind<key>Free a key
unbindallFree every key
vars[filter] [--changed]Open the variables window; a filter narrows it
versionShow the game, gewy and protocol versions
vote<n>Pick an entry on the open map vote
watch<code>Spectate a session 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 or the control API. set, get, vars, help and exec work there too.

CommandArgumentsDescription
statusWhat this server is doing
membersWho is here, playing or spectating
kick<name|#member|playerid>Drop a member
ban<name|#member|playerid> [secs] [reason]Drop somebody and keep them out; no seconds means forever
unban<playerid>Lift a ban
bansList the bans
banlistsThe 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 server's session on a map now
maps[refresh]List the maps here and on the map server
nextmapMove 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
startStart the session's match
endEnd the session's match
say<text>Say something to everyone
tell<name|#member|playerid> <text>Send one player a private system line
announce<text>Send everyone 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
explode<x> <y> <z> [intensity] | <player> [intensity]Set off a blast; 1 is a grenade, bigger reaches further and hurts more
kill<name|#member|playerid> [intensity]Kill a player; an intensity blows them apart instead of dropping them
signal<name> [arg]Send a signal to the map's automation
automation[list|state]List the map's automation nodes and signals, or show their state
loadout<name|#member|playerid> [primary|none [sidearm|none [utility|none]] | reset]Override the guns a player brought, whatever the session offers; alone, show them
score[--json | reset | <player> [kills|deaths|score] <n|+n|-n> | team <0|1> [rounds|fights] <n|+n|-n>]Show or set the score, kills and deaths; alone, show everything
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

KeyNameCommandAction
F4F4dumpDump state
F5F5screenshotScreenshot
F6F6toggle dev.third_person
F9F9devDev tools
F10F10dev weapons

Variables

profile

Player.

VariableDefaultValuesDescription
profile.nameplayerDisplay name

net

Servers.

VariableDefaultValuesDescription
net.backendhttps://backend.eliteduelspeed.comBackend URL: the server list, invite codes and the race registry
net.sitehttps://eliteduelspeed.comWebsite URL, for the links the Watch page copies
net.short_sitehttps://eds.lolShort link host, for the replay links the Watch page copies

dev

Developer.

VariableDefaultValuesDescription
dev.third_personfalseChase camera
dev.cam_dist1100 to 600 quChase camera arm length
dev.cam_shoulder18-200 to 200 quChase camera shoulder offset, right is positive
dev.cam_height0-100 to 200 quChase camera focus height above the eye
dev.cam_yaw0-180 to 180 degChase camera orbit yaw; 180 puts it in front looking back
dev.cam_pitch0-89 to 89 degChase camera orbit pitch
dev.cam_min240 to 600 quClosest the wall pull-in may bring the chase camera
dev.cam_clearance160 to 200 quGap the chase camera keeps off whatever it hits
dev.cam_in_rate300 to 120How fast the chase camera pulls in
dev.cam_out_rate60 to 120How fast the chase camera eases back out
dev.cam_fov00 to 170 degChase camera field of view; 0 keeps video.fov
dev.cam_roll0-180 to 180 degChase camera roll
dev.cam_collidetruePull the chase camera in at walls
dev.sound_vizfalseDraw live sounds, their occlusion rays and indirect paths; offline, in the editor, in replays and with cheats on
dev.smoke_cellsfalseOutline the cells each smoke cloud fills
dev.reticle_rulerfalseDraw MOA circles about the crosshair
dev.shot_viewmodelfalseKeep the view model in clean screenshots
dev.hide_viewmodelfalseHide the first-person view model
dev.styleAutoAuto, Eds, Urt, Q3, Cs2, Val, Css, Csgo, Tf2, Ow2, Cod4, Bo1, Halo2, Reflex, ApexRenderer style
dev.exposure_lockfalsePin auto-exposure to the map's authored midpoint
dev.q3_overbright-1idTech3 r_overBrightBits override; -1 keeps the map's
dev.q3_map_overbright-1idTech3 r_mapOverBrightBits override; -1 keeps the map's
dev.q3_gamma0idTech3 r_gamma override; 0 keeps the map's
dev.src_hdrtrueSource 1 HDR path; off forces the LDR chain
dev.cod4_filmtrueCoD4 film tweak
dev.cod4_glowtrueCoD4 glow
dev.bo1_filmtrueBlack Ops three-zone film grade
dev.bo1_glowtrueBlack Ops glow
dev.bo1_curvetrueBlack Ops filmic s-curve
dev.light_stylestrueAnimate the light style table
dev.halo2_lightmap_gain20 to 4Halo 2 lightmap modulate; 0 keeps the map's gain
dev.halo2_detailtrueHalo 2 detail maps
dev.halo2_env10 to 4Halo 2 environment map scale
dev.halo2_fogtrueHalo 2 atmospheric fog
dev.depth_prepasstrueFill depth before shading the opaque world, so an overdrawn pixel is only shaded once
dev.gpu_timingfalseTimestamp every render pass for timing; HUD widgets showing GPU metrics turn this on by themselves

Commands

CommandArgumentsDescription
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
dev[home|anim|parts|pose|tp|rekey|cards|wardrobe|weapons]Open the dev tools here, on this map; again to close and go back
dump[player|probe|collision|pose]Print the player, what the crosshair is on, the nearby collision and the pose
notices[list|update|fallback|announce [tone] [title]|clear|refresh]Add test cards to the main menu notices: an update, fallback mode or an announcement
timing[on|off]Turn per-pass GPU timing on or off; alone, print the last frame's zones