Converting maps from CSS to TF2

Got a question or a tutorial?
User avatar
Posts: 572
Joined: Sun Jan 12, 2014 7:40 am
Location: St. Louis, MO

Converting maps from CSS to TF2

Post by Nastybutler » Mon Jan 13, 2014 2:08 am

Since Kelao's original post at was erased with the rest of the site, there's no other way of informing the masses of how this works, and what I have to go through on a per map basis. This is a very long process and extremely tedious. Patience is required.

I'll pretty much sum up (to the best of my ability) what needs to be done to port a map. All the time I've been doing it along with a couple others, I've learned quite a lot about the process itself and the usefulness of hammer. I've taken all the steps I've learned from all over the internet and information from top mappers and put them all into a nice little post here.

As Kelao stated before, I expect no credit for porting maps. I do this as a service to the community, however small the surfing community in tf2 may be. Remember as you're going through this process yourself someday, that you're only broadening the horizons of these maps. You're not here to majorly alter them. Think of the time, effort and creativity these authors have put into their maps; I'd expect you to do the same when reshaping their works.

Now that's over with, and since you're still reading this, I'm assuming that you have at least the basic knowledge of how hammer works. If you don't, then head on over to the Valve Developer wiki to get yourself situated. (Note that after the steampipe update, source sdk no longer works for Team Fortress 2. Instead, navigate to ".../program files/Steam/steamapps/common/Team Fortress 2/tf/bin/hammer.exe to get started.)

Now that you have your basic knowledge of hammer, there's a few things you'll need before you get started with converting:

We'll be using all these programs during our porting process, so make sure you have them setup and such before you get started.

It's also advisable that you make a separate folder for all your Source editing needs. Shortcuts, map folders and all your programs can go into it for ease of use.

Now. Let's get started.

This whole process will be a lot easier if you already own Counter Strike: Source. If not, it'll be even longer. Most of the skillsurf maps you see on tf2 today are pretty much all ported from CS:S. Since you'll be mapping with tf2's version of hammer, you'll need all the textures from CS:S in your tf2 folder so hammer can pick them up and save you a bunch of time.

In order to do so, we'll be using GCFScape. When you start it up, it'll look something like this:

Now, if you have CS:S, navigate to '.../program file/Steam/steamapps/common/Counter Strike: Source/cstrike'. What you're looking for is a file called 'cstrike_pak_dir.vpk'. That's the file that holds all the texture contained within CS:S.

Once you do, drag it over to GCFScape and open it. You'll see a multitude of folders inside.

Now, with GCFScape still open, you want to navigate to '.../program file/Steam/steamapps/common/Team Fortress 2/tf' and open that up. The folders you see in GCFScape that you want to transfer over into you TF2 folder are thus:
  • Material (do note, inside you'll see a folder called 'vgui' DO NOT copy this over, or else you'll seriously screw up tf2. This folder will take a very long time to transfer over, so be patient)
  • Models (This folder will take a very long time as well)
  • Particles
  • Sound
The materials folders has all your textures for in-game and models. The particles get the idea.

After that's all said and done, you should now notice a multitude of added textures in hammer when you open a map. Now that's all setup and ready to go.

Now, the fun part. Decompiling.

Obtain a map. Either by downloading it off Gamebanana, another site, or out of your cstrike/maps folder. This is where that 'source editing' folder comes in play that I mentioned earlier. Make a new folder to put your obtained .bsp'll be using that folder quite a lot for compiles, fixes, etc. If a map is hard to find, google is your best friend. Just type in surf_<map name>.bsp, and 9 times out of 10 something will pop up. If not, then ask a friend to hook you up. Somebody somewhere has a copy.

Once you have your map, open up GCFScape again. (yeah. This thing is gonna pay for itself in usage). Drag the .bsp file into it. Once again, you'll see all the folders and junk that's packed into the map. Once again, open up your /common/team fortress 2/tf folder and drag all the map folders into tf. If it asks if anything needs to be replaced, just click yes. Now you have all the textures that was packed in the map in hammer. If you don't have CS:S, then you'll have to repeat this process with every map you want to convert. Most often times, a lot of maps will have custom content that the cstrike dir.vpk doesn't have...which is why GCFScape comes in handy. It'll allow you to extract that custom content (textures, sounds, etc.) into your tf folder for use.

Now this is where it gets interesting. Decompilation. This is where you bust out VMEX. VMEX is a simple decompiling tool. Once you have it extracted, double click on it to open it up. You'll get a screen like this:

Browse for your map, and make sure to uncheck cubemaps. I'll explain that later on. Everything else is checked on, Backface texture set to Face, Face Texture set to Original, then DECOMPILE!

The log will scroll through the decompiling process (usually only takes a couple seconds), and saved a decompiled version of your map along with the .bsp. Once it's done, close it out. You'll see that in the map folder where you saved the map, you'll see the surf_<map name>_d.vmf. Rename it, cut the '_d' off, and voila. Also make sure to save a copy of the original map .bsp for reference later.

Every once in a while, VMEX will give you an error something along the lines of "This map is protected from decompilation!" and will close. This means the map is locked. Yes, you can lock your maps during compile...but that's a different story for a different day. So what do you do about a locked map? That's where bspsource come in. It's another decompiler based off the VMEX code, but works a lot more efficiently. And, it can usually break map locks. Same rule applies. Open it up, load your map, make sure cubemaps is unchecked, and decompile.

Open your map in hammer. This is what you've been looking for.

This is where it gets long and tedious, and I'll go through the steps as best I can.


TF2's hammer doesn't recognize some of CS:S' you have to change those first.

First and foremost, what I like to do is scroll through the map from start to finish, make sure nothing's missing. Every once in a while, the decompilation process will not decompile the whole map in it's entirety, so sometimes a ramp or a wall will be missing. Go through the map and re-add those as close to the original layout as possible. (Requires some knowledge of the map structure before-hand).

Find your way to the spawn, and remove all the terrorist/counter terrorist spawns from the map. Replace them with info_player_teamspawn. At least 15 for each team (red and blue). If you don't, then the server will crash trying to allocate players into 1 or 2.

You can also safely remove any player_equip and weapon equips (deagle, awp, knife, etc) from the map as well. Those aren't needed in tf2. Most often on skillsurf maps, you'll also see a damage_filter. Most css skillsurf servers don't have a godmode plugin, so they add a damage_filter to keep you from taking fall damage. Although it works in tf2, it's not needed because we have a godmode plugin. It's up to you if you want to keep it in or not, along with the trigger_multiple that's linked to it which you'll usually find at the spawn.

You should also remove any and all env_cubemaps. We'll be adding our own later.

As you're working, remember to save often. Hammer has a very bad habit of crashing, thus making you lose hours of work. Hammer does have an implemented autosave feature, but don't make a habit of relying on it.


Typically, you work on skillsurf maps which don't have a jail. If you're porting a combat map that has a decent linear surf to it, more than likely it'll have a jail as well. A few high tier skillsurf maps have jails as well. Why? I don't know. Just delete the jail and everything inside of it, and go through the map and reconfigure all the trigger_teleports that tp you to jail to tp you to spawn instead (or wherever). You may have to rename a few triggers or a destination or two, but that's pretty easy.


THIS is the longest part of the process. Most often, maps from CS:S will be custom fitted to allow CS:S models through. CS:S models only need 33 hammer units to squeeze through a tight space, whereas TF2 models require 49. If you're having trouble remembering, you can also look at the Mappers Reference to get a better understanding of how much space you'll need for a comfortable ride. Anything and everything needs to be re-sized. Windows, doors, holes in the ground, etc. Try to re-size it big enough to allow a tf2 player through, but without severely damaging the map or severely altering the original layout.

Something like this:

When I ported over surf_symbiosis, those windows were way too small for a TF2 model to comfortably surf through. So I had to make it bigger as you can see by the measurement. Then just adjusted everything else around it to fit with the rest of the map without making it too obvious.

A golden rule a lot of veteran mappers go by, but beginner mappers usually overlook is save and compile often. It may be a tedious task, but it'll guarantee that you're heading in the right direction. It'll also help save you some time in the long run if you were to go and re-size the whole map, make adjustments and come to find out that all the time you put in was fucked up by one little misplaced brush.

The point of resizing is the mainstay of porting. You want to make sure the map is comfortably surfable in TF2, without use of any exploits or wonky mouse movements. You've been surfing long enough to know the difference between a tier 5 map and a map that just doesn't feel right.

Now you've finally finished resizing, everything seems suitable enough to enjoy...but it's not. We have the longest part taken care of, now the hardest part:


Yeah. Every single map that every single person has ever made needs to be optimized. Read: Make game play smooth and reduce as much lag and compiling time as possible without destroying the map.

You'll notice that a lot of CS:S mappers don't fully optimize their maps; that's because CS:S utilizes the engine at it's fullest potential, whereas TF2 does not. So in CS:S, complete optimization isn't required for a surf map as it is in TF2.

If you have worked on maps and have no clue about optimization, I'd suggest you start here at the Visibility and Level Design. It'll give you the most insight of optimizing lights, visibility and geometry in the map.

We'll start with the easier part: Visleafs.

Visleafs are portals in every map. Every time you create a brush in hammer, the edges cut into your map on straight lines. As the map gets bigger and more complex, more lines cut into the map. These lines will eventually intersect, making 3D spaces called 'visleafs'. In order to show them in hammer, just go into file > run map. Turn off bsp and vrad, and just let vvis run on fast. That'll generate a portalfile. Go up to view > load portalfile and you'll see the visleafs cut in the map.

Those blue lines.

During compiling, there's a program that runs called 'vvis'. What VVIS does is it renders objects inside those visleafs one by one. Meaning, it goes through each 3D space and renders what's inside of it visible. The program that runs after it called 'vrad' applies lighting and shadows to each one of those spaces, one by one, depending on what type of geometry is in that space. This is what takes compiling so long. But of course, the more processing power your computer has, the quicker it goes. If you got a shit processor or less than 4Gb of ram, expect your compile to take 10-15 hours.

How do I make it go faster you ask? Well, I'll tell ya.

There are a couple of ways to lower the amount of visleafs that get cut into a map. The most basic option is func_detail. What func_detail does, is it tells the compiler that the object is a detail and shouldn't be counted as a proper solid form. Although in reality, it is. It's fucking with the compiler's head, tricking it into thinking that it's not real.

In doing so, func_detailng non-critical items such as decorations, eye-candy and even surf ramps will help the compiling time go by quicker and even reduce lag in game. Although, you can't func_detail an outside wall of the map. It'll cause a leak and the map won't compile. But, that doesn't mean go func_detailing everything in the map, either. Just the eye candy and the ramps. If you func_detail everything, then vvis will compile in a couple of seconds and won't give vrad enough information to render the lighting. Meaning you'll probably have some pretty shitty shadows.

See? This surf ramp is func_detailed, so the edges of it doesn't cut any visleafs, thus making the compile process go that much faster. Now imagine if that ramp wasn't detailed, and all the edges of it intersect with all the lines it comes into contact with. That's a lot of 3D space for the compiler to light. The bigger the spaces doesn't necessarily mean longer compile times, it's quite the opposite. If you have a thousand tiny little spaces on your map from all the lines intersecting, then the compiler has to go through each and every one individually and try to decide how to render it. As composed to it running into a bigger space, rendering it, and moving onto the next. You get what I'm sayin?

Another part of optimization are brushsides. A simple cube made in hammer has 6 sides. As you compile your map, those 6 sides all count, no matter what texture or entity you apply to it. If you turn it into a still has 6 sides. If you func_detail it, it still has 6 sides. The number of brushsides also count towards your compiling time. A map can have a total of 65,535 brushsides, or a total of 8,192 brushes. Any more than that, and your vbsp won't compile your map.

Also note, that func_brushes and func_illusionary don't cut visleafs, either. But also remember, you only have a limited amount of brushes you can use in a map.

So what if you have a really big area with a lot of visleafs in it due to a lot of eye candy? That's what 'HINT" is for.

That purple thing

HInts, when used between large rooms, tell the compiler to render each room separately instead of all at once, thus lowering compile times as well and making it easier on vrad to light and properly shadow your map. I can not stress enough how important it is to use these during optimization. Most mappers usually oversee the use of them, then wonder why their maps lag out. Using a hint with a skip texture on the other side will cut a visleaf in between those two large rooms and/or sections of the map.

Such as.

But don't go overboard with it, or else you'll cut too many visleafs and wind up doing more damage than good.


One of the hardest parts of optimizing is lightmapping. Lighting in hammer is very advanced and very long winded, so I'll try to keep it as short as possible.

Static light
Lightmaps at work.

Static light is pre-compiled into lightmaps, which are to all intents and purposes textures. This makes it very cheap, and indeed makes individual light entities free.

There are two areas where optimization can be performed:

Lightmap Scale

A higher Lightmap scale can cause more texture memory to be used, and can impact performance slightly when in the same scene of other materials that effect the total memory usage. Use larger scales wisely when there aren't other expensive materials within the Scene. This even takes effect when there isn't any lighting baked onto a Lightmap, therefore reducing the quality of a Lightmap in a dark area can counter for higher scales in expensive scenes. Lastly, Lightmap Quality also can effect the map file size, and compile time.

lightmaps at work

To set the lightmap scale, just go into faceedit and change it in the top right hand corner.


To see how your lightmaps are affected, down in your 3D view you'll see the word 'camera' in the top left corner. Click on that and change the view to 'lightmap grid'

this is what it'll look like

Now, as you adjust the lightmap through the faceedit, you'll notice the lightmap grids change size and shape. If you want to view how shadows are projected on an object, click the camera again and choose 'ray traced view'. A window will pop up showing you how the lighting affects an object. If it's unsuitable, adjust the brightness and distance of the light.

Naming lights

VRAD assumes that all named lights will be switched on or off at some point, and compiles an extra version of all lightmaps the light touches to provide for this. Not only does this bloat map size, VRAD compiles direct lighting only to reduce the number of lightmaps that need to be touched (i.e. no bounced light). Don't name static lights unless you really have to!

Dynamic light

Dynamic lights are expensive and must be carefully managed. Their number is important, but also what they are pointing at: the more complex the surfaces and numerous the models at which a dynamic light points, the more expensive it becomes. This makes them particularly unsuited to multiplayer maps where it is unclear where the action will be.

It's best, from a performance standpoint, to simply avoid dynamic light unless you notice a large parcel of your budget going unused. Players will be used to static light and won't expect anything better unless you set a precedent yourself.


If VRAD needs more RAM than you have physically installed, it will page memory to the disk and slow down your compile time greatly. Lower lightmap scales to reduce memory usage.

Brush Optimization:

Another way of reducing compile time and adding better performance is reducing the amount of brushes used. This is usually a quick and easy process, considering most maps are pretty much limited to a specific size (that size being the hammer grid and the number of brushes allowed per map), and most maps don't typically lag.

But if the map lags a bit and you've done the steps above, it's time to lower the number of brushes.

Brush work is generally quick. What you're looking for are ways to reduce a number of brushes in a map. If you find a spot in hammer that has a typically large amount of brushes in one area

such as this

You can reduce the amount of pointless brushes and replace it with one brush. First off, it'll reduce the number of brushes and brushsides the map has, thus reducing compile time.

Second, is another thing called 't-junctions'. If a map has too many t-junctions (when two brushes come up against another brush forming a 'T'), the compiler won't compile. So, just remove those brushes and replace it with a bigger one.

like that

Pretty simple.


I usually save this for last. Remember when I said 'we'll be adding our own cubemaps later?'. Well, this is later.

Env_cubemap is the entity. If the map has ANYTHING reflective...reflective textures, water, glass, you'll want to put an env_cubemap near it. An env_cubemap can render shiny textures reflective within up to (128x128)x6 units away, although default is (32x32)x6. So anything within that distance of a env_cubemap will be rendered reflective.

So, plonk your cubemaps down and let's move on.

clean as a whistle...shines like one, too.

Now that's all said and done, you want to have your first compile. Excited enough to rush through it and surf the ever loving shit out of, we bust out the big daddy of compilers....VBCT.

Have you been saving your map during your progress? Save it again. Just in case.

Once VBCT is installed, start it up. You'll see a box on it saying 'Launch sdk' Uncheck that first. SDK's useless now, remember? Don't need to start it up to compile. Then, right click the '...' button and select Team Fortress 2. Up in the top left, Open File. Select the map, then you have 3 different options for compiling:

Fast...usually used to test cordoned sections or very basic maps. Not used for playing.
Full...Used for alpha testing maps, lighting and visleafs of a map. A bit better render than fast.
Final...this is used when everything's in place and you're ready to release the map into the public. Obviously takes the longest.

This thing is a beast.

If everything's fully optimized, Final shouldn't take more than 10 minutes to finish. If it does, then you need to go back into hammer and find out what needs fixing...lightmaps, detailing, etc.

After the map is done compiling, you need to pack all the textures back into it that you ripped out of it at the beginning with GCFScape. (DO NOTE: You MUST be logged into Steam in order for VBCT to compile!)

You can use one of two things for this, either pakrat or packbsp. I use pakrat only because I can't get packbsp to work on my computer, so that's what I'll be showing today. There's also a program out there called VIDE, but I spent a couple hours on it and still have no fucking clue how to use it. If you can figure it out, then by all means..use it. This all boils down to personal preference.


After you compile, you now have your ported .bsp. BUT! It's STILL not ready yet. If you use it now, you won't have any textures when you test it out. So, now we pack 'em back in.

Open your packer (in this case, I'm using pakrat). It'll look something like this:


You'll notice you won't have a whole lot of items in there. That's an easy fix. Just click 'auto' down at the bottom, and it will scan your tf folder for anything the map requires for use (textures, models, sounds, scripts, etc.).

If anything's missing (which will happen from time to time), then just click 'add' and hunt down the textures by hand. Remember the original copy we saved before we started all this? You can use GCFScape to rip the textures back out into your tf folder again and try scanning again to make sure everything's in there that's supposed to be.

Once all that's said and done, save your .bsp and load it in game and have a test run!


We're STILL not done yet. Yeah, your port is awesome. It's lag free, pretty as hell, surfs as smooth as ice...but where's the shiny shit?

Now we build cubemaps.

Start up tf2, but don't load a map yet. Now for the fun stuff, I'm guessing you have a basic knowledge of using the console. But once you start up TF2 you just simply enter in the following commands in your 'console' without the -'s and you will successfully and properly build cubemaps for your map which will give you proper reflections on windows, water and anything else shiny. AS WELL AS getting rid of all the purple checkerboards.

-mat_specular 0
-map <mapname>(Load your map)
-mat_specular 1
-map <mapname>(Load a different level; clears texture cache)
-map <mapname>(Load you map again

And voila! A new, healthy, shiny, freshly ported map! Bring friends in to test it out first....test the shit out of it. Make sure everything is where it's supposed to be, how it's supposed to look and most of all...make sure it's surfable in tf2.

Common problems:

During your working process in hammer, you should check out the error reporter by either going up to the menu and selecting it, or pushing alt+p. A window will pop up with all the errors of the map. Some of the more common ones include:

There is no player start!

This can safely be ignored. A player_start entity is mainly used for singleplayer games where maps were tended for one player. On multi-player maps such as surf maps, you have the teamspawn entity to spawn players into a map.

Brush is missing (such and such texture)

There was probably a problem when you ripped the textures out of the map before you decompiled. Save the map, close hammer, open up GCFScape and re-rip the textures. Once that's said and done, open hammer back up and they should be there.

Entity has bad I/O connections:

You'll see this quite often on maps with quite a few trigger_multiples. The I/O connections is a command system, practically linking one entity to another through a series of commands. I.E., as you pass through a trigger_multiple, it may play a sound or attach a trail to you. These can usually be ignored because the I/O system doesn't usually activate until a player triggers it somehow....unless it's connected to an entity with the wrong name or a missing entity. Then you should check into it and see if you can rename or replace the entity...or even delete the trigger itself without serious repercussions.

There is a leak in the map

This happens during compiling. There's an entity in your map that's leaking out into the void. (The black area on the grid surrounding your map). This happens because your outside walls don't make a perfect matter how miniscule it is. If this error happens, go back into hammer, up top click view then 'load pointfile'. A red line will show up in hammer detailing what entity is leaking and where it's leaking from. Seal the leak, resave and recompile. Also note, that if a trigger hangs outside of the map, it will cause a leak as well.

A very big thanks goes out to Kelao for the inspiration and a buttload of information. Thanks also go out to Felix and Egan for all the help they've given me over the past year.

This bitch took me 4 hours to write. I'm going to bed.

If you have any questions about mapping or porting or anything related to hammer, hit me up.
Last edited by Nastybutler on Mon Jan 13, 2014 3:23 am, edited 1 time in total.
[Owner] -DB!- tordana: meet me in the playground after school
User avatar
[pfN] big blue
Posts: 211
Joined: Sun Jan 12, 2014 9:52 pm
Location: East TX

Re: Converting maps from CSS to TF2

Post by [pfN] big blue » Mon Jan 13, 2014 2:21 am

User avatar
Site Admin
Posts: 281
Joined: Tue Nov 05, 2013 1:43 am

Re: Converting maps from CSS to TF2

Post by tordana » Mon Jan 13, 2014 4:21 pm

Holy guide batman. This is awesome.
User avatar
Posts: 572
Joined: Sun Jan 12, 2014 7:40 am
Location: St. Louis, MO

Re: Converting maps from CSS to TF2

Post by Nastybutler » Tue Jan 14, 2014 1:37 am

tordana wrote:Holy guide batman. This is awesome.
These are the basics I have to go through with

There's plenty of other problems that occasionally come up as well, but I didn't have the patience to write down every single detail.

As I said before, if anybody has any questions, just hit me up.
[Owner] -DB!- tordana: meet me in the playground after school
User avatar
Posts: 28
Joined: Sun Jan 19, 2014 6:23 pm

Re: Converting maps from CSS to TF2

Post by streebree » Sun Jan 19, 2014 6:29 pm

Thanks for making this, Butler. This is a godtier guide.
User avatar
Posts: 159
Joined: Sun Jan 12, 2014 3:05 pm

Re: Converting maps from CSS to TF2

Post by elfman______________ » Thu Jan 23, 2014 11:15 pm

be sure to keep the maps looking similar to how they did in css.

you can also add timer support when porting the map

for staged maps add trigger_multiple boxes around the start of stages stagex_start and the ends of stages stagex_end (x being the stage number obv)

for linears add a trigger_multiple box around map start and name it start_zone and at the end of the map a box named end_zone
you can add checkpoints to linears by making boxes named checkpoint_x

bonuses can be added by making bonusx_start boxes at the start and bonusx_end boxes at the end

be sure not to make startzones too close to boosters or they'll make the boosters not work (see pandemonium and sw2 bonuses)

you can make more acurate zones in hammer but its not really worth doing if you already have a final compile done (best added in the middle)
User avatar
Site Admin
Posts: 281
Joined: Tue Nov 05, 2013 1:43 am

Re: Converting maps from CSS to TF2

Post by tordana » Fri Jan 24, 2014 3:05 pm

It's worth noting that if you need a stage to allow bunnyhops or telehops for whatever reason, name it "stage4_start TH"
User avatar
Evil MrMuffinz
Posts: 151
Joined: Tue Jan 21, 2014 10:30 pm
Location: north mrica KNOW WHAT IM SAYING?

Re: Converting maps from CSS to TF2

Post by Evil MrMuffinz » Sun Jan 26, 2014 12:21 am

gj butlerImage klappas are the best
User avatar
Posts: 572
Joined: Sun Jan 12, 2014 7:40 am
Location: St. Louis, MO

Re: Converting maps from CSS to TF2

Post by Nastybutler » Sun Jan 26, 2014 2:54 am

elfman______________ wrote:be sure to keep the maps looking similar to how they did in css.

you can also add timer support when porting the map

for staged maps add trigger_multiple boxes around the start of stages stagex_start and the ends of stages stagex_end (x being the stage number obv)

for linears add a trigger_multiple box around map start and name it start_zone and at the end of the map a box named end_zone
you can add checkpoints to linears by making boxes named checkpoint_x

bonuses can be added by making bonusx_start boxes at the start and bonusx_end boxes at the end

be sure not to make startzones too close to boosters or they'll make the boosters not work (see pandemonium and sw2 bonuses)

you can make more acurate zones in hammer but its not really worth doing if you already have a final compile done (best added in the middle)

The reason why I didn't write any of this down is because it's exclusive to our timer. Every other skillsurf timers have their own commands and variables to work with. What I wrote was just a generalization.

But handy info to use for Resurfed none-the-less.
[Owner] -DB!- tordana: meet me in the playground after school
User avatar
Posts: 50
Joined: Thu Jan 30, 2014 4:32 am
Location: Paris, France

Re: Converting maps from CSS to TF2

Post by Rms » Tue Feb 18, 2014 5:22 am

Good job Butler, very good tutorial. Covers all the process and you made it understandable for noobs like me

Post Reply