env-ViZDoom-turbo is a Python library for reinforcement-learning researchers who need fast, parallel ViZDoom environments. It provides a Gymnasium vector environment that can be used directly or selected as an isolated environment provider in GradLab.
Each vector lane owns an independent DoomGame. Lanes advance concurrently through ViZDoom's native API, while a bounded Rust worker pool applies max-pooling, crop, resize, grayscale conversion, frame-stack rotation, and final CHW/HWC layout in one GIL-free native call. Resize geometry and area-sampling tables are compiled once per environment instead of rebuilt per step.
Install
Install the published package from PyPI:
uv add env-vizdoom-turbo
To work from source:
git clone git@github.com:tsilva/env-ViZDoom-turbo.git
cd env-ViZDoom-turbo/turbo
uv sync --all-extras
Run Python and project commands through uv run.
Use
import gymnasium as gym
import numpy as np
env = gym.make_vec(
"env_vizdoom_turbo:EnvViZDoomTurbo-v0",
game="VizdoomBasic-v1",
num_envs=16,
num_threads=8,
obs_resize=(84, 84),
obs_grayscale=True,
obs_layout="chw",
frame_skip=4,
frame_stack=4,
use_restricted_actions="minimal",
)
try:
observations, infos = env.reset(seed=7)
actions = np.zeros(env.num_envs, dtype=np.int64)
observations, rewards, terminated, truncated, infos = env.step(actions)
done = terminated | truncated
if np.any(done):
observations, infos = env.reset(
options={
"reset_mask": done,
"state_indices": np.zeros(env.num_envs, dtype=np.int32),
}
)
finally:
env.close()
The module-qualified ID imports the package and registers the factory. This ID
is vector-only and requires an explicit game, which can be a canonical
registered Vizdoom... Gymnasium ID or a ViZDoom .cfg path.
EnvViZDoomTurboVecEnv remains available for direct use, and the existing
scenario-specific vector IDs remain registered for compatibility.
Crop or mask observations
The crop API matches the other turbo environments. obs_crop always contains
raw-screen edge widths in (top, bottom, left, right) order. With
obs_crop_mode="remove", those edges are removed before resize. With
obs_crop_mode="mask", the raw geometry is preserved and those edges are
replaced with obs_crop_fill before resize.
For example, the classic 320×240 Doom HUD occupies the bottom 32 pixels. This keeps the HUD enabled in ViZDoom while masking it out of policy observations:
env = EnvViZDoomTurboVecEnv(
"VizdoomBasic-v1",
vizdoom_config={"render_hud": True},
obs_crop=(0, 32, 0, 0),
obs_crop_mode="mask",
obs_crop_fill=0,
)
The 320×240-to-84×84 grayscale area-resize profile applies crop removal and masking directly in the indexed native pipeline, without an intermediate RGB frame conversion.
Frame-aligned info histories
Pass info_frame_stack_keys to request policy-transition histories whose depth
always matches the resolved frame_stack:
env = EnvViZDoomTurboVecEnv(
"VizdoomBasic-v1",
frame_skip=4,
frame_stack=4,
game_variables=["HEALTH", "ARMOR", "AMMO2", "SELECTED_WEAPON"],
info_filter={
"mode": "all",
"keys": ["health", "armor", "ammo2", "selected_weapon"],
},
info_frame_stack_keys=["health", "armor", "ammo2", "selected_weapon"],
)
For every selected key such as health, the existing current value and mask
remain infos["health"] and infos["_health"]. The opt-in history adds
infos["health_frame_stack"] with shape (num_envs, frame_stack) and
infos["_health_frame_stack"] with shape (num_envs,); a non-scalar signal's
trailing dimensions follow the history axis unchanged. Histories are ordered
oldest-to-newest. An ordinary reset repeats the reset value, a masked reset
changes only selected lanes, and every vector-environment step() shifts and
appends exactly once regardless of frame_skip. Terminal histories are
returned before reset, and live snapshots preserve continuation histories
exactly. These are policy-transition histories, not raw ViZDoom-tic histories.
Selected keys must be present in an info_filter with mode="all", available
on reset and every step, and unique. Unknown, unavailable, colliding, or
filtered-out selections fail during construction rather than falling back to
current-only values.
Augmented environments
Augmented variants use the <base>-Plus-v<version> naming convention.
VizdoomBasic-Plus-v1 preserves the canonical Basic scenario while sampling
one target appearance and one coordinated wall/floor/ceiling texture set per
lane on every reset:
env = EnvViZDoomTurboVecEnv(
"VizdoomBasic-Plus-v1",
num_envs=16,
enemy_variants={
"target": [
"original",
"basalt-furnace-sentinel-v1",
"verdigris-ram-hound-v1",
],
},
surface_variants={
"texture_set": [
"original",
"polar-bunker-v1",
"solar-shrine-v1",
"verdant-ruin-v1",
],
},
)
observations, infos = env.reset(seed=7)
print(infos["target_variant_index"])
print(infos["texture_set_variant_index"])
Transition infos stay numeric and portable. Resolve those indices through the
immutable enemy_variants and surface_variants catalogs, or use
active_enemy_variant_ids() and active_surface_variant_ids() outside the
transition path when human-readable IDs are needed.
Each non-original texture-set choice changes all three room surfaces together, so a lane cannot mix materials from different themes. Omitting either variant mapping samples uniformly from every catalog default.
VizdoomDefendLine-Plus-v1 preserves the canonical Defend the Line mechanics
while independently selecting one configured appearance for each enemy and
surface role in every vector lane on every reset:
env = EnvViZDoomTurboVecEnv(
"VizdoomDefendLine-Plus-v1",
num_envs=16,
enemy_variants={
"shooter": [
"original",
"basalt-furnace-sentinel-v1",
],
"fighter": [
"original",
"verdigris-ram-hound-v1",
],
},
surface_variants={
"wall": [
"original",
"basalt-blocks-v1",
"steel-panels-v1",
],
"floor": [
"original",
"dark-stone-v1",
],
"ceiling": [
"original",
"industrial-grid-v1",
],
},
)
observations, infos = env.reset(seed=7)
print(infos["shooter_variant_index"])
print(infos["fighter_variant_index"])
print(infos["wall_variant_index"])
print(infos["floor_variant_index"])
print(infos["ceiling_variant_index"])
Selection is uniform within each configured role, reproducible under
reset(seed=...), and driven by separate role RNG streams so it does not consume
gameplay, no-op, sticky-action, or another role's randomness. Omit
enemy_variants and surface_variants to use every role's catalog defaults. An
enemy_variants sequence remains a shorthand for configuring the shooter role
only. Masked resets resample selected lanes only. enemy_variant_roles and
surface_variant_roles, their read-only two-dimensional active-index arrays,
and the role-keyed active_enemy_variant_ids() and
active_surface_variant_ids() mappings expose the current choices.
The surface catalog also exposes three image-generated, coordinated sets through
the immutable surface_variant_themes mapping: polar-bunker-v1,
solar-shrine-v1, and verdant-ruin-v1. Each maps to matching wall, floor, and
ceiling ids generated as individual material sources with shared theme
references. Role selection remains independent, so configure each role with the
corresponding singleton id when a reset must use one intact visual theme.
In a GradLab environment config, declare the same list under
env_config.env_args.enemy_variants or env_config.env_args.surface_variants.
Reusable source frames, Doom patch lumps, manifests, proofs, and provenance live
under env_vizdoom_turbo/assets/enemy_variants/. Seamless 64×64 PLAYPAL surface
tiles, tiled proofs, prompts, manifests, and provenance live under
env_vizdoom_turbo/assets/surface_variants/. The packaged Plus WADs are built from
the editable scenario sources with:
uv run python scripts/build_basic_plus.py \
--acc /absolute/path/to/acc \
--acc-include /absolute/path/to/acc-source
uv run python scripts/build_defend_line_plus.py \
--acc /absolute/path/to/acc \
--acc-include /absolute/path/to/acc-source
New generated surface sources can be normalized into a compatible tile with
scripts/process_surface_variant.py; its manifest gate verifies opacity,
palette membership, exact dimensions, and measured wrap seams. The default
pipeline center-crops one material source and downsamples it directly to 64×64,
repairing only wrap axes that exceed the seam threshold. Legacy generated grids
remain supported through --grid-row and --grid-column; source and processed
comparison grids live with the editable Defend the Line Plus scenario sources.
Turbo Vector API v2
EnvViZDoomTurboVecEnv implements the strict Turbo Vector API v2:
metadata["turbo_api_version"]is2,metadata["transition_transport"]is"numpy", andmetadata["render_modes"]advertisesrgb_array.- Immutable
capabilitiesandsignal_schemadeclarations describe supported features and the dtype, shape, and reset/step availability of every signal.capabilities["supports_info_frame_stack"]advertises opt-in aligned info histories, and each generated history has shape(frame_stack, *original_shape)insignal_schema. buttons,action_mode,action_preset,action_table,action_meanings, andaction_table_hashexpose the resolved action semantics without provider-specific probing.state_catalogis an immutable ordered tuple. Callers select reset states with anint32state_indicesarray and inspect the read-only active indices withactive_state_indices(); state sampling and lane routing remain caller-owned.observation_ownershipandobservation_buffer_depthdeclare the exact lifetime of returned observations. Rendering is opt-in: withrender_mode="rgb_array",render_lane(index)renders one lane,get_images()renders all lanes, andrender()renders lane zero. With the defaultrender_mode=None, the first two methods returnNoneandget_images()returns oneNoneentry per lane.
Use with rlab
Install this distribution in the rlab runtime, then select its provider:
environment:
env_provider: env-vizdoom-turbo
env_config:
game: VizdoomBasic-v1
state: default
n_envs: 16
env_args:
num_threads: 8
use_restricted_actions: minimal
obs_grayscale: true
obs_layout: chw
frame_stack: 4
preprocessing:
frame_skip: 4
max_pool_frames: true
observation_size: 84
obs_resize_algorithm: area
task:
id: identity
action: {set: native}
signals: {}
events: {}
termination: {}
reward: {reward_mode: native}
Commands
uv sync --all-extras # install project and dev dependencies
uv run pytest -q # run Python and live-environment tests
uv run ruff check . # lint Python
cargo fmt --check # check Rust formatting
cargo clippy --all-targets --all-features -- -D warnings # lint Rust
uv build --wheel # build the distributable wheel
ENV_VIZDOOM_TURBO_PREBUILT_CORE=/path/to/vizdoom uv build --wheel
# package a validated optimized core
Install TurboBench 1.0.0:
uv tool install \
--exclude-newer-package turbobench-cli=2026-08-12T00:00:00Z \
turbobench-cli==1.0.0
Use its immutable vizdoom/basic-v1 profile for correctness-gated throughput
comparisons and public performance claims. The repository-local
benchmarks/compare_contract.py remains available for focused deterministic
trace checks. The inherited examples/python/fps_test.py,
examples/python/gymnasium_vect_bench.py, and
tests/manual_test_performance.py scripts are single-build diagnostics only;
they do not provide matched workloads, validity gates, or claim evidence.
Notes
- Python 3.14 is supported. Release wheels target macOS ARM64 and Linux x86-64. Source builds require Rust 1.85 or newer.
- ViZDoom 1.3.0 supplies built-in scenarios and Freedoom assets. Commercial Doom IWADs are not included; pass one with
rom_pathwhen required. - Autoreset is disabled. Terminal lanes retain their final observation and must be selected explicitly with a masked reset.
- Preprocessing supports crop removal or masking, max-pooling, nearest/bilinear/area resize, grayscale or RGB, frame skip, frame stacking, and CHW or HWC layouts.
- The native vector path supports image observations,
rgb_arrayrendering, and one player. Recording is not supported.
Architecture
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file env_vizdoom_turbo-1.3.0.post29-cp314-cp314-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: env_vizdoom_turbo-1.3.0.post29-cp314-cp314-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 39.9 MB
- Tags: CPython 3.14, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e3d7880734f24db6670b0078c3b2b3b2ca58093d8145eb762ca2262c2ba0901
|
|
| MD5 |
b49555e8564cac5fd9315ed7088a1bf9
|
|
| BLAKE2b-256 |
1e30cf99760fcc65f9bd1f2d853d9026e0261682b446cc539554d29db3a3b5fa
|
Provenance
The following attestation bundles were made for env_vizdoom_turbo-1.3.0.post29-cp314-cp314-manylinux_2_28_x86_64.whl:
Publisher:
release.yml on tsilva/env-ViZDoom-turbo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
env_vizdoom_turbo-1.3.0.post29-cp314-cp314-manylinux_2_28_x86_64.whl -
Subject digest:
4e3d7880734f24db6670b0078c3b2b3b2ca58093d8145eb762ca2262c2ba0901 - Sigstore transparency entry: 2668253091
- Sigstore integration time:
-
Permalink:
tsilva/env-ViZDoom-turbo@07b4a0f271ce3f9f1e445b824d1f856b074bbb73 -
Branch / Tag:
refs/tags/env-vizdoom-turbo-v1.3.0.post29 - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@07b4a0f271ce3f9f1e445b824d1f856b074bbb73 -
Trigger Event:
push
-
Statement type:
File details
Details for the file env_vizdoom_turbo-1.3.0.post29-cp314-cp314-macosx_15_0_arm64.whl.
File metadata
- Download URL: env_vizdoom_turbo-1.3.0.post29-cp314-cp314-macosx_15_0_arm64.whl
- Upload date:
- Size: 42.9 MB
- Tags: CPython 3.14, macOS 15.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a9c55113d6feacb2afa54939df06b4d2e44472ea660d1f723ec41b10cd34882
|
|
| MD5 |
7bb41cf5779b81edb05d592a2e89479f
|
|
| BLAKE2b-256 |
f7ab1b8557aea200103b8441372af54fc48f0c4242e76f7688cf2bedf35ea6ca
|
Provenance
The following attestation bundles were made for env_vizdoom_turbo-1.3.0.post29-cp314-cp314-macosx_15_0_arm64.whl:
Publisher:
release.yml on tsilva/env-ViZDoom-turbo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
env_vizdoom_turbo-1.3.0.post29-cp314-cp314-macosx_15_0_arm64.whl -
Subject digest:
1a9c55113d6feacb2afa54939df06b4d2e44472ea660d1f723ec41b10cd34882 - Sigstore transparency entry: 2668252976
- Sigstore integration time:
-
Permalink:
tsilva/env-ViZDoom-turbo@07b4a0f271ce3f9f1e445b824d1f856b074bbb73 -
Branch / Tag:
refs/tags/env-vizdoom-turbo-v1.3.0.post29 - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@07b4a0f271ce3f9f1e445b824d1f856b074bbb73 -
Trigger Event:
push
-
Statement type: