{"id":17994951,"url":"https://github.com/totalkrill/bevy_mod_lookat","last_synced_at":"2025-09-10T19:41:42.113Z","repository":{"id":252245399,"uuid":"839866955","full_name":"TotalKrill/bevy_mod_lookat","owner":"TotalKrill","description":"microplugin for bevy that syncs the rotation of entites towards a selected target","archived":false,"fork":false,"pushed_at":"2024-11-30T12:19:45.000Z","size":4063,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-21T01:51:00.078Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TotalKrill.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-08T13:37:11.000Z","updated_at":"2024-11-30T12:19:48.000Z","dependencies_parsed_at":"2024-08-25T16:29:17.488Z","dependency_job_id":"860c9568-3e8f-4f7a-b53b-b5ccbedc384f","html_url":"https://github.com/TotalKrill/bevy_mod_lookat","commit_stats":null,"previous_names":["totalkrill/bevy_mod_lookat"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalKrill%2Fbevy_mod_lookat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalKrill%2Fbevy_mod_lookat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalKrill%2Fbevy_mod_lookat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalKrill%2Fbevy_mod_lookat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TotalKrill","download_url":"https://codeload.github.com/TotalKrill/bevy_mod_lookat/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245576528,"owners_count":20638125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-29T20:17:17.496Z","updated_at":"2025-09-10T19:41:42.087Z","avatar_url":"https://github.com/TotalKrill.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bevy_mod_lookat\n\n[![Crates.io](https://img.shields.io/crates/v/bevy_mod_lookat)](https://crates.io/crates/bevy_mod_lookat)\n[![Documentation](https://docs.rs/bevy_mod_lookat/badge.svg)](https://docs.rs/bevy_mod_lookat)\n[![License](https://img.shields.io/crates/l/bevy_mod_lookat)](https://opensource.org/licenses/MIT)\ne\n\nA Bevy Plugin and library to help with rotating an entity towards a target even through hierarchies\n\n![](simple.gif)\n\n## Features\n\n- Updates an entities rotation in the world towards another entity or target\n\n| Bevy version | Crate version |\n| ------------ | ------------- |\n| 0.16         | 0.3-0.4       |\n| 0.15         | 0.2           |\n| 0.14         | 0.1           |\n\n## Example\n\n``` rust\n//! A simple 3D scene with light shining over a cube sitting on a plane.\nuse bevy::{color::palettes::css::*, prelude::*, render::primitives::Aabb};\nuse bevy_mod_lookat::*;\n\nfn main() {\n    App::new()\n        .add_plugins(DefaultPlugins)\n        .add_plugins(RotateTowardsPlugin::default())\n        .add_systems(Startup, setup)\n        .add_systems(Update, (mover, rotate).chain())\n        .add_systems(\n            PostUpdate,\n            (draw_axes, draw_forward).after(TransformSystem::TransformPropagate),\n        )\n        .run();\n}\n\n#[derive(Component)]\nstruct Move;\n\n#[derive(Component)]\nstruct Rotate;\n\n#[derive(Component)]\nstruct ShowAxes;\n\n#[derive(Component)]\nstruct ShowForward;\n\nfn draw_axes(mut gizmos: Gizmos, query: Query\u003c(\u0026GlobalTransform, \u0026Aabb), With\u003cShowAxes\u003e\u003e) {\n    for (\u0026transform, \u0026aabb) in \u0026query {\n        let t = transform.compute_transform();\n\n        let length = aabb.half_extents.length();\n        gizmos.axes(t, length);\n    }\n}\nfn draw_forward(mut gizmos: Gizmos, query: Query\u003c\u0026GlobalTransform, With\u003cShowForward\u003e\u003e) {\n    for \u0026transform in \u0026query {\n        let t = transform.compute_transform();\n\n        gizmos.line(\n            t.translation,\n            t.translation + t.forward() * 6.0,\n            Color::BLACK,\n        );\n    }\n}\nfn rotate(mut query: Query\u003c\u0026mut Transform, With\u003cRotate\u003e\u003e, time: Res\u003cTime\u003e) {\n    for mut transform in \u0026mut query {\n        transform.rotate_y(time.delta_secs() / 2.);\n        transform.rotate_x(time.delta_secs());\n    }\n}\nconst SPEED: f32 = 1.0;\nfn mover(time: Res\u003cTime\u003e, mut ents: Query\u003c\u0026mut Transform, With\u003cMove\u003e\u003e) {\n    let distance = 2.0;\n    for mut ent in ents.iter_mut() {\n        ent.translation.x = distance * f32::sin(SPEED * time.elapsed().as_secs_f32());\n        ent.translation.z = distance * f32::cos(SPEED * time.elapsed().as_secs_f32());\n        ent.translation.y =\n            1.5 + 0.5 * distance * f32::cos(SPEED * 3.0 * time.elapsed().as_secs_f32());\n    }\n}\n/// set up a simple 3D scene\nfn setup(\n    mut commands: Commands,\n    mut meshes: ResMut\u003cAssets\u003cMesh\u003e\u003e,\n    mut materials: ResMut\u003cAssets\u003cStandardMaterial\u003e\u003e,\n) {\n    // circular base\n    commands.spawn((\n        Mesh3d(meshes.add(Circle::new(4.0))),\n        MeshMaterial3d(materials.add(Color::WHITE)),\n        Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),\n    ));\n\n    let target_id = commands\n        .spawn((\n            Mesh3d(meshes.add(Cuboid::new(0.05, 0.05, 0.05))),\n            MeshMaterial3d(materials.add(Color::from(CRIMSON))),\n            Transform::from_xyz(1.0, 0.5, 1.0),\n            Move,\n            Rotate,\n            ShowAxes,\n        ))\n        .id();\n\n    // cube\n    commands\n        .spawn((\n            Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),\n            MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))),\n            Transform::from_xyz(3.5, 0.5, 0.0),\n            ShowAxes,\n        ))\n        .with_children(|commands| {\n            commands\n                .spawn((\n                    Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),\n                    MeshMaterial3d(materials.add(Color::srgb_u8(124, 100, 255))),\n                    Transform::from_xyz(0.0, 0.5, 0.0),\n                    Rotate,\n                    ShowAxes,\n                ))\n                .with_children(|parent| {\n                    parent.spawn((\n                        Mesh3d(meshes.add(Cuboid::new(0.3, 0.1, 2.0))),\n                        MeshMaterial3d(materials.add(Color::from(GREEN))),\n                        Transform::from_xyz(0.0, 0.7, 0.0),\n                        RotateTo {\n                            entity: target_id,\n                            // this choses what the flat side should be in relation towards\n                            updir: UpDirection::Parent,\n                        },\n                        ShowForward,\n                    ));\n                });\n        });\n    // light\n    commands.spawn((\n        PointLight {\n            shadows_enabled: true,\n            ..default()\n        },\n        Transform::from_xyz(4.0, 8.0, 4.0),\n    ));\n    // camera\n    commands.spawn((\n        Camera3d::default(),\n        Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),\n    ));\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use test::bench::Bencher;\n\n    #[bench]\n    fn bench(b: \u0026mut Bencher) {\n        let mut app = App::new();\n        app.add_plugins(MinimalPlugins);\n        let mut commands = app.world_mut().commands();\n        // circular base\n        commands.spawn(SpatialBundle {\n            transform: Transform::from_rotation(Quat::from_rotation_x(\n                -std::f32::consts::FRAC_PI_2,\n            )),\n            ..default()\n        });\n\n        for i in 0..100 {\n            let target_id = commands\n                .spawn((\n                    SpatialBundle {\n                        transform: Transform::from_xyz(i as f32 * 1.0, 0.5, 1.0),\n                        ..default()\n                    },\n                    Move,\n                    Rotate,\n                ))\n                .id();\n\n            // cube\n            commands\n                .spawn((SpatialBundle {\n                    transform: Transform::from_xyz(3.5, 0.5, i as f32 * 1.0),\n                    ..default()\n                },))\n                .with_children(|commands| {\n                    commands\n                        .spawn((\n                            Rotate,\n                            SpatialBundle {\n                                transform: Transform::from_xyz(0.0, i as f32 * 0.5, 0.0),\n                                ..default()\n                            },\n                        ))\n                        .with_children(|parent| {\n                            parent.spawn((\n                                SpatialBundle {\n                                    transform: Transform::from_xyz(0.0, i as f32 * 0.7, 0.0),\n                                    ..default()\n                                },\n                                RotateTo {\n                                    entity: target_id,\n                                    // this choses what the flat side should be in relation towards\n                                    updir: UpDirection::Parent,\n                                },\n                                ShowForward,\n                            ));\n                        });\n                });\n        }\n\n        app.add_plugins(RotateTowardsPlugin)\n            .add_systems(Update, (mover, rotate));\n\n        // move past the Startup state\n        for i in 0..20 {\n            app.update();\n        }\n\n        b.iter(|| {\n            app.update();\n        });\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftotalkrill%2Fbevy_mod_lookat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftotalkrill%2Fbevy_mod_lookat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftotalkrill%2Fbevy_mod_lookat/lists"}