cs2asset
Import textures, HDR skies, and 3D models into Counter-Strike 2 Hammer.
cs2asset converts common asset formats into Source 2 resources, runs Valve's compiler, and installs the result directly into a selected CS2 addon.
Assets can come from local files, Poly Haven, or ambientCG. Poly Haven supports materials, HDR skies, and models; ambientCG supports PBR materials.
Features
- Import PBR texture sets as CS2 materials
- Import
.blend,.glb,.gltf,.fbx, and.objmodels - Import
.hdrand.exrpanoramas as HDR skies - Search and import assets directly from Poly Haven and ambientCG
- Generate editable Source 2 source files and compiled resources
- Automatically discover CS2 Workshop Tools, Blender, and addon projects
- Rebuild previously imported assets without changing their Hammer paths
- Create experimental two-layer environment blend materials
- Keep generated assets organized in dedicated
cs2assetdirectories
Setup
You'll need Counter-Strike 2 with Workshop Tools installed and Blender.
Blender is used internally for conversion and inspection, including the model pipeline and other asset-processing tasks.
The examples in this README use uv, but cs2asset is a normal Python package and does not depend on uv specifically.
Run the published package directly without cloning this repository:
uvx cs2asset --help
Check that cs2asset can find CS2, Valve's tools, Blender, and your addons:
uvx cs2asset doctor
Then select the addon you want to import assets into:
uvx cs2asset init
init remembers the selected addon for future commands.
Create new addons through CS2 Workshop Tools before selecting them in cs2asset.
Quick start
Windows right-click import
Register Import into CS2 Hammer for supported model files, HDR/EXR skies, and PBR texture ZIP archives:
uvx cs2asset context-menu add
uvx cs2asset context-menu status
uvx cs2asset context-menu remove
Registration applies only to your Windows user and does not require administrator access or change default file associations. On Windows 11, use Show more options. Select one file at a time. The importer uses your saved addon, or prompts you to choose one, and keeps the console open until you press Enter after the import.
The entry uses an absolute path to uv.exe to run the published cs2asset package,
not a temporary Python environment. If uv is not on PATH, use
context-menu add --uv "C:\path\to\uv.exe". Run add again if you move uv.
When testing an unreleased checkout, Explorer still runs the published package;
the published version must include these commands before the entry can be used.
Import local assets:
uvx cs2asset import .\assets\mossy_rock.glb
uvx cs2asset import .\assets\forest_ground\
uvx cs2asset import .\assets\sunset.hdr
Or import directly from Poly Haven:
uvx cs2asset import polyhaven:concrete_floor_01 --resolution 2k
uvx cs2asset import polyhaven:sunset_jhbcentral --resolution 4k
uvx cs2asset import polyhaven:dirty_football --resolution 2k
Or import a material directly from ambientCG:
uvx cs2asset import ambientcg:Grass005 --resolution 2k
After an import, cs2asset prints the final Source 2 resource path. Use that path directly in Hammer's Asset Browser.
An already-open Hammer session may need an Asset Browser refresh before newly imported resources appear.
Using Poly Haven
Poly Haven is the easiest way to get usable materials, HDRIs, and models into Hammer without manually downloading and converting files.
Search for assets from the CLI:
uvx cs2asset search "forest ground" --provider polyhaven
uvx cs2asset search "mossy rock" --provider polyhaven --type models
uvx cs2asset search "sunset" --provider polyhaven --type hdris
Then import an asset by ID:
uvx cs2asset import polyhaven:forest_ground_04
uvx cs2asset import polyhaven:dirty_football
uvx cs2asset import polyhaven:sunset_jhbcentral
You can also paste a Poly Haven asset URL directly:
uvx cs2asset import https://polyhaven.com/a/concrete_floor_01
Inspect what will be imported before doing anything:
uvx cs2asset info polyhaven:concrete_floor_01
Choose a resolution:
uvx cs2asset import polyhaven:concrete_floor_01 --resolution 1k
uvx cs2asset import polyhaven:concrete_floor_01 --resolution 2k
uvx cs2asset import polyhaven:sunset_jhbcentral --resolution 4k
Default Poly Haven resolutions are:
- 2K for textures
- 2K for models
- 4K for HDR skies
If a requested resolution does not exist, cs2asset reports the available choices.
Once imported, the asset behaves like any other local cs2asset import and can be listed or rebuilt:
uvx cs2asset list
uvx cs2asset rebuild IMPORT_ID
Cached Poly Haven assets can also be rebuilt offline:
uvx cs2asset rebuild IMPORT_ID --offline
Poly Haven assets are CC0.
Using ambientCG
ambientCG provides PBR materials that can be downloaded and imported directly into Hammer.
Search for materials from the CLI:
uvx cs2asset search "grass" --provider ambientcg
Then import a material by ID:
uvx cs2asset import ambientcg:Grass005
You can also paste an ambientCG asset URL directly:
uvx cs2asset import https://ambientcg.com/a/Grass005
Inspect the selected download before importing:
uvx cs2asset info ambientcg:Grass005
Choose a resolution:
uvx cs2asset import ambientcg:Grass005 --resolution 1k
uvx cs2asset import ambientcg:Grass005 --resolution 2k
The default resolution is 2K. The importer prefers PNG packages and falls back to JPG at the requested resolution. If that resolution is unavailable, it reports the available packages.
Once imported, materials can be listed and rebuilt like other imports:
uvx cs2asset list
uvx cs2asset rebuild IMPORT_ID
Cached ambientCG materials can also be rebuilt offline:
uvx cs2asset rebuild IMPORT_ID --offline
Use the ambientcg: prefix or an ambientCG asset URL; bare asset IDs default to
Poly Haven. ambientCG support currently covers materials.
ambientCG assets are CC0.
Supported inputs
cs2asset normally detects the asset type automatically.
| Input | Imported as |
|---|---|
.blend |
Model |
.glb |
Model |
.gltf |
Model |
.fbx |
Model |
.obj |
Model |
.hdr |
HDR sky |
.exr |
HDR sky |
| Texture directory | Material |
| Texture ZIP | Material |
polyhaven:ID |
Poly Haven asset |
| Poly Haven asset URL | Poly Haven asset |
ambientcg:ID |
ambientCG material |
| ambientCG asset URL | ambientCG material |
You can require a specific asset type with:
uvx cs2asset import SOURCE --type material
uvx cs2asset import SOURCE --type model
uvx cs2asset import SOURCE --type sky
Materials
A directory containing a recognizable PBR texture set can be imported directly.
For example:
rock/
├── rock_albedo.png
├── rock_normal.png
├── rock_roughness.png
└── rock_ao.png
Import it with:
uvx cs2asset import .\rock\
Supported texture names include:
| Map | Common names |
|---|---|
| Base color | basecolor, base_color, albedo, diffuse, color, diff |
| Normal | normal, normalgl, normaldx, nor_gl, nor_dx, nrm |
| Roughness | roughness, rough |
| Metalness | metallic, metalness, metal |
| Ambient occlusion | ao, ambient_occlusion |
| Height | height, displacement, disp |
| Opacity | opacity, alpha |
| ARM / ORM | AO, roughness, and metalness in R/G/B |
A base-color texture is required.
Generic names such as normal and nrm are treated as OpenGL normal maps by default. Explicit GL and DirectX names are detected automatically.
You can specify the convention for generic normal filenames:
uvx cs2asset import .\rock\ --normal-format dx
Local folders and ZIP packages can contain both DirectX and OpenGL normal maps
for the same material. The importer selects OpenGL when both exist and detects
DirectX when it is the only variant. Duplicate maps of one convention and mixed
texture sets still produce an ambiguity error. Explicit NormalGL/NormalDX
filenames determine conversion; --normal-format dx is a hint for generic
normal filenames with no declared convention. Selected normals are reported in
choices and warnings, and DirectX inputs are converted to OpenGL once.
Materials use CS2's csgo_complex.vfx shader.
Missing optional maps use constant values rather than preventing the material from being imported.
Packed ARM/ORM maps are supported when their layout is known.
Models
FBX embedded images are extracted into the build workspace. Missing external images
are resolved against the model directory and its .fbm folder; ambiguous filenames
produce an error. Textures must be connected to supported material shader inputs.
Supported formats:
.blend
.glb
.gltf
.fbx
.obj
Example:
uvx cs2asset import .\assets\mossy_rock.glb
cs2asset uses Blender to inspect and convert the source before generating the Source 2 model resources required by Hammer.
Static meshes, UVs, materials, supplied LODs, and basic collision are supported.
By default, a simple convex collision hull is generated. Collision can be disabled:
uvx cs2asset import .\assets\rock.glb --collision none
A different scale can also be supplied:
uvx cs2asset import .\assets\rock.glb --scale 1.0
Rigged models are currently imported as static snapshots of their evaluated pose.
HDR skies
HDR and EXR panoramas can be imported directly:
uvx cs2asset import .\assets\sunset.hdr
You can adjust yaw and exposure during import:
uvx cs2asset import .\assets\sunset.hdr --yaw 90 --exposure -1
The generated sky material can be assigned to env_sky in Hammer.
The panorama provides the visual sky and environment data. Map-specific lighting such as sun direction and brightness is still configured in Hammer.
Projects
List discovered addons:
uvx cs2asset projects list
Select one:
uvx cs2asset projects use de_example
You can also specify the project for an individual import:
uvx cs2asset import .\assets\rock.glb --project de_example
For scripts or other non-interactive environments:
uvx cs2asset init --project de_example
Non-interactive commands do not stop to ask for project selection.
For the complete command and argument list, see the CLI reference.
Common commands
# Check the local setup
uvx cs2asset doctor
# Select an addon
uvx cs2asset init
# Import an asset
uvx cs2asset import SOURCE
# Inspect an asset
uvx cs2asset info SOURCE
# Search online providers
uvx cs2asset search "QUERY" --provider polyhaven
uvx cs2asset search "QUERY" --provider ambientcg
# List installed imports
uvx cs2asset list
# Rebuild an existing import
uvx cs2asset rebuild IMPORT_ID
# Show configuration
uvx cs2asset config show
# Show help
uvx cs2asset --help
Some useful import options:
uvx cs2asset import concrete_floor_01 --resolution 1k
uvx cs2asset import concrete_floor_01 --tiling 2
uvx cs2asset import concrete_floor_01 --surface concrete
uvx cs2asset import dirty_football --collision none
uvx cs2asset import sunset_jhbcentral --yaw 90 --exposure -1
Dry runs
Resolve an import without converting, compiling, or installing anything:
uvx cs2asset import concrete_floor_01 --dry-run
This is useful for checking the selected source, detected asset type, options, project, and expected output paths.
Rebuilding assets
Previously imported assets can be rebuilt while keeping their existing Hammer resource paths:
uvx cs2asset rebuild IMPORT_ID
Local imports normally reread the original source files.
To rebuild from the retained input snapshot instead:
uvx cs2asset rebuild IMPORT_ID --cached-inputs
Cached provider assets can be rebuilt offline:
uvx cs2asset rebuild IMPORT_ID --offline
Use cs2asset list to find import IDs.
Environment blends
Experimental
cs2asset can create two-layer Hammer materials using csgo_environment_blend.vfx.
Local materials:
uvx cs2asset blend create `
.\materials\forest_ground `
.\materials\rock `
--name forest_rock
Poly Haven materials:
uvx cs2asset blend create `
polyhaven:forest_ground_04 `
polyhaven:rock_face_03 `
--name forest_rock
Local and online sources can also be mixed:
uvx cs2asset blend create `
.\materials\rock `
polyhaven:forest_ground_04 `
--name mixed_ground
The resulting material can be applied to suitable Hammer geometry and painted using Hammer's blend tools.
The current implementation supports two layers. Extra layers, custom transition controls, and cutout/blended transparency are not yet supported.
Configuration
Show the current configuration:
uvx cs2asset config show
Set a user default:
uvx cs2asset config set resolution 1k
Set a project-specific value:
uvx cs2asset config set surface concrete --project de_example
Configuration precedence is:
command line
↓
project configuration
↓
user configuration
↓
automatic discovery
Useful environment variables:
CS2ASSET_CONFIG_DIR
CS2ASSET_CACHE_DIR
CS2ASSET_CS2_ROOT
CS2ASSET_BLENDER
Custom tool locations can also be provided directly:
uvx cs2asset `
--cs2-root 'D:\SteamLibrary\steamapps\common\Counter-Strike Global Offensive' `
doctor
uvx cs2asset import dirty_football `
--blender 'C:\Program Files\Blender Foundation\Blender 5.1\blender.exe'
Generated resources
Editable Source 2 resources are installed into the selected addon's content tree.
Compiled resources are installed into the corresponding game tree.
Generated assets are organized under:
materials/cs2asset/
materials/skybox/cs2asset/
models/cs2asset/
This keeps imported resources separate from manually created addon assets.
Resource filenames use the asset name, so Hammer displays names such as
lifebuoy.vmdl, lifebuoy.vmat, and snow_road.vmat instead of model.vmdl
or blend.vmat. Provider/asset/variant folders still separate sources and settings.
A model with one material puts its named VMAT directly in its material variant
folder; several materials use names such as lifebuoy_rope.vmat in separate folders.
Rebuild older imports to get these names. Previously owned generic resource paths
remain as editable and compiled compatibility copies, preserving existing map
references. New imports do not create these copies. The manifest records them in
resource_aliases.
Valve compiler warnings appear in terminal/JSON output and the manifest's combined
warnings list. compiler_warnings records each warning's resource, message, and
log path. Warnings remain visible after an unchanged dependency check and clear
after a clean rebuild.
cs2asset also retains the information needed to rebuild previously imported assets.
Limitations
Current limitations include:
- Models are imported as static geometry
- Skeletal animation is not exported
- Rigged models are imported as static evaluated poses
- Physics-prop setup is not generated
- Collision is limited to a simple convex hull
- Automatic LOD generation is not implemented
- Procedural Principled material inputs require
--bake-materials - Unsupported or non-standard material graphs may require manual preparation
- Multiple UV channels on the same mesh require baking
- Compatible affine UV mappings are applied to mesh UVs; conflicting mappings require baking
- Material opacity uses alpha testing rather than blended transparency
- Displacement/parallax is not currently generated
- Environment blends are experimental
- HDR sky imports do not configure map-specific sunlight
Where possible, unsupported inputs result in an explicit conversion error rather than silently generating an incorrect asset.
Development
Clone the repository and install its development dependencies:
uv sync --locked
uv run cs2asset --help
Run the test suite:
uv run pytest -q
uv run ruff check src tests scripts
Run integration tests against locally installed CS2 and Blender tools:
$env:CS2ASSET_INTEGRATION = '1'
uv run pytest -q
Build the package:
uv build
Installation
Install from PyPI with uv:
uv tool install cs2asset
Then use cs2asset directly:
cs2asset doctor
cs2asset init
cs2asset import .\assets\rock.glb
You can also install the package using another Python package manager if preferred.
To run directly from the repository without installing:
uvx --isolated --from . cs2asset --version
To run the published package without installing a persistent command:
uvx cs2asset doctor
To upgrade a persistent installation, run uv tool upgrade cs2asset.
Releases
The .github/workflows/publish.yml workflow tests, builds, and publishes to PyPI
when a v* tag is pushed. The tag must match both versions in pyproject.toml
and src/cs2asset/__init__.py.
Before the first release, configure a pending Trusted Publisher in your PyPI account with these values:
- Project name:
cs2asset - GitHub owner:
gronnmann - Repository:
cs2asset - Workflow filename:
publish.yml - Environment:
pypi
For each release, update both package versions, run uv lock, commit the changes,
and push the branch and matching tag:
git push origin master
git tag -a v0.2.1 -m "Release 0.2.1"
git push origin v0.2.1
Use the new version number for subsequent releases. PyPI versions cannot be reused.
License
See LICENSE for the license of cs2asset.
Assets imported through cs2asset retain their original licenses. Poly Haven and ambientCG assets are CC0.
Models with multiple objects and mapped materials
One source file produces one model by default. Inspect the source before selecting or splitting it (inspection downloads dependencies but does not compile or install):
cs2asset model-list https://polyhaven.com/a/fir_sapling_medium
cs2asset import trees.blend --object TreeA
cs2asset import trees.blend --collection TreeA
cs2asset import trees.blend --split collections --origin center
cs2asset import props.blend --split objects
cs2asset import trees.blend --bake-materials --bake-resolution 2048
Selection uses exact names. Object selection includes its descendants and matching
named LOD siblings. Object splitting starts with visible objects without an LOD
suffix or with LOD0. Collection splitting uses top-level scene collections, keeping
nested collections and LODs together. Hidden render objects are excluded. Each
split group has its own model and material resources, recorded in one import so
rebuilding repeats the same selection. Materials are currently generated separately
for each split group. --origin source preserves source coordinates; center
centers each model's LOD0 bounding box and applies that offset to all its LODs.
Compatible constant Mapping nodes are applied directly to exported UV coordinates.
Named UV maps and corner vector UV attributes are supported. Conflicting texture
mappings, procedural coordinates, and rotation/reflection with tangent normal maps
require explicit baking. --bake-materials bakes linked base color, roughness,
metalness, opacity, and tangent normal inputs from a Principled BSDF onto the active
UV layout. Resolution accepts 16–8192 pixels. Baking does not unwrap meshes:
overlapping UVs must represent compatible surface values, and UV islands must fit
the texture tile. A mixed surface with one connected Principled shader can bake that PBR component;
additional translucent/additive lobes are omitted and reported. Surfaces without a
unique connected Principled shader remain unsupported.
Metadata
Release files for cs2asset 0.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cs2asset-0.3.3.tar.gz | 67.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cs2asset-0.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 147.8 kB
Release files / cs2asset-0.3.3.tar.gz
| Download URL | cs2asset-0.3.3.tar.gz |
|---|---|
| Size | 67.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9da7da1760de08610b19697a3b21f07e6147d568b3747c73b02418bd3d32001b
|
|
BLAKE2b-256 checksum How to use checksums |
c9b1a0c22fe7243c68ed59612002de12c63d1efd310a0000dc93afe8c1306982
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / cs2asset-0.3.3-py3-none-any.whl
| Download URL | cs2asset-0.3.3-py3-none-any.whl |
|---|---|
| Size | 80.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77880850c2a1179a5e2378160d9d5205e9267315e533bf159bd9c996c47f969f
|
|
BLAKE2b-256 checksum How to use checksums |
24414e2234381ccd415d6ba6d10d391519ce12ff35e75366a7f167313eaf6116
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log