How Environment Art for Counter-Strike 2 Map Sanctum Was Made
3D Environment Artist Twist, one of the creators of the Counter-Strike 2 map Sanctum, discussed the development of environment art, custom tools, and key artistic decisions.
Making Environment Art for Sanctum
Sanctum is a competitive Counter-Strike 2 map in a lush jungle around an ancient temple under restoration. It mixes real historical architecture with fresh creative ideas for great visuals and gameplay.
The map was added to the official CS2 competitive map pool on January 22, 2026, after months of teamwork by level designers, environment artists, and digital artists. This article covers the development process of environment art, custom tools I've built, and key art decisions.
A bit about me, Twist: I'm an Environment Artist with experience in game engines like Unreal, Unity, plus rendering for stills and cinematics in Vray and Octane. I also built Hammer5Tools, which is a pack of utilities to speed up CS2 map workflows. It grew during Sanctum to fix real issues.
My Contribution to the Project
Ruban started the project as owner and level designer. I came later and took over visuals and led production, tweaking layouts for smooth visuals. My main responsibilities: setting and building the full art vision, creating key assets and materials, producing most of the final content, overseeing textures, lighting, and consistency, helping tweak layouts and gameplay, and developing Hammer5Tools for the workflow.
Creative Direction & Concept
When I joined the project, the theme was already set, but the geometry wasn't final, so we could still tweak the setting. Similar jungle-temple maps already existed in the CS2 Workshop, making ours feel unoriginal, risky, and expensive at the same time. Switching themes would've meant rebuilding the whole layout, so we kept the idea and location.
Jungle-temple maps are common in Counter-Strike 2, but I wanted a unique take instead of copying others. Main inspiration: Cambodia's Angkor Wat, one of the world's most famous temples. We couldn't copy it exactly, though it's a sacred Buddhist site that demands respect to avoid issues.
So I stylized the map. It captures Angkor Wat's feel and mood without being photorealistic. I changed and reinterpreted the architecture, avoided religious sculptures and patterns, modified towers to reduce similarity, and focused on stylization over exact history.
Level Design
While the original layout and basic shape of the level were given to me, I made significant changes to the level design related to visuals. It all started around August 2024.
The first pass was more like a draft. It might seem like all the shapes are the same, but they're not. I spent a huge amount of time playtesting this map along with a couple of good friends: syncope, g3om, and more.
The main reasons were architecture and gameplay polishing. The main goal was to create an existing, real temple that could exist in real life, while ensuring we didn't break the gameplay, geometry, or other elements. The main challenge in architecture was to create symmetric geometry for houses and buildings.
Along with gameplay and architectural buildings, I worked to create beautiful visual ideas on the map. For instance, this tree was inspired by real trees growing in Angkor Wat. The tree model was shaped by rainless and finished by me.
During work on the level design, I was inspired to create a program that could help with playtesting and analyzing players' movements and behavior on the map.
Actually, it wasn't as helpful as I thought at the time of creating it. But some people in the Counter-Strike 2 level design community found this tool helpful, so I'm glad to contribute to the CS2 mapping community!
At the end of 2024, I finally accomplished what I was satisfied with for most of the geometry, both from gameplay and visual perspectives. It was still far from final, but no major gameplay changes were needed in the next passes of developing this map.
In this screenshot, you might see beautiful unique ivy generation which covers the tower; it was created by Rainless. You might also see some props and materials already there. That's because I wanted to create a good general look and then dig into the detailing of the level. During this stage, the visual art direction was established too.
The visual changes and art direction evolved along the way, but at least gameplay was finished. I adjusted the visuals to the initial layout geometry and created a playable map already with draft visuals.
Visual
The visual work happened in several passes, with playtests and ideas linked closely, making it hard to pinpoint the biggest changes. In general: place rough elements on the map, playtest, clean it up, playtest again, then fix issues, sometimes scrap and restart spots from scratch.
Once satisfied with the ideas and composition, I moved to content creation. First, I finished one corner to set a quality reference for the map, more technical than artistic. It's often the best way to figure out what content the scene needs. Custom content is tough for me, yet 80% of the map uses it. The remaining 20% consists of third-party assets, such as those from Dekogon or from the standard Counter-Strike library. At the end, time pressure forced third-party assets, but I integrated them, fixed technical issues, and relabeled some for a unique look.
Once most custom content was ready and no more grayboxes or dev materials were left, we moved to polishing. It's the shortest phase but most effective: you already have a complete product, needs finishing touches.
The special thing about this stage was the wall paintings and particles. I'm incredibly glad to have worked with the highly talented digital artist Gurin. He drew fantastic pictures with the theme of the map. All of them tell mini-stories linked to Counter-Strike, like planting the bomb, wingman mode, competitive play, and the volcano.
Digital Art
All paintings were made by our digital artist GURIN.
The goal was to capture the feeling of Angkor Wat without copying it directly. At first, the idea was to recreate paintings from the Angkor Wat temple and adapt them to the CS2 setting.
However, we dropped that approach early in development because I didn't want to risk problems caused by too much similarity to a real-world location.
Even small elements were changed or censored late in production.
It was a huge amount of work, and I'm truly grateful to GURIN, who worked on these paintings throughout the project's development.
Once all wall paintings were done, I processed them with Substance 3D Designer and added some details.
Along with wall paintings, he also drew some graffiti from the famous map Overpass as an easter egg, but with some adaptation to the theme.
Particles
Particles and the volcano: In the Counter-Strike 2 mapmaking community, no one had done such a thing before, and it was complicated to create. Explosions are the simplest part; it's easy to make them. Nothing hard there. But the lava flows… I tried different methods, such as shader animation, mesh animation, and morphing. But none of them could give a decent look and performance. Particles were the only way, and I would say it wasn't as simple as it might seem.
First, I thought there was a way to calculate particles' collision with the volcano mesh. And that worked perfectly with one small nuance: it didn't work on the 3D skybox.
Explanation for those who haven't worked with the Source 2 engine:
A 3D skybox is another map that always runs on top of your root map. This map can have geometry such as mountains, etc. This allows us to create decent fog and split lightmap resolution. And there are some technical reasons for it, of course: the map size limit. You can't create a large open-world map in Source 2; you need to fit the limits. Those are reasons why, in Source 2, we use a 3D skybox in combination with the skybox.
The possible solutions were: bringing the volcano from the skybox to the root map, but in this case, I would lose the fog effects applied to that mesh, plus performance reasons.
Now I know I could use a vsnap file, which stores dedicated particle positions. But even now, I'm struggling to create and use them, and I'm not sure it would be possible in this case.
Eventually, I found the solution! It was about using a weird system of bone animation and particle systems in combination. The lava flow particle uses its previous position to set the end point, and the start point is the spawn point. Then, over time, it modifies, changes color, and shape.
Using Blender and its gorgeous tools for creating animations with curvatures, I created lava flow lines and bones for each of them. Some lava flows start at the beginning of the eruption, some later, creating lava flow splits.
The result in the game
Source 2 has an awesome graphical feature: volumetric light. But in the CS2 branch, this feature was disabled. I found a solution to fake this effect by using custom particles.
Content Creation
The special thing about this project is that almost everything on the map must have a unique texture set to have good shading. Along with rainless, we made all necessary production assets and kept completing and adding new ones during the process.
Assets
For the architecture pieces, rocks, and blocks, I used ZBrush to sculpt. First, I got the right shapes and dimensions in the Source 2 World Editor itself, then exported them into Blender. By using the BlenderToZBrush add-on, I loaded them into ZBrush for sculpting and back via GoZ. After that, I did a little decimation for the high-poly meshes because there's no reason to use a 15-million-polygon model when you can get almost the same result with a 1-million-polygon model.
To create low-poly meshes, I used a higher decimation percentage and then created UVs. It was tricky because of shading issues with objects like that. You can't actually create a clean normal map without compensations and with good polycount. So it's a balance between correct tech side and performance.
To create textures, I made a few custom base materials in Substance 3D Designer and then set up a smart material in Substance 3D Painter to quickly apply to new assets.
I'm happy with the result. The colors look strong, with good detail and material definition. They're slightly stylized, but the added noise and fine detail balance that out and keep the overall look realistic.
Tile Materials
For tile meshes and materials, even though I'm familiar with Substance 3D Designer and know how to build this material there, I don’t like that approach because the results can look lower quality. In many cases, it’s faster to sculpt the meshes manually and then texture them than to build the whole setup in Substance 3D Designer.
That said, Designer has its advantages, mainly the huge variety and flexibility. I don't need that much variation for this project. Another benefit of sculpted meshes is that they let me add real geometry on top of the material. Bricks that stick out from walls or floor pieces add depth and detail to the scene. The edges bake well, the shading holds up, and overall, this approach works better here.
Foliage
On this project, I barely touched SpeedTree, but I did, and it's fun, I would say. I like how you can manage trees by hand and assign vertex colors dynamically.
Smart Props
I was excited to work with the new tool for me, which is smart props. Almost every asset on the map has its own smart prop, whether simple or not.
If you are familiar with Unreal Engine, the most precise description of smart props would be limited blueprints focusing on content creation. These tools allow you to randomize the placement of objects, simplify using modular sets, and more!
I enjoyed this Source 2 feature, but the lack of existing tools for it led me to create my own. I chose Qt because it's the most powerful GUI framework (and the Source 2 Map Editor is created with this framework), and Python because I had no serious programming experience.
The project I called Hammer5Tools: “Hammer” stands for Source 2 Map Editor, and "5Tools" for the different utilities included: Loading Editor, Soundevent Editor, Smartprop Editor, AssetGroupMaker, and HotkeyEditor.
The idea of this whole project was to fill the gap of missing tools for Source 2. I'm sure Valve employees have these kinds of tools; there are even some icons in engine files. But for some reason, they don't publish them to the community.
The Source 2 content pipeline is split into two folders: content and game. Unlike Unreal Engine, which converts assets to its own format and then compiles them for use in the game, Source 2 does it differently: your source files must be in the content folder, and then Source 2 compiles them into its own format.
To define which file is which, there are a few file formats:
- Vmdl – stands for Valve Model.
- Vmat – stands for Valve Material.
- Vsmart – stands for Valve Smart Prop.
- Vtex – stands for Valve Texture.
Basically, these are the most often used formats, and all of them have non-binary formats (they can be opened via Notepad). So, editing them is not so difficult, but making a program to edit them is more complex.
I decided that making a full 3D viewport was overkill for me because it doesn't even make sense.
The first tool that was done is the Loading Editor; this tool provides features to create screenshots on the map and add loading screens along with icons and descriptions. It was the simplest tool, but I had to learn the basics of Python and Qt.
After a brief pause, I started to work on the Soundevent Editor. A soundevent is a description of how sound files should play, where, and how loud the volume should be.
But then I realized that my programming skills weren't enough to handle the KV3 format. As I said, it was my first programming experience, so making a custom parser for an in-house format was difficult.
At the same time, progress on Sanctum continued, and Rainless and I started making the content. Often, we needed a huge number of variations for the models, and importing all of them into the engine was slow… That was the time when AssetGroupMaker was born. To speed up the process of importing similar assets, I created this tool.
For instance, you have 200 models with different variations, but all their settings are the same except for a few. You create one file, which should be the reference for all others. The program will look at this reference file and update all those 199 files in real time. But if you have a few different models, you can add them to an ignore list. Also, you can filter input files by extension.
All configurations are stored in a file named %folder_name%.hbat.
The directory example would be like:
This tool was so helpful because you can't change attributes for multiple assets at the same time, like in Unity or Unreal Engine. And we had a lot of them! Actually, it works with almost everything that has a non-binary format.
Honestly, at that moment, I wasn't too familiar with the sounds in Counter-Strike 2 and Source 2 itself. But I found an already-done KV3 library for Python by kristiker. Right after finding the library, I started work on this tool, but it had a bit weird UI design and was badly designed from a code perspective. So, the question of rewriting the editor was always there.
After a post on X, a talented sound designer, bman, joined my Discord server, and I asked him to help with a new concept for the Soundevent Editor: how it should look for someone who works with sounds.
At the end of the discussion, we drafted the concept for the new editor design. I also mentioned that it would be cool to show one parameter able to control the volume of sounds at a distance. At that moment, I had no idea how I could reverse-engineer this function and implement it in the program. But bman said he had a friend who could help me with that.
Andrew900460 is a clever programmer who reverse-engineered the algorithm for calculating the Distant Volume Mapping Curve and helped implement it in the project.
“… I used Ghidra to inspect the cs2.exe and find the function that interprets the volume curve data. I'm not sure, but I think I also used Cheat Engine to figure out how the actual input data was stored after it was converted from the text file.”
“But if I did use Cheat Engine, I only used it in the CS2 instance that starts up when launching the modding tools; Never when launching the game normally.”
Finding the function wasn't easy, and once he found it, he had to make the decompiled C code into something a lot more readable in C++, then translate it to Python.
Right after I finished the first version of the Soundevent Editor, I started work on the Smartprop Editor, the tool I wanted the most. With some experience from the first version of the Soundevent Editor, I quickly designed the basics of the program, despite it being a way more complex editor than the Soundevent Editor.
Smart prop files are simply built; they're constructed of blocks: Element, Modifier, Selection Criteria. Elements can have children or be children to other elements. Modifiers and Selection Criteria are additional parameters to describe the functions of elements. Some elements cannot have children, like smartprop or model.
For each parameter, you can set a variable or expression.
It might look hard, but I insist it's simple to understand. So I started creating logic and widgets for all properties. During content creation, I also modified and updated the editor with new features. Finally, the Hotkey Editor, which is an editor for hotkeys in the Source 2 World Editor.
I'm glad to see my map in the official Counter-Strike 2 map pool. I did so much work and spent so much time accomplishing it all. And thanks to Ruban, who gave me the opportunity to show my environmental skills on his map.
Credits:
Twist – Steam, X, ArtStation
rainless – Steam, X
Ruban – Steam, X, ArtStation
GURIN – Steam
rastick – Steam