The Complete GoldSrc Mapping Guide: Building a Real Counter-Strike 1.6 Map
This is a full walkthrough for building maps in classic Counter-Strike 1.6, running on the GoldSrc engine. It covers everything from tool setup to compiling, optimizing, and packaging a finished map — written for GoldSrc specifically, not Source or Source 2. The workflow, compilers, and entity set below (Valve Hammer Editor, ZHLT, BSP/VIS/RAD) do not apply to CS:Source or CS:GO, which use a completely different toolchain (Hammer++, VBSP/VVIS/VRAD, VMF format).
Click to read the full guide →
Step 1: Install the Core Tools
You need three things before you touch a single brush:
- Valve Hammer Editor (v3.4 or later) — the actual level design application. It’s the GoldSrc-era predecessor to Hammer++.
- ZHLT (Zoner’s Half-Life Tools) — the compiler suite. This is what converts your editable
.map/.rmffile into a playable.bsp. - halflife-cs.fgd and halflife.wad — the entity definitions and base texture set for Counter-Strike specifically.
Install Hammer to a simple path like C:\Hammer\ rather than Program Files — GoldSrc-era tools sometimes fight with Windows write permissions in protected folders. Extract ZHLT into its own dedicated folder too, for example C:\zhlt\. Keep your compile tools and your Counter-Strike install in accessible, non-nested locations; this will matter later when writing your compile script.
Step 2: Configure Hammer Properly
Open Tools → Options and work through each tab — most beginners skip half of this and pay for it later.
- Game Configurations tab: create a new configuration named
cstrike. Point the Game Executable Directory at your Counter-Strike install, and the Mod Directory specifically at thecstrikesubfolder. - Game Data Files: add
halflife-cs.fgd. This file tells Hammer what entities exist (spawn points, buttons, lights, CS-specific entities like buy zones) and what properties each one has. - Textures tab: add
halflife.wadas your base WAD. You can add more WADs later (custom texture packs,zhlt.wadfor tool textures) — Hammer will pull from all loaded WADs when you browse textures. - Build Programs tab: point Hammer at your ZHLT executables (
hlcsg.exe,hlbsp.exe,hlvis.exe,hlrad.exe). This lets you compile directly from inside Hammer later instead of relying only on a batch file, which is faster for iteration.
Step 3: Learn the Interface
Hammer splits your screen into four viewports: Top, Front, Side, and a 3D/Camera view. The three orthographic views are 2D slices of your map from different angles — everything you build exists simultaneously in all of them. Get comfortable checking your work across all three 2D views before committing to a shape; a wall that looks fine from the top might be floating or misaligned from the side.
Key tools you’ll use constantly:
- Selection tool — select, move, and resize existing brushes and entities.
- Brush (block) tool — draw new rectangular solids.
- Entity tool — place point entities like lights and spawn points.
- Camera tool — creates a preview camera so the 3D viewport shows something.
- Clipping tool — slices a single brush into two along a plane, essential for anything that isn’t a plain box (stairs, ramps, angled walls).
- Vertex tool — manually drag individual corners/edges of a brush for custom shapes.
Step 4: Understand Brushes and the Void
Every solid object in a GoldSrc map — walls, floors, stairs, props built from geometry — is a brush: a convex 3D shape defined by flat planes. GoldSrc brushes must be convex; you can’t make a single brush shaped like an L or a U. Complex shapes are built from multiple brushes fit together, or by using the clipping/vertex tools to reshape a box.
Outside of anything you build is the void — empty, non-existent space. The void isn’t a wall or a boundary; it’s the absence of your map. This concept is central to the single biggest challenge new mappers face, covered next.
Step 5: The Golden Rule — No Leaks
A GoldSrc map must be a fully enclosed, sealed volume. If there is any gap — a missing wall, a tiny sliver where two brushes don’t quite touch, a doorway with no door brush sealing it — the void leaks into your playable space. This is called a leak, and it breaks your compile’s lighting and visibility calculations entirely (the compiler can’t process VIS or RAD correctly if it can’t tell what’s “inside” your map).
Practical rules to avoid leaks:
- Every room needs a floor, ceiling, and all four walls — no exceptions, even for rooms you think are “outdoor.”
- Outdoor/sky areas still need to be enclosed by a skybox — a large hollow box using the
SKYtexture. There’s no such thing as truly open space in GoldSrc. - Windows and openings need to be sealed with glass brushes, grates, or something — an open hole to the void is a leak.
- If your compile does leak, ZHLT generates a pointfile. Load it in Hammer (Map → Load Pointfile) and it draws a red line straight from your map’s origin to the exact leak point — follow the line to find the gap.
Step 6: Build Your First Room
- Pick a texture from a loaded WAD using the texture browser.
- Draw a brush in the Top viewport for your floor — flat and wide.
- Hold Shift while dragging the floor brush to duplicate it, then resize the copy into a wall. Repeat for all four walls and the ceiling.
- Check every seam in all three 2D viewports to confirm brushes are actually touching, not just visually close.
- Adjust your grid size with the
[and]keys — use a large grid (32, 64, or bigger) for basic room shapes, and only drop to a fine grid when you need small precise details. Building on too fine a grid early on is one of the most common causes of tiny, invisible leaks.
Step 7: Texture Alignment
Textures on GoldSrc brushes can be reset, scaled, and shifted independently per face. Poor alignment (stretched, rotated, or seamed textures) is one of the fastest ways to make a map look unfinished. Use the Face Edit sheet (usually opened with the texture application tool or a dedicated hotkey) to:
- Fit a texture cleanly to a face size
- Adjust X/Y shift and scale so textures align across adjoining brushes (like a floor and a wall meeting at a corner)
- Use “Treat as one” alignment across multi-brush surfaces so a texture doesn’t visibly repeat awkwardly at brush seams
Step 8: Place Core Entities
Entities give your geometry gameplay meaning. Every Counter-Strike map needs, at minimum:
- info_player_start — Counter-Terrorist spawn points. Place several, floating slightly above the floor (never touching walls or floor) so players don’t spawn stuck.
- info_player_deathmatch — Terrorist spawn points, same placement rules.
- light — a point light entity. Set color and brightness via Alt+Enter on the entity. Standard format is R G B Brightness (e.g.
255 255 128 200).
Beyond the basics, Counter-Strike’s FGD gives you gamemode-defining entities:
- func_buyzone — a brush entity (select brushes, Ctrl+T) defining where players can open the buy menu. Set the Team property so CT and T buy zones don’t overlap incorrectly.
- func_bomb_target — defines a bombsite for de_ maps.
- info_bomb_target — point entity alternative/companion for radar bomb icon placement.
- hostage_entity — places a rescuable hostage for cs_ maps.
- func_hostage_rescue — brush entity marking the rescue zone.
- armoury_entity — spawns weapons/equipment pickups directly in the world.
- weaponbox and related — used less often manually, but relevant for scripted weapon placement.
Map type dictates which entities are mandatory: de_ maps need bomb targets, cs_ maps need hostages and rescue zones, and both need properly configured buy zones or the round will not function correctly even if the map compiles fine.
Step 9: Add Detail Entities
Once the gameplay skeleton is in place, layer in atmosphere:
- ambient_generic — plays a looping or triggered sound (wind, machinery, music) from a WAV in the game’s sound folder.
- func_water — a brush entity that turns a sealed volume into swimmable/visible water, with adjustable current and opacity.
- func_door and func_door_rotating — sliding and rotating doors respectively, built by turning a brush into an entity (Ctrl+T) and configuring open direction, speed, and lip.
- func_ladder — an invisible climbable volume placed over a ladder-textured brush; without it, the ladder texture is purely visual and unclimbable.
- func_breakable — glass, crates, or other destructible geometry.
- trigger_multiple / trigger_once — invisible brush volumes that fire other entities when a player touches them, the backbone of scripted sequences.
Step 10: Understand the Compile Process
ZHLT compiles in four sequential stages, each producing input for the next. Understanding what each stage actually does makes error messages far less mysterious:
- hlcsg (CSG) — Constructive Solid Geometry. Converts your brushes into the engine’s internal format and checks for leaks. This is where a leak error first appears.
- hlbsp (BSP) — Binary Space Partitioning. Splits your map into a tree structure the engine uses for collision and rendering. This stage can throw errors about “MAX_MAP” limits if your map is too complex or contains malformed brushes.
- hlvis (VIS) — Visibility. Calculates which parts of the map can see which other parts, so the engine doesn’t render geometry the player can’t possibly see. This is usually the slowest stage on large or open maps.
- hlrad (RAD) — Radiosity. Calculates lighting by bouncing light off surfaces. This stage is what actually makes your light entities and texture lights visible in-game.
A basic Steam-based compile batch file looks like this:
@echo off
hlcsg -nowadtextures yourmapname
hlbsp yourmapname
hlvis yourmapname
hlrad yourmapname
copy yourmapname.bsp "C:\Steam\SteamApps\<youraccount>\counter-strike\cstrike\maps"
pause
"C:\Steam\Steam.exe" -applaunch 10 -dev +sv_cheats 1 +map yourmapname
-nowadtextures embeds all textures directly into the BSP so players don’t need your custom WADs installed separately — strongly recommended for anything you plan to release publicly.
Step 11: Useful Compile Flags for Faster Iteration
Full-quality compiles can take a long time, especially VIS and RAD on larger maps. While actively building and testing, use fast/preview flags to cut iteration time dramatically, then switch to full quality only for your final release build:
hlvis -fast— a much faster, lower-quality visibility pass for testing.hlrad -fast— quick, rougher lighting pass, useful for checking layout without waiting on full radiosity.hlcsg -onlyents— skips full geometry recompilation and only updates entity data, useful when you’ve only moved a spawn point or tweaked a light, not the brushwork.- Full release compile should drop the fast flags entirely, and consider
hlrad -extrafor higher-quality bounce lighting on a finished map.
Step 12: Optimize for Performance
GoldSrc is an old engine, but poorly optimized maps still choke it, especially in multiplayer. A few essential habits:
- Use the NULL texture on any brush face that will never be seen by a player — the underside of terrain, brush faces pressed flush against another brush, the outside of your skybox. NULL faces aren’t rendered or lit, saving compile time and runtime performance.
- Hint brushes (using the
zhlt.wadtool textures) let you manually guide the VIS compiler to split visibility more intelligently around corners and sightlines, which is otherwise one of the hardest things to optimize automatically. - Avoid excessive brush count and unnecessary complexity in detail geometry — use texture detail instead of geometric detail where possible.
- func_wall or func_illusionary can convert static decorative brushes into entities, which removes them from VIS calculations in certain cases and can help performance on detail-heavy areas.
- Keep an eye on the
r_speedsin-game counter (enable withsv_cheats 1, thenr_speeds 1) while testing — it shows real-time polygon and surface counts so you can spot problem areas.
Step 13: Test Thoroughly
Compile with cheats enabled and walk your own map like a player would, not just a builder:
- Use
noclipto check for leaks and gaps you might have missed visually. - Use
impulse 101to grab a full weapon set and test combat sightlines, not just navigation. - Check that all spawn points are unobstructed and that buy zones, bomb sites, or hostage rescue zones actually trigger correctly.
- Test with bots or a second player if possible — solo walkthroughs miss a lot of balance issues that only show up with real player movement and gunfights.
Step 14: Package for Distribution
If you want other people to play your map without manually installing your WAD files, remember to compile with -nowadtextures so all textures are baked directly into the .bsp. Beyond that:
- Include any custom sounds referenced by
ambient_genericentities in a matchingsound/folder structure alongside your map, since audio isn’t embedded in the BSP. - Consider writing a simple readme noting map type (de_/cs_/etc.), player count recommendation, and credits.
- Test your final packaged BSP on a clean install or a dedicated server without your Hammer environment present, to confirm nothing is silently depending on local files that won’t ship with the map.
That covers the full pipeline: tool setup, interface fundamentals, brush-based geometry, leak-proofing, the full CS entity set, the four-stage compile process, performance optimization, and final packaging.