---
title: "GoldSrc Map Optimization: The Complete Checklist"
excerpt: "A practical pass-by-pass checklist for keeping a CS 1.6 map fast and inside engine limits: NULL, func_detail, VIS, hint brushes, texture scale and clip hulls."
category: "mapping"
tags: "optimization, mapping"
image: ""
read_time: "9 min read"
---
<p>A GoldSrc map runs well when it respects the engine's fixed limits and gives <code>hlvis</code> an easy job. Most performance and "map won't compile" problems trace back to a handful of habits. This is the checklist to run against any CS 1.6 map before release — each item is cheap, and together they keep the map inside the BSP v30 limits and fast on modest hardware.</p><h2>1. NULL every face the player never sees</h2><p>Apply the <code>NULL</code> tool texture to the backs of walls, undersides of floors, tops of skybox brushes, and any hidden brush side. <code>NULL</code> faces are removed at compile: no rendering, no lightmap, less work for every tool. This single habit reduces face count, wpoly, and lightmap usage across the whole map. It is the first thing to check when you hit <a href="/tutorials/fix-allocblock-full">AllocBlock: Full</a>.</p><h2>2. Convert decorative brushwork to func_detail</h2><p>Trim, pipes, rails, signs, clutter, ornamental arches — anything non-structural — should be <code>func_detail</code>. It stays visible and lit but is removed from the BSP tree and from clipnode generation, which cuts face splitting and keeps you clear of <a href="/tutorials/fix-max-map-clipnodes">MAX_MAP_CLIPNODES</a>. Add a <code>CLIP</code> cage where a func_detail shape still needs to block the player.</p><h2>3. Simplify the collision hull with CLIP</h2><p>The player does not need pixel-accurate collision. Wrap complex geometry (rocks, many-sided pillars, terrain) in simple <code>CLIP</code> brushes and let the visual shape be func_detail. Fewer, simpler solid brushes means fewer clipnodes and smoother movement with no snagging.</p><h2>4. Control texture scale for lightmaps</h2><p>Large faces at a small texture scale generate huge lightmaps. Raise the scale on big, low-detail surfaces (ceilings, outer walls, floors under props) to shrink their lightmap footprint, and keep detailed surfaces at <code>1.0</code>. Run a compile with <code>-chart</code> and read the lightmap line:</p><pre>hlrad -chart mymap.bsp</pre><h2>5. Seal the map and kill leaks first</h2><p>VIS optimization is meaningless if the map leaks — a leak makes <code>hlvis</code> either fail or treat the whole level as one visible blob. Confirm a clean compile with no leak, using the pointfile if needed; see <a href="/tutorials/fix-leak-in-hull-pointfile">the leak/pointfile guide</a>. A sealed hull is the precondition for everything below.</p><h2>6. Cut visibility with VIS-aware layout and hint brushes</h2><p>Long unbroken sightlines force the engine to draw huge amounts of the map at once. Break lines of sight with geometry, and place <code>hint</code> brushes (faced with <code>hint</code>, backed by <code>skip</code>) at doorways and corners to split visleafs so the engine culls what is around the corner. This is the core of keeping wpoly low; see <a href="/tutorials/vis-optimization-hint-brushes">VIS optimization with hint brushes</a>. Run the full <code>hlvis</code> pass (not <code>-fast</code>) for the release build.</p><h2>7. Keep entities and wpoly in budget</h2><p>Watch the in-game <code>r_speeds</code>: aim to keep wpoly (world polygons in view) well under a few thousand in the busiest spot on a public server. Merge tiny brushes, remove invisible detail, and avoid huge open rooms full of geometry. Fewer <code>func_</code> entities where a world brush will do also helps, as each entity is drawn separately.</p><h2>8. Final compile discipline</h2><p>Always run the whole chain in order — <code>hlcsg → hlbsp → hlvis → hlrad</code> — for the release, with full VIS and full RAD, and read the <code>-chart</code> output at the end. Vluzacn's VHLT v34 gives the clearest limit report. Fix every warning; a clean log is the goal.</p><h2>Common errors</h2><ul><li><strong>High wpoly / choppy on open maps</strong> — long sightlines and no hint brushes. Break sight lines and add hints.</li><li><strong>Compile hits a limit</strong> — NULL hidden faces and func_detail the clutter; see the <a href="/tutorials/fix-max-map-clipnodes">clipnodes</a> and <a href="/tutorials/fix-allocblock-full">AllocBlock</a> fixes.</li><li><strong>VIS took forever or did nothing</strong> — the map leaks, or you ran <code>-fast</code>. Seal it, then run full VIS.</li><li><strong>Map looks flat after scaling textures</strong> — you scaled detailed faces. Only scale large, low-detail surfaces.</li><li><strong>Player snags on invisible edges</strong> — a CLIP cage is oversized or a func_detail is unexpectedly solid. Tighten the collision.</li></ul><h2>Verification</h2><p>Compile the release build with full VIS and RAD, open the map, and turn on <code>r_speeds 1</code> (or <code>developer 1</code>) to watch wpoly and epoly as you walk the busiest routes. Confirm wpoly stays in budget around corners — if it does not drop when you round a corner, your hint brushes are not splitting visibility there. Check the <code>-chart</code> report shows headroom on faces, clipnodes and lightmaps. Once those numbers are healthy and the log is warning-free, the map is ready to <a href="/tutorials/package-map-for-fastdl">package for FastDL</a>.</p>









