simvx.core.env_sync_spec

Single source of truth for WorldEnvironment → renderer-subsystem field propagation. Both the Vulkan EnvironmentSync and the web WebApp _sync_world_environment walk the same spec; new env fields propagate to both backends by adding one row.

Composites (e.g. camera.exposure × env.tonemap_exposure) and structurally divergent bridges (sky_mode → clear-colour / skybox) stay imperative in the calling sync method: only field-to-attribute propagation lives here.

Module Contents

Classes

EnvField

One row of the WorldEnvironment → renderer mapping.

Functions

apply_spec

Walk ENV_SYNC_SPEC, read each env attr, write via resolve.

feed_tonemap

The (mode, exposure, white) a SubViewport’s feed is tone-mapped with.

Data

API

simvx.core.env_sync_spec.__all__

[‘EnvField’, ‘ENV_SYNC_SPEC’, ‘ENV_SYNC_COMPOSITES’, ‘apply_spec’, ‘feed_tonemap’]

class simvx.core.env_sync_spec.EnvField[source]

One row of the WorldEnvironment → renderer mapping.

env_attr : name of the attribute on WorldEnvironment. target : logical "subsystem.field" path. The backend resolver maps the subsystem to a concrete object (Vulkan Renderer._post_process, web WebRenderer). transform : optional callable applied to the env value before write. Used for enum→int translation, alpha-trim, etc. backends : backends that should propagate this field. Lets the spec reflect today’s reality where some env fields are wired on web but not desktop yet (e.g. ssao_radius).

env_attr: str

None

target: str

None

transform: collections.abc.Callable[[Any], Any] | None

None

backends: tuple[str, ...]

(‘vulkan’, ‘web’)

simvx.core.env_sync_spec.ENV_SYNC_SPEC: tuple[simvx.core.env_sync_spec.EnvField, ...]

()

simvx.core.env_sync_spec.ENV_SYNC_COMPOSITES: frozenset[str]

‘frozenset(…)’

simvx.core.env_sync_spec.apply_spec(env: Any, *, backend: str, resolve: collections.abc.Callable[[str, str, Any], None]) → None[source]

Walk ENV_SYNC_SPEC, read each env attr, write via resolve.

resolve(subsystem, attr, value) does the backend-specific dispatch (attribute write, method-kwarg accumulation, etc.). Fields whose backend list excludes the requested backend are skipped.

Quality-tier resolution happens here so both backends inherit it from the one choke point: a named env.quality_tier maps its wired dials (render_scale, probe_blend_count, probe_face_size, shadow_caster_count) to the core tier-table values, which then ride the exact same rows and transition paths as an explicit per-dial Property. A dial whose row is one-backend-only is still resolved here and simply skipped for the other backend, so the tier means the same thing wherever the row exists. “auto”/”custom” yield no overrides and this reads every attr straight off env, the pre-tier behaviour.

simvx.core.env_sync_spec.feed_tonemap(viewport: Any, root: Any) → tuple[int, float, float][source]

The (mode, exposure, white) a SubViewport’s feed is tone-mapped with.

A feed is display-referred: it holds what the main tonemap pass would put on screen for the viewport’s camera, so a sprite showing it 1:1 matches the same camera rendered as the main scene. The curve follows the rule for which world the viewport renders: a WorldEnvironment inside the viewport’s own subtree is its own, and without one it shares the main scene’s (root’s, outside every SubViewport). With neither, the renderer’s defaults apply, as they do to a main scene with no WorldEnvironment. Exposure is the viewport camera’s exposure times the environment’s tonemap_exposure, as the main pass composes it from the main camera. Both backends call this.