Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions docs/SCENE_EFFECTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

Scene effects are authored entity components. They use the existing hierarchy, transforms, scene persistence and undo history. An entity has at most one effect component; use child entities to combine effects. Configuration is saved; live particles and playback clocks are transient.

This guide describes the native editor and native Play path. CPU simulation is the supported particle path. The compatibility section identifies renderer features that remain unavailable.
This guide describes the native editor and Play path, with capability-gated GPU particles and CPU fallback. The compatibility section describes renderer and browser limits.

## Add and preview an effect

1. Open a project and scene in the editor.
2. Use hierarchy **+ Add → Effects** to create an effect entity, or select an entity and open **Properties → Scene effects → + Add / replace effect**.
3. Select the new effect entity. Expand **Common** for playback, seed, duration and visibility, then the effect-specific section for simulation and appearance.
4. Open **Properties → Effect preview** to play, pause, resume, stop, restart, reset or step by 1/60 second. Preview speed ranges from 0 to 4; time scrubbing replays up to 30 seconds, and bounds/metrics are available. Move its entity with the normal transform gizmo. An emitting trail needs movement before it creates a ribbon. Preview runs a scratch SceneWorld through the same simulation path, including registered child-asset sub-emitters. Stopping preview clears transient child groups.
4. Open **Properties → Effect preview** to play, pause, resume, stop, restart, reset or step by 1/60 second. Preview speed ranges from 0 to 4; time scrubbing replays up to 30 seconds, and bounds/metrics are available. Use the Inspector gizmo selector for **Entity transform**, **Emission-volume size**, **Beam start**, **Beam end** or **Force-wind direction**. These use the existing transform-gizmo handles; releasing records one undo transaction and Escape restores the original. Enable preview audio explicitly to hear composite cues; scrubbing stays silent. An emitting trail needs movement before it creates a ribbon. Preview runs a scratch SceneWorld through the same simulation path, including registered child-asset sub-emitters. Stopping preview clears transient child groups.
5. Save the scene, close it and reopen it. The configuration returns; playback starts from the configured initial state.

Open **Effects presets & assets**, search the built-in library and click a preset to instantiate a group under the selection. Drag a preset onto the viewport or hierarchy to place it. Use **Load .effect** or **Save selection .effect** for custom assets. The preset is editable. For a selected single-effect component, **Assign single-effect asset…** changes its source. Composite assets are instantiated through the asset browser. Configure entity references such as a light pulse's target or a beam's endpoint; effects requiring targets cannot infer your intended object.
Expand Down Expand Up @@ -74,9 +74,9 @@ A teleport farther than `teleport_distance` clears the previous strip so it does

## Effect asset and composite tutorial

An `.effect` file contains `EffectAsset { version, name, effects }`, with optional `entity_ids` and column-major `transforms` arrays for authored child identities and transforms relative to the group. Instantiation allocates fresh child IDs and remaps references between children, preserving their relative transforms. Legacy assets without those arrays instantiate at the group origin. References to scene objects outside the asset remain external references; assign them for the destination scene. Version 1 stores an ordered list of fully typed child configurations. `common.delay` and `common.duration` give each child its position in the composite timeline. The asset reader rejects unsupported versions, empty groups, groups above 128 children and files above 4 MiB.
An `.effect` file contains `EffectAsset { version, name, effects }`, with optional `entity_ids` and column-major `transforms` arrays for authored child identities and transforms relative to the group. Aligned light, primitive, mesh, material, texture and part-attribute arrays preserve ordinary child components. Optional `group_settings`, `sound_cues`, `parameters`, `bindings` and `trigger_bindings` describe the composite timeline. Instantiation allocates fresh child IDs and remaps references between children, preserving their relative transforms. Legacy assets without those arrays instantiate at the group origin. References to scene objects outside the asset remain external references; assign them for the destination scene. Version 1 stores an ordered list of fully typed child configurations. `common.delay` and `common.duration` give each child its position in the composite timeline. The asset reader rejects unsupported versions, empty groups, groups above 128 children and files above 4 MiB.

`presets()` returns 35 independent built-in assets; `instantiate()` clones a group's configuration. `instantiate_from(asset_id)` additionally retains the source UUID and child index; `restore(instance)` resets that child to its shared asset defaults. Editing one instance does not mutate another instance or the source asset. Explosion combines a time-zero burst, delayed smoke, an expanding shockwave and a camera impulse. The showcase generator writes all built-in assets under `assets/effects`.
`presets()` returns 35 independent built-in assets; `instantiate()` clones a group's configuration. `instantiate_from(asset_id)` additionally retains the source UUID and child index; `restore(instance)` resets that child to its shared asset defaults. Editing one instance does not mutate another instance or the source asset. Explosion combines a time-zero burst, delayed smoke, an expanding shockwave, mesh debris, a light flash, camera impulse and a generated sound cue. The preset installer provides the stable-ID WAV and debris OBJ with normal asset sidecars. Object dissolve and Character highlight include self-targeting demonstration geometry. The showcase generator writes all built-in assets under `assets/effects`.

A composite's children are ordinary scene effects. Parenting preserves transform inheritance and standard duplication/deletion behavior. Reset individual instance values by reapplying the asset. Select the group and open **Scene effects → Composite timeline (seconds)** to change child enabled state, start and duration, select a child to edit, duplicate, move earlier or delete it. Select a source child for **Restore asset defaults** and **Update shared asset**. **Update shared asset** refreshes matching instances in the currently open authoring scene while preserving fields that differ from the old defaults; arrays are treated as complete overrides. That scene refresh is one undo transaction. The shared asset file write is a separate asset edit. When an asset is registered during scene loading, persisted source baselines merge current asset defaults while preserving per-field overrides; arrays remain atomic overrides. Legacy instances without a baseline retain embedded configuration until restored.

Expand Down Expand Up @@ -148,17 +148,21 @@ Run this on an entity that does not already have an effect. For a previously aut

JavaScript uses the same names and objects, with `null` instead of `nil`. Python also exposes the same `Effects` wrappers. Other generic-query adapters can use the existing `rustic.query` boundary, for example `{op:'effect_types'}`. Effect requests include `effect_create`, `effect_get`, `effect_configure`, `effect_control` and `effect_state`. Entity arguments in raw protocol requests must be stable UUIDs. Configuration uses the typed variant shape `kind: {Particle: {...}}`; unknown fields, unknown kinds and invalid values return errors before committing a scene mutation.

Runtime edits affect the live Play world. Stop Play to return to the authored scene. Use the Inspector and Save for persistent authoring. `dispose` removes the effect component, not its entity. Completion and particle birth/collision/death records are available in Rust `EffectFrame.events` and the existing Events service. Subscribe with `Events.connect(entity, "EffectCompleted", callback)` or `EffectBirth`, `EffectCollision` and `EffectDeath`; event arguments contain the world position vector. A composite root emits EffectCompleted once when its descendants complete; restarting or resetting begins a new completion cycle. `Effects.sampleWind(position, time, layers)` samples compatible wind at a position, using the supplied time in seconds for gust phase.
Runtime edits affect the live Play world. Stop Play to return to the authored scene. Use the Inspector and Save for persistent authoring. `dispose` removes the effect component, not its entity. Completion and particle birth/collision/death records are available in Rust `EffectFrame.events` and the existing Events service. Subscribe with `Events.connect(entity, "EffectCompleted", callback)` or `EffectBirth`, `EffectCollision` and `EffectDeath`; event arguments contain the world position vector. A composite root emits EffectCompleted once when its own timeline completes; its default duration includes child tails. Restarting or resetting begins a new completion cycle. `Effects.sampleWind(position, time, layers)` samples compatible wind at a position, using the supplied time in seconds for gust phase.

## Renderer compatibility and color management

The native renderer supports up to eight fog volumes, four shafts and four flares per frame. Fog raymarching uses 8–64 steps. Shafts use radial framebuffer sampling with depth occlusion and remain available with fog because the current fog model does not already produce equivalent directional shafts. Fog has height, edge and procedural noise density; anisotropic phase functions and dynamic-light scattering are unavailable. Depth of field uses a 25-tap depth-dependent blur focused at the center of the image.
The native renderer supports up to eight fog volumes, four shafts and four flares per frame. Fog raymarching uses 8–64 steps. Shafts use radial framebuffer sampling with depth occlusion and remain available with fog because the current fog model does not already produce equivalent directional shafts. Fog has height/edge density, procedural or textured noise, anisotropy and per-light scattering. Occlusion samples the available camera depth, so offscreen occluders are outside that approximation. Temporal fog/shaft history reprojects with motion/depth rejection and resets on camera cuts, resize and project changes. Motion blur uses object and camera motion vectors. Depth of field uses a 25-tap spatial blur with configurable focal distance and range.

The native wgpu renderer batches depth-tested transparent geometry and particles. It supports Alpha, Additive and Multiply effects without a separate draw call for every billboard. Empty texture slots use procedural sprites. Geometry-based effects should use the existing mesh/material conventions when selecting assets. Mesh particles use batched source geometry through the PBR path with a 16-step color palette; a missing source mesh is omitted. Custom particle sprite atlases support up to 63 textures per frame, resampled to 256-pixel layers, with flipbook UVs and velocity stretching. Decal projection clips receiver triangles and supports albedo/normal asset textures plus scalar roughness/metallicity; packed ORM, decal surface-layer filtering and explicit material-asset overrides are unavailable. Outline color and thickness use depth-occluded stencil silhouettes; through-wall outlines are unavailable.

The existing material shader tone-maps before the resolved frame is post-processed. Effects grading decodes display colors for its calculations and re-encodes them. Bloom is a thresholded display-range filter; this is **not an HDR bloom pipeline**. Heat haze changes actual sampled framebuffer coordinates. GPU particle simulation is not implemented or advertised. CPU simulation is the supported path.
The native scene path renders linear HDR into `Rgba16Float`; bloom thresholds scene radiance before the final tone map. Heat haze changes sampled framebuffer coordinates. Particle `simulation_mode` supports `Cpu`, `Gpu` and `Auto`. The GPU path keeps particle state in compute buffers and draws it directly; unsupported authored modules fall back to CPU with an Inspector reason. Particle event generation, sorted transparency, collisions, textures/materials and force/noise modules require CPU simulation. The showcase includes a 10,000-particle Auto station. Browser WebGL uses the CPU path.

Unsupported advanced options must not be inferred from a configuration field alone. Current boundaries include GPU particle simulation, runtime cubemap capture, six-face cubemap file layouts, temporal volumetric history, and motion-vector motion blur. Baked local probes use a 2:1 equirectangular HDR/PNG/JPEG asset registered through its `.rmeta` ID; their bounds blend local reflection input and support box parallax correction. Overlap chooses the highest-priority probe per mesh rather than a weighted sum of probes. `cubemap` names that panorama asset. The showcase supplies a generated HDR panorama and sidecar. Water uses the reusable Rust `WaterSurface::sample(world_position)` interface, returning displacement, normal and foam. `RippleWaterSurface` combines a bounded queue of disturbances; `water_surface_mesh` builds a displaced grid. Configure target/source velocity, wavelength, damping, wake angle, foam and normal strength. This is an analytical cosmetic surface model, not a fluid solver. Browser export must be checked independently; the native effect renderer does not establish browser support.
Reflection probes capture six HDR faces in the native renderer on enable, at an interval or on explicit refresh. Captures include sky, scene meshes/lights and transparent particles; camera post effects and local fog post are excluded. Baked `.cubemap` assets describe six square HDR or LDR faces; legacy 2:1 panoramas remain supported. Probe quality controls prefilter sample count, overlap blends weighted probe input, and box parallax correction follows world transforms. Allocation is bounded to 16 maps and 1 GiB of retained probe textures. Water uses the reusable Rust `WaterSurface::sample(world_position)` interface, returning displacement, normal and foam. `RippleWaterSurface` combines a bounded queue of disturbances; `water_surface_mesh` builds a displaced grid. Configure target/source velocity, wavelength, damping, wake angle, foam and normal strength. This is an analytical cosmetic surface model, not a fluid solver. Browser export must be checked independently; the native effect renderer does not establish browser support.

## Projection, light and camera envelopes

Decals support box, sphere, cylinder and thin-plane projectors, receiver layer masks, ORM/emissive maps and a continuous distance fade before the configured render distance. Sphere/cylinder clipping uses a bounded convex approximation. `LightPulse.fade_in` and `fade_out` multiply its intensity curve using seconds within the cycle. Camera impulses expose `Additive`, `Replace` and signed-component `Maximum` blending in priority order. Their reset mode either returns to rest or holds the last active offset after natural completion until an explicit lifecycle command; authored camera transforms stay unchanged.

## Performance and cleanup

Expand Down
Loading
Loading