Crates.io | leptos_verlet |
lib.rs | leptos_verlet |
version | 2.0.2 |
created_at | 2025-06-22 17:09:24.046476+00 |
updated_at | 2025-08-06 14:37:15.104438+00 |
description | An engine to perform Verlet simulations in Leptos apps. |
homepage | https://github.com/Flan8er/leptos_verlet |
repository | https://github.com/Flan8er/leptos_verlet |
max_upload_size | |
id | 1721788 |
size | 263,025 |
An engine that allows the addition of interactive verlet simulations into any leptos app.
Check out my other projects here!
use leptos_verlet::prelude::*;
#[component]
pub fn App() -> impl IntoView {
let simulation_container = NodeRef::<Div>::new();
let active_modifier: RwSignal<ModificationTarget> = RwSignal::new(ModificationTarget::None);
view! {
<VerletConfigProvider/>
<main class="w-screen h-screen flex items-center justify-center overflow-hidden relative">
<ElementPane active_modifier/>
<InfoModal active_modifier/>
<div
node_ref=simulation_container
class="w-full h-full relative"
>
<VerletCanvas parent_element=simulation_container/>
<MouseMonitor active_modifier/>
</div>
<ControlPane active_modifier/>
</main>
}
}
In the ^1.2 update, a new function is exposed to allow custom meshes to be imported and attached to a simulation Point. The mesh will track, follow, and reorient relative to whatever Point it's attached to.
// Imports and spawns the mesh into the simulation
// Must be ran inside a reactive context
model_loader("/static/monkey.glb", "monkey.glb", 0);
// To attach the mesh to a SpawnNode:
SpawnNode {
attachment: Some(String::from("monkey.glb")),
..default()
}
The SpawnNode type also takes in an extra argument: "attachment". This is an optional String where the value is the same model_name used in the model_loader function ("monkey.glb" in the above code). This essentially tells the mesh to follow whatever point it is attached to.
Any shape can be created, simulated, and styled using the built in spawner that reads from a Vec of SpawnNode.
pub struct SpawnNode {
/// The point to spawn.
pub point: Point,
/// A list of connections this point should share with other points.
pub connection: Option<Vec<Vec3>>,
/// The material of the point. Note, any 'locked' point will be displayed as red.
pub point_material: MaterialType,
/// A specified material for each connection.
pub connection_material: Option<Vec<MaterialType>>,
/// The mesh of the point.
pub point_mesh: MeshType,
/// A specified mesh for each connection.
pub connection_mesh: Option<Vec<MeshType>>,
/// The diameter of the point.
pub point_size: f32,
/// The thickness of the connection.
pub connection_size: Option<Vec<f32>>,
/// The model_name for any imported model to be attached to this point.
pub attachment: Option<String>,
}
pub struct SpawnRequest {
pub mesh_network: Vec<SpawnNode>,
}
Shown below is a verbose use case for spawning a square to be used to visualize the mesh network system. As much as feasible, a system should be created for programmatically generating these structures.
The desired vertices of the shape are constructed (below the initial velocity is set to zero by giving the point the same "current position" as "previous position"), and then added to a SpawnNode with the desired connection vertices and mesh/material styling. A mesh_network is then constructed and sent as a spawn request.
use leptos_verlet::prelude::*;
let spawn_request = expect_context::<SpawnSender>();
let square_size = 0.45;
let point_size = 0.025;
let stick_size = 0.01;
let point_mesh = MeshType::Sphere;
let stick_mesh = MeshType::Cuboid;
let point_material = MaterialType::Color([1., 1., 1., 1.]); // The spawned points will be pure white
let stick_material = MaterialType::Color([1., 1., 1., 0.75]); // The spawned connections will be opaque white
let bottom_left = Vec3::new(-square_size / 2., 0., 0.);
let bottom_right = Vec3::new(square_size / 2., 0., 0.);
let top_right = Vec3::new(square_size / 2., square_size, 0.);
let top_left = Vec3::new(-square_size / 2., square_size, 0.);
let bottom_left_node = SpawnNode {
point: Point::new(bottom_left, bottom_left, false),
connection: Some(vec![top_left, bottom_right]),
point_material: point_material.clone(),
connection_material: Some(vec![stick_material.clone(), stick_material.clone()]),
point_mesh: point_mesh.clone(),
connection_mesh: Some(vec![stick_mesh.clone(), stick_mesh.clone()]),
point_size: point_size,
connection_size: Some(vec![stick_size, stick_size]),
..default()
};
let bottom_right_node = SpawnNode {
point: Point::new(bottom_right, bottom_right + 0.5, false),
connection: Some(vec![bottom_left, top_right, top_left]),
point_material: point_material.clone(),
connection_material: Some(vec![
stick_material.clone(),
stick_material.clone(),
stick_material.clone(),
]),
point_mesh: point_mesh.clone(),
connection_mesh: Some(vec![
stick_mesh.clone(),
stick_mesh.clone(),
stick_mesh.clone(),
]),
point_size: point_size,
connection_size: Some(vec![stick_size, stick_size, stick_size]),
..default()
};
let top_right_node = SpawnNode {
point: Point::new(top_right, top_right, false),
connection: Some(vec![bottom_right, top_left]),
point_material: point_material.clone(),
connection_material: Some(vec![stick_material.clone(), stick_material.clone()]),
point_mesh: point_mesh.clone(),
connection_mesh: Some(vec![stick_mesh.clone(), stick_mesh.clone()]),
point_size: point_size,
connection_size: Some(vec![stick_size, stick_size]),
..default()
};
let top_left_node = SpawnNode {
point: Point::new(top_left, top_left, false),
connection: Some(vec![bottom_left, top_right, bottom_right]),
point_material: point_material.clone(),
connection_material: Some(vec![
stick_material.clone(),
stick_material.clone(),
stick_material.clone(),
]),
point_mesh: point_mesh.clone(),
connection_mesh: Some(vec![
stick_mesh.clone(),
stick_mesh.clone(),
stick_mesh.clone(),
]),
point_size: point_size,
connection_size: Some(vec![stick_size, stick_size, stick_size]),
..default()
};
let mesh_network = vec![
bottom_left_node,
bottom_right_node,
top_right_node,
top_left_node,
];
let spawn_custom = {
let spawn_request = spawn_request.clone();
let mesh_network = mesh_network.clone();
move |_| {
spawn_request
.send(SpawnRequest::new(mesh_network.clone()))
.ok();
}
};
Crate version | Compatible Leptos version |
---|---|
1.0 | 0.7 |
2.0 | 0.8 |