srctools.vmf

Reads and writes VMF map files, providing various tools to make it easier to modify.

Core Functionality

class srctools.vmf.VMF(
map_info: Mapping[str, str] = ...,
preserve_ids: bool = False,
*,
format_version: int | None = None,
hammer_version: int | None = None,
hammer_build: int | None = None,
is_prefab: bool | None = None,
cordon_enabled: bool | None = None,
map_version: int | None = None,
show_grid: bool | None = None,
show_3d_grid: bool | None = None,
snap_grid: bool | None = None,
show_logic_grid: bool | None = None,
grid_spacing: int | None = None,
active_cam: int | None = None,
quickhide_count: int | None = None,
strata_inst_visibility: StrataInstanceVisibility | None = None,
)

Represents a VMF file, and holds counters for various IDs used.

Has functions for searching for specific entities or brushes, and converts to/from a property_parser tree.

The dictionaries by_target and by_class allow quickly getting a set of entities with the given class or targetname.

staticmethod parse(
tree: Keyvalues | str,
preserve_ids: bool = False,
) VMF

Convert a keyvalues tree into VMF classes.

export(
*,
inc_version: bool = True,
minimal: bool = False,
disp_multiblend: bool = True,
) str
export(
dest_file: FileWText,
*,
inc_version: bool = True,
minimal: bool = False,
disp_multiblend: bool = True,
) None

Serialises the object’s contents into a VMF file.

  • If no file is given the map will be returned as a string.

  • By default, this will increment the map’s version - disable inc_version to suppress this.

  • If minimal is True, several blocks will be skipped (Viewsettings, cameras, cordons and visgroups)

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is stripped.

  • named_cordons controls if multiple cordons may be used (post L4D), or if only a single cordon is allowed.

is_prefab: bool

Marks whether this map is a intended as a prefab.

cordon_enabled: bool
map_ver: int

The map version increments once whenever the map is saved in Hammer.

format_ver: int
hammer_ver: int
hammer_build: int
show_grid: bool

Whether Hammer has the grid enabled.

show_3d_grid: bool

Whether Hammer has the 3D grid enabled.

snap_grid: bool

Whether Hammer has grid snapping enabled.

show_logic_grid: bool

Whether Hammer has the incomplete logical grid enabled.

grid_spacing: int

The last grid size in Hammer.

Common behaviours

Automatic conversion

VMFs store string values in several locations, which are commonly treated as other data types, parsed as necessary. To make this easier to deal with, several data types are automatically converted when passed to relevant functions.

type srctools.vmf.ValidKVs

Parameters with this type automatically convert values to a string.

srctools.vmf.conv_kv(val: ValidKVs) str

Convert a type into a string matching Valve’s syntax.

The following types are allowed:

  • Strings: Passed unchanged.

  • Booleans: Converted to 1 or 0.

  • int: Stringified as normal.

  • float: Strips .0 if integral.

  • [Frozen] Vec, [Frozen] Angle: Uses the standard 1 2 3 form.

  • [Frozen] Matrix: Converted to the corresponding angle.

  • Any enum: The value attribute is extracted and recursively converted.

Locations with automatic conversion include entity values, instance fixups, and output parameters.

ID management

The VMF class records IDs used by brushes, faces, entities, groups, visgroups and AI nodes. When creating new objects, they will automatically get assigned a new ID. IDs are ‘owned’ while the relevant object is alive - removing them from the VMF will still keep it reserved.

VMF.solid_id: IDMan
VMF.face_id: IDMan
VMF.ent_id: IDMan
VMF.group_id: IDMan
VMF.vis_id: IDMan
VMF.node_id: IDMan
class srctools.vmf.IDMan

This class keeps track of IDs for a particular object type. It has no public constructor.

allow_duplicates: bool

Can be changed to disable the ID validation, allowing new objects to overlap existing ones.

get_id(desired: int = -1) int

Get a valid ID.

with VMF.allow_duplicate_ids(self)

While inside this context manager, allow all IDs to have duplicates.

IDs are still tracked, so future IDs will not overlap these.

Solid.id: int

A unique ID assigned to this solid. Will be picked automatically when the brush is created.

Side.id: int
VisGroup.id: int
VisGroup.id: int
Entity.id: int
EntityGroup.id: int

Brushes

VMF.brushes: list[Solid]

The list of all world brushes in the map.

VMF.add_brush(item: Solid | PrismFace) None

Add a world brush to this map.

VMF.add_brushes(brushes: Iterable[Solid]) None

Add multiple brushes to the map.

VMF.remove_brush(brush: Solid) None

Remove a world brush from this map.

class srctools.vmf.Solid(
map: VMF,
id: int = -1,
sides: list[Side] = NOTHING,
visgroup_ids=(),
hidden: bool = False,
group_id: int | None = None,
vis_shown: bool = True,
vis_auto_shown: bool = True,
is_cordon: bool = False,
editor_color: Vec = NOTHING,
)

A single brush, serving as both world brushes and brush entities.

editor_color: Vec

The RGB colour this brush appears as in 2D views. Randomly assigned when the brush is created, but then set to the colour of the tied entity or visgroup.

group_id: int | None

If set, this brush is grouped in the group with this ID.

hidden: bool

If set, this brush has been hidden in some way (quick hide, cordons, visgroups). It will not be compiled into the final map.

sides: list[Side]

The faces for this brush.

vis_auto_shown: bool

Determines whether this brush has been hidden via a builtin “Auto” visgroup.

vis_shown: bool

Determines whether this brush has been hidden via a user-authored visgroup.

visgroup_ids: set[int]

The set of IDs of user-authored visgroups this brush belongs to.

is_cordon: bool

If set, this brush has been generated by Hammer to seal cordoned areas. These are deleted when loading the map by Hammer and recreated on save.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
hidden: bool = False,
) Solid

Parse a Property tree into a Solid object.

export(
buffer: FileWText,
ind: str = '',
disp_multiblend: bool = True,
include_groups: bool = True,
) None

Generate the strings needed to define this brush.

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is stripped.

  • include_groups specifies if visgroup/group values are included. This is not allowed inside brush entities.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = ...,
keep_vis: bool = True,
) Solid

Duplicate this brush.

remove() None

Remove this brush from the map.

get_bbox() tuple[Vec, Vec]

Get two vectors representing the space this brush takes up.

get_origin(
bbox_min: Vec | None = None,
bbox_max: Vec | None = None,
) Vec

Calculates a vector representing the exact center of this brush.

translate(diff: VecBase | Vec_tuple | tuple[float, float, float]) None

Move this solid by the specified vector.

localise(
origin: VecBase | Vec_tuple | tuple[float, float, float],
angles: Angle | FrozenAngle | Matrix | FrozenMatrix | None = None,
) None

Shift this brush by the given origin/angles.

point_inside(
point: VecBase | Vec_tuple | tuple[float, float, float],
threshold: float = 1e-06,
) bool

Check if the specified point is inside the brush.

The threshold controls tolerance - a point is still counted if it is this far away from the surface.

class srctools.vmf.Side(
vmf_file: VMF,
planes: list[Vec],
des_id: int = -1,
lightmap: int = 16,
smoothing: int = 0,
mat: str = 'tools/toolsnodraw',
rotation: float = 0,
uaxis: UVAxis | None = None,
vaxis: UVAxis | None = None,
disp_power: Literal[0, 1, 2, 3, 4] = 0,
)

A brush face.

planes: list[Vec]
mat: str
smooth: int
ham_rot: float
lightmap: int
uaxis: UVAxis
vaxis: UVAxis
property scale

When set, modifies both the U and V axes.

property offset

When set, modifies both the U and V axes.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
) Side

Parse the property tree into a Side object.

export(
buffer: FileWText,
ind: str = '',
disp_multiblend: bool = True,
) None

Generate the strings required to define this side in a VMF.

  • disp_multiblend controls whether displacements produce their multiblend data (added in CSGO), or if it is skipped.

classmethod from_plane(
vmf: VMF,
position: VecBase | Vec_tuple | tuple[float, float, float],
normal: VecBase | Vec_tuple | tuple[float, float, float],
material: str = 'tools/toolsnodraw',
) Side

Generate a new brush face, aligned to the specified plane.

The normal vector points out of the face. This calculates a valid texture alignment, but does not specify an exact result.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = ...,
) Side

Duplicate this brush side.

des_id is the id which is desired for the new side. map is the VMF to add the new side to (defaults to the same map). If passed, side_mapping will be updated with an old -> new ID pair.

get_bbox() tuple[Vec, Vec]

Generate the highest and lowest points these planes form.

get_origin() Vec

Calculates a vector representing the exact center of this plane.

translate(diff: VecBase | Vec_tuple | tuple[float, float, float]) None

Move this side by the specified vector.

  • A tuple can be passed in instead if desired.

localise(
origin: VecBase | Vec_tuple | tuple[float, float, float],
angles: Matrix | FrozenMatrix | Angle | FrozenAngle | None = None,
) None

Shift the face by the given origin and angles.

This preserves texture offsets.

normal() Vec

Compute the unit vector which extends perpendicular to the face.

class srctools.vmf.UVAxis(x: float, y: float, z: float, offset: float = 0.0, scale: float = 0.25)

Values saved into Side.uaxis and Side.vaxis.

These define the alignment of textures on a face.

offset: float
scale: float
x: float
y: float
z: float
classmethod parse(value: str) UVAxis

Parse a UV axis from a string.

copy() UVAxis

Return a duplicate of this axis.

vec() Vec

Return the axis as a vector.

rotate(
angles: Angle | FrozenAngle | Matrix | FrozenMatrix,
) UVAxis

Rotate the axis by some orientation.

This doesn’t alter texture offsets.

localise(
origin: VecBase | Vec_tuple | tuple[float, float, float],
angles: Angle | FrozenAngle | Matrix | FrozenMatrix,
) UVAxis

Rotate and translate the texture coordinates.

Creation

VMF.make_prism(
p1: Vec | FrozenVec,
p2: Vec | FrozenVec,
mat: str = 'tools/toolsnodraw',
set_points: bool = False,
) PrismFace

Create an axis-aligned brush connecting the two points.

A PrismFaces tuple will be returned which contains the six faces, as well as the solid. All faces will be textured with ‘mat’. If set_points is defined, explicit vertex info will be included.

VMF.make_hollow(
p1: Vec | FrozenVec,
p2: Vec | FrozenVec,
thick: float = 16,
mat: str = 'tools/toolsnodraw',
inner_mat: str = '',
) list[Solid]

Create 6 brushes to surround the given region.

If inner_mat is not specified, it’s set to mat.

class srctools.vmf.PrismFace(
solid: Solid,
top: Side,
bottom: Side,
north: Side,
south: Side,
east: Side,
west: Side,
)

Return value for VMF.make_prism() and VMF.make_hollow().

This can be indexed with an axis-aligned Vec or 3-tuple normal to fetch a side.

north: Side

The +y side of the brush.

south: Side

The -y side of the brush.

east: Side

The +x side of the brush.

west: Side

The -x side of the brush.

top: Side

The +z side of the brush.

bottom: Side

The -z side of the brush.

solid: Solid

The generated brush.

Displacements

Brush faces converted to displacements add a number of additional properties to the face.

Side.disp_power: Literal[0, 1, 2, 3, 4]

The number of subdivisions for a displacement, ranging from 0-4. If zero, the brush is not a displacement and the other values are ignored.

property Side.is_disp: bool

Returns whether this is a displacement or not.

Side.disp_size

Return the number of vertexes in each direction of a displacement.

Side.disp_allowed_vert: array[int] | None
Side.disp_elevation: float
Side.disp_flags: DispFlag
Side.disp_pos: Vec | None
Side.disp_get_tri_verts(
x: int,
y: int,
) tuple[DispVertex, DispVertex, DispVertex, DispVertex, DispVertex, DispVertex]

Return the locations of the triangle vertexes.

This is a set of 6 verts, representing the two triangles in order. See 2013 SDK src/public/builddisp.cpp:896-965.

class srctools.vmf.Vec4(x: float = 0.0, y: float = 0.0, z: float = 0.0, w: float = 0.0)

Defines a 4-dimensional vector.

x: float
y: float
z: float
w: float
class srctools.vmf.DispFlag

Bases: Flag

Per-displacement flags, configuring collisions.

Does NOT match the file values, since those are inverted.

COLL_NONE = 0
COLL_PHYSICS = 1
COLL_PLAYER_NPC = 2
COLL_BULLET = 4
COLL_ALL = 7
SUBDIV = 8
SUBDIV_COLL_ALL = 15
class srctools.vmf.TriangleTag

Bases: Flag

Two flags set on all displacement triangles.

If walkable, it is shallow enough to stand on. If buildable, TF2 Engineers can place buildings.

STEEP = 0
WALKABLE = 1
BUILDABLE = 9

Alias: FLAT

class srctools.vmf.DispVertex(
x: int,
y: int,
normal: ~srctools.math.Vec = NOTHING,
distance: float = 0,
offset: ~srctools.math.Vec = NOTHING,
offset_norm: ~srctools.math.Vec = NOTHING,
alpha: float = 0.0,
triangle_a: ~srctools.vmf.TriangleTag = <TriangleTag.BUILDABLE: 9>,
triangle_b: ~srctools.vmf.TriangleTag = <TriangleTag.BUILDABLE: 9>,
multi_blend: ~srctools.vmf.Vec4 = Vec4(x=0.0,
y=0.0,
z=0.0,
w=0.0),
multi_alpha: ~srctools.vmf.Vec4 = Vec4(x=0.0,
y=0.0,
z=0.0,
w=0.0),
multi_colors: list[~srctools.math.Vec] | None = None,
)

A vertex in dislacements.

x: int
y: int
normal: Vec
distance: float
offset: Vec
offset_norm: Vec
alpha: float
triangle_a: TriangleTag
triangle_b: TriangleTag
multi_blend: Vec4
multi_alpha: Vec4
multi_colors: list[Vec] | None

Entities

VMF.entities: list[Entity]

The list of all entities in the map.

VMF.spawn: Entity

The worldspawn entity represents the world and stores all world brushes. This will always exist. It is also present in the entities list.

VMF.add_ent(item: Entity) None

Add an entity to the map.

The entity should have been created with this VMF as a parent.

VMF.remove_ent(item: Entity) None

Remove an entity from the map.

After this is called, the entity will no longer be exported. The object still exists, so it can be reused.

VMF.add_ents(ents: Iterable[Entity]) None

Add multiple entities to the map.

VMF.create_ent(classname: str, **kargs: ValidKVs) Entity

Convenience method to allow creating point entities.

This constructs an entity, adds it to the map, and then returns it. A classname must be passed!

class srctools.vmf.Entity(
vmf_file: VMF,
keys: Mapping[str, ValidKVs] = ...,
fixup: Iterable[FixupValue] = (),
ent_id: int = -1,
outputs: Iterable[Output] = (),
solids: Iterable[Solid] = (),
hidden: bool = False,
groups: Iterable[int] = (),
vis_ids: Iterable[int] = (),
vis_shown: bool = True,
vis_auto_shown: bool = True,
logical_pos: str | None = None,
editor_color: Vec | tuple[int, int, int] = (255, 255, 255),
comments: str = '',
)

A representation of either a point or brush entity.

Creation:

Supports ent[key] operations to read and write keyvalues. To read instance $replace values operate on entity.fixup[var].

staticmethod parse(
vmf_file: VMF,
tree_list: Keyvalues,
hidden: bool = False,
_worldspawn: bool = False,
) Entity

Parse a property tree into an Entity object.

_worldspawn indicates if this is the worldspawn entity, which additionally contains the entity group definitions.

export(
buffer: FileWText,
ind: str = '',
disp_multiblend: bool = True,
_is_worldspawn: bool = False,
) None

Generate the strings needed to create this entity.

  • disp_multiblend controls whether displacements produce their multiblend data (added in ASW), or if it is skipped.

  • _is_worldspawn is used interally to generate the special worldspawn block.

copy(
des_id: int = -1,
vmf_file: VMF | None = None,
side_mapping: MutableMapping[int, int] = ...,
keep_vis: bool = True,
) Entity

Duplicate this entity entirely, including solids and outputs.

remove() None

Remove this entity from the map.

make_unique(unnamed_prefix: str = '') Entity

Ensure this entity is uniquely named, by adding a numeric suffix.

If the entity doesn’t start with a name, it will use the parameter.

hidden: bool
visgroup_ids: set[int]
vis_shown: bool
vis_auto_shown: bool
groups: set[int]
editor_color: Vec
logical_pos: str
comments: str
solids: list[Solid]
is_brush() bool

Is this Entity a brush entity?

get_bbox() tuple[Vec, Vec]

Get two vectors representing the space this entity takes up.

get_origin() Vec

Return a vector representing the center of this entity’s brushes.

for face in sides() Iterable[Side]

Iterate through all our brush sides.

Outputs

Entity.outputs: list[Output]
Entity.add_out(*outputs: Output) None

Convenience method to add outputs to this entity.

Entity.output_targets() set[str]

Return a set of the targetnames this entity triggers.

for output in VMF.iter_inputs(name: str) Iterator[Output]

Loop through all Outputs which target the named entity.

* can be used at the beginning or end of the name for a wildcard search.

class srctools.vmf.Output(
out: str,
targ: Entity | str,
inp: str,
param: ValidKVs = '',
delay: float = 0.0,
*,
times: int = -1,
only_once: bool = False,
inst_out: str | None = None,
inst_in: str | None = None,
comma_sep: bool = False,
)

An output from one entity pointing to another.

When parsing, either the post-L4D 0x1B character can be used, or the previous , delimiters can be used. For commas, extraneous ones will be treated as part of the parameters.

input: str

The input to fire.

target: str

The target entity.

output: str

The output which triggers this.

params: str

Parameters to give the input, or "" for none.

delay: float

The number of seconds before the output should fire.

times: int

The number of times to fire before being deleted. -1 means forever, Hammer only uses -1 and 1.

property only_once: bool

Instead of setting times, this provides an interface like how Hammer does.

comma_sep: bool

Use a comma as a separator, instead of the OUTPUT_SEP character.

inst_in: str | None

The local entity we are really triggering in instance inputs (instance:name;Input)

inst_out: str | None

The local entity for an instance output (instance:name;Output)


classmethod parse(prop: Keyvalues) Output

Convert the VMF Property into an Output object.

export(buffer: FileWText, ind: str = '') None

Generate the text required to define this output in the VMF.

as_keyvalue() str

Generate the text form of the output.

This backslash-escapes characters where necessary.

classmethod combine(
first: Output,
second: Output,
) Output

Combine two outputs into a merged form.

This is suitable for combining a Trigger and OnTrigger pair into one, or similar values.

staticmethod parse_name(name: str) tuple[str | None, str]

Extract the instance name from values of the form:

instance:local_name;Command

This then returns a local_name, command tuple. If not of this form, the first value will be None.

Raises:

ValueError – If the command part is missing. This will crash VBSP if it tries to parse.

exp_out() str

Combine the instance name with the output if necessary.

exp_in() str

Combine the instance name with the input if necessary.

copy() Output

Duplicate this Output object.

gen_addoutput(delim: str = ',') str

Return the parameter needed to create this output via AddOutput.

This assumes the target instance uses Prefix fixup, if inst_in is set.

srctools.vmf.SEP
Output.SEP: Final = '\x1b'

The character used to separate output values, after L4D. Before then commas (,) were used.

Instances

func_instance entities can have fixup variables defined on them, which are stored in a number of replace01 keys. To avoid having to deal with the details, these are automatically parsed and stored under a fixup attribute.

Entity.fixup

Access $replace variables on instances.

class srctools.vmf.EntityFixup(
fixup: Iterable[FixupValue] | EntityFixup = (),
)

A specialised mapping which keeps track of the variable indexes.

This treats variable names case-insensitively, and optionally allows writing variables with $ signs in front. The case of the first assigned name for each key is preserved.

Additionally, lookups never fail - returning "" instead. Pass in a non-string default or use in to distinguish.

get(var: str) str
get(var: str, default: str | T) str | T

Get the value of an instance $replace variable.

If not found, the default will be returned (an empty string).

copy_values() list[FixupValue]

Generate a list that can be passed to the constructor.

clear() None

Wipe all the $fixup values.

setdefault(var: str, /, default: str = '') str
setdefault(
var: str,
/,
default: ValidKV_T,
) str | ValidKV_T

Return $key, but if not present set it to the default and return that.

items() ItemsView[str, str]

Provides a view over all variable-value pairs.

values() ValuesView[str]

Provides a view over all variable values.

export(buffer: FileWText, ind: str) None

Export all the fixup values into the VMF.

substitute(
text: str,
default: str | None = None,
*,
allow_invert: bool = False,
) str

Substitute the fixup variables into the provided string.

Variables are found based on the defined values, so constructions such as val$varval are valid (with no delimiter indicating the end of variables). Longer matches are preferred. If a match is not found, the characters a-z, 0-9 and _ are detected as variables, and substituted with a default.

Parameters:
  • text – The source text to substitue into.

  • default – If set, unrecognised fixups are set to this value. If not, KeyError is raised.

  • allow_invert – If enabled, a variable can additionally be specified like :var`!$var` to cause it to be inverted when substituted. Valid booleans are the same as those parsed by srctools.conv_bool.

int(key: str, def_: int | T = 0) int | T

Return the value of an integer key.

Equivalent to int(fixup[key]), but with a default value if missing or invalid.

float(
key: str,
def_: float | T = 0.0,
) float | T

Return the value of an integer key.

Equivalent to float(fixup[key]), but with a default value if missing or invalid.

bool(key: str, def_: bool | T = False) bool | T

Return a fixup interpreted as a boolean.

Valid values are the same as srctools.conv_bool.

vec(
key: str,
x: float = 0.0,
y: float = 0.0,
z: float = 0.0,
) Vec

Return the given fixup, converted to a vector.

type srctools.vmf.FixupValue

Opaque value storing a key/value pair plus the index. Can be passed to fixups to attempt to preserve the index.

Finding Entities

Several features are provided to help locate entities in a similar way to the game.

VMF.by_class: MutableMapping[str, AbstractSet[str]]
VMF.target: MutableMapping[str, AbstractSet[str]]
for entity in VMF.search(name: str) Iterator[Entity]

Yield all entities that fit this search string.

This can be the exact targetname, end-* matching, or the exact classname.

Entities added or renamed after iteration begins will not be detected. Unnamed entities will never be detected. If the name is blank, this therefore finds nothing.

for entity in VMF.iter_ents(**cond: str) Iterator[Entity]

Iterate through entities having the given keyvalue values.

for entity in VMF.iter_ents_tags(
vals: Mapping[str, str] = ...,
tags: Mapping[str, str] = ...,
) Iterator[Entity]

Iterate through all entities.

The returned entities must have exactly the given keyvalue values, and have keyvalues containing the tags.

Cordons

VMF.cordons: list[Cordon]

The list of all cordons defined in the map.

class srctools.vmf.Cordon(
vmf_file: VMF,
min_: Vec,
max_: Vec,
is_active: bool = True,
name: str = 'Cordon',
)

Represents one cordon volume.

classmethod parse(
vmf_file: VMF,
tree: Keyvalues,
) Cordon

Parse a cordon from the VMF file.

export(buffer: FileWText, ind: str = '') None

Write the cordon into the VMF.

copy() Cordon

Duplicate this cordon.

remove() None

Remove this cordon from the map.

Strata Source Extensions

Strata Source adds a few additional values to preserve vertices and store settings.

Side.strata_points: list[Vec] | None
VMF.strata_viewports: list[Strata2DViewport | Strata3DViewport] | None

Records the current state of all 2D and 3D viewports. If None, no value is saved in the file.

class srctools.vmf.Strata2DViewport(axis: Literal['x', 'y', 'z'], u: float, v: float, zoom: float)

Represents the position of a 2D viewport in Strata Source.

In the file this is specified as a single vector, with the planar axis set to ±65536.

axis: Literal['x', 'y', 'z']
u: float
v: float
zoom: float
classmethod from_vector(
pos: Vec,
zoom: float = 1.0,
) Strata2DViewport

Determine the appropriate axis from the position vector.

export(buffer: FileWText, title: str) None

Export the 2D viewport definition.

class srctools.vmf.Strata3DViewport(position: Vec, angle: Angle)

Represents the position of a 3D viewport in Strata Source.

Changing roll does work, but should be avoided since Hammer doesn’t allow control of that axis.

position: Vec
angle: Angle
export(buffer: FileWText, title: str) None

Export the 3D viewport definition.

VMF.strata_instance_vis: StrataInstanceVisibility | None

Records the last state of the instance viewing mode. If None, no value is saved in the file.

class srctools.vmf.StrataInstanceVisibility

Bases: Enum

Strata Source saves and restores the ‘view instances’ option.

HIDDEN = 0

Do not preview instances.

TINTED = 1

Show with a green tint

NORMAL = 2

Show normally.