//! GPU-driven cloth simulation.
//!
//! Spawn a cloth with [`spawn_cloth`](commands::spawn_cloth) to simulate a
//! tessellated sheet entirely on the GPU. The sheet hangs from the
//! entity's origin, spanning `width` along local +X and `height` down
//! local -Y. Pinned particles follow the entity's global transform every
//! frame, so moving or rotating the entity drags the cloth with it. The
//! entity scale must stay (1, 1, 1).
//!
//! Cloth entities are regular mesh entities: a grid mesh is registered in
//! the mesh cache and the simulation writes deformed vertices straight
//! into the renderer's vertex buffers each frame. The cloth therefore
//! renders through the standard PBR mesh pipeline with full material
//! support (base color, normal, metallic-roughness, emissive, and
//! occlusion textures, IBL, clustered lights), casts and receives
//! shadows, and is pickable. Appearance is controlled entirely by the
//! entity's [`MaterialRef`](crate::ecs::material::components::MaterialRef);
//! [`spawn_cloth`](commands::spawn_cloth) registers a default double-sided
//! material named `Cloth_{entity_id}` that you can replace or edit.
//!
//! The simulation runs in the renderer's `cloth_pass` (part of the
//! default render graph) as compute kernels per frame:
//!
//! 1. **Integrate**: Verlet integration applying gravity and wind. Wind
//!    couples through the cloth normals, so sheets catch gusts like sails.
//! 2. **Solve**: iterative distance constraints (structural, shear, and
//!    bend) run as Jacobi passes that ping-pong between two position
//!    buffers.
//! 3. **Normals**: central-difference normals and tangents feeding both
//!    shading and the next frame's wind coupling.
//! 4. **Writeback**: converts particles into the entity's local space and
//!    writes position, normal, and tangent into the mesh pass and shadow
//!    pass vertex buffers at the cloth's mesh range.
//!
//! There is no per-frame CPU work beyond uniform uploads.
//!
//! Wind is scene-global state stored at `world.resources.wind` (see
//! [`Wind`]). Mutate it at any time; every cloth reads it each frame,
//! scaled by its own [`Cloth::wind_response`].
//!
//! # Spawning Cloth
//!
//! ```ignore
//! let curtain = spawn_cloth(
//!     world,
//!     Cloth {
//!         columns: 128,
//!         rows: 96,
//!         width: 6.0,
//!         height: 4.0,
//!         ..Default::default()
//!     },
//!     Vec3::new(0.0, 4.6, 0.0),
//!     "Curtain".to_string(),
//! );
//!
//! // Appearance comes from the material registry like any mesh entity.
//! world.core.set_material_ref(curtain, MaterialRef::new("red_fabric"));
//! ```
//!
//! # Driving the Wind
//!
//! ```ignore
//! world.resources.wind.direction = Vec3::new(0.0, 0.0, 1.0);
//! world.resources.wind.strength = 8.0;
//! world.resources.wind.gust_strength = 4.0;
//! ```
//!
//! # Resetting
//!
//! [`reset_cloth`](commands::reset_cloth) restores a cloth to its rest pose
//! at the entity's current transform. Changing any field on the [`Cloth`]
//! component rebuilds the simulation state and re-registers the mesh (via
//! [`sync_cloth_meshes_system`](systems::sync_cloth_meshes_system) in the
//! default frame schedule), so tweaking resolution or size at runtime is
//! safe.
//!
//! # Properties
//!
//! | Property | Unit | Description |
//! |----------|------|-------------|
//! | `columns`/`rows` | count | Particle grid resolution (minimum 2 each) |
//! | `width`/`height` | world units | Sheet dimensions |
//! | `pinning` | [`ClothPinning`] | Which particles anchor to the entity |
//! | `stiffness` | 0-1 | Constraint correction strength per iteration |
//! | `damping` | 0-1 | Velocity retained per substep |
//! | `substeps` | count | Simulation steps per frame |
//! | `solver_iterations` | count | Constraint passes per substep (rounded up to even) |
//! | `gravity` | m/s² | Acceleration vector |
//! | `wind_response` | multiplier | Scale applied to the global [`Wind`] |
//! | `ground_height` | world Y | Optional floor plane particles cannot pass |
//! | `texture_tiling` | repeats | Material texture repeats baked into the mesh UVs |
//!
//! [`Cloth`]: components::Cloth
//! [`Cloth::wind_response`]: components::Cloth::wind_response
//! [`ClothPinning`]: components::ClothPinning
//! [`Wind`]: resources::Wind

pub mod commands;
pub mod components;
pub mod resources;
pub mod systems;
