OrbitCamera

Struct OrbitCamera 

Source
pub struct OrbitCamera {
    pub target: Vec3,
    pub distance: f32,
    pub azimuth: f32,
    pub elevation: f32,
    pub fov: f32,
    pub mode: OrbitMode,
    pub sensitivity: f32,
    pub zoom_sensitivity: f32,
    pub min_distance: f32,
    pub max_distance: f32,
}
Expand description

A camera controller that orbits around a target point.

§Example

let mut orbit = OrbitCamera::new()
    .target(Vec3::ZERO)
    .distance(5.0)
    .mode(OrbitMode::Interactive);

// In frame loop:
orbit.update(frame.input, frame.dt);
*frame.camera = orbit.camera();

Fields§

§target: Vec3

Point the camera orbits around.

§distance: f32

Distance from target.

§azimuth: f32

Horizontal angle in radians (yaw).

§elevation: f32

Vertical angle in radians (pitch), clamped to avoid gimbal lock.

§fov: f32

Field of view in radians.

§mode: OrbitMode

Control mode.

§sensitivity: f32

Mouse sensitivity for interactive mode.

§zoom_sensitivity: f32

Scroll zoom sensitivity.

§min_distance: f32

Minimum distance from target.

§max_distance: f32

Maximum distance from target.

Implementations§

Source§

impl OrbitCamera

Source

pub fn new() -> Self

Examples found in repository?
examples/sphere.rs (line 9)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 35)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 28)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 42)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn target(self, target: impl Into<Vec3>) -> Self

Set the target point to orbit around.

Examples found in repository?
examples/sphere.rs (line 10)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 36)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 29)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 43)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn distance(self, distance: f32) -> Self

Set the distance from target.

Examples found in repository?
examples/sphere.rs (line 11)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 37)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 30)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 44)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn mode(self, mode: OrbitMode) -> Self

Set the control mode.

Examples found in repository?
examples/sphere.rs (line 14)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 40)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 33)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 47)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn fov(self, fov_degrees: f32) -> Self

Set the field of view in degrees.

Examples found in repository?
examples/sphere.rs (line 13)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 39)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 32)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 46)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn azimuth(self, azimuth: f32) -> Self

Set the initial azimuth (horizontal angle) in radians.

Source

pub fn elevation(self, elevation: f32) -> Self

Set the initial elevation (vertical angle) in radians.

Examples found in repository?
examples/sphere.rs (line 12)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 38)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 31)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 45)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn sensitivity(self, sensitivity: f32) -> Self

Set mouse sensitivity for interactive mode.

Source

pub fn zoom_sensitivity(self, sensitivity: f32) -> Self

Set scroll zoom sensitivity.

Source

pub fn distance_limits(self, min: f32, max: f32) -> Self

Set distance limits.

Source

pub fn update(&mut self, input: &Input, dt: f32)

Update the camera based on input and delta time.

Examples found in repository?
examples/sphere.rs (line 17)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 48)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 40)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 53)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}
Source

pub fn camera(&self) -> Camera

Get the current camera state.

Examples found in repository?
examples/sphere.rs (line 18)
5fn main() {
6    run_with_config(AppConfig::new().title("Raymarched Sphere"), |ctx| {
7        ctx.hot_effect_world("examples/shaders/sphere.wgsl");
8
9        let mut orbit = OrbitCamera::new()
10            .target(Vec3::ZERO)
11            .distance(3.0)
12            .elevation(0.3)
13            .fov(90.0)
14            .mode(OrbitMode::AutoRotate { speed: 0.5 });
15
16        move |frame| {
17            orbit.update(frame.input, frame.dt);
18            frame.set_camera(orbit.camera());
19        }
20    });
21}
More examples
Hide additional examples
examples/stl_loader.rs (line 49)
10fn main() {
11    run_with_config(
12        AppConfig::new().title("STL Loader Demo").size(1280, 720),
13        |ctx| {
14            ctx.default_font(18.0);
15            ctx.background_color(Color::rgb(0.08, 0.08, 0.12));
16            ctx.enable_mesh_rendering();
17
18            // Load the chess piece STL with the fluent API
19            // - centered() moves the bounding box center to origin
20            // - normalized() scales to fit in a unit cube
21            // - scaled() then scales to desired size
22            let chess_piece = ctx
23                .load("examples/assets/models/chess.stl")
24                .centered()
25                .upright()
26                .normalized()
27                .scaled(2.0)
28                .unwrap();
29
30            // Create some primitive meshes for the scene
31            let plane = ctx.mesh_plane(10.0);
32            let cube = ctx.mesh_cube();
33
34            // Orbit camera for viewing the model
35            let mut orbit = OrbitCamera::new()
36                .target(Vec3::new(0.0, 1.0, 0.0))
37                .distance(5.0)
38                .elevation(0.4)
39                .fov(60.0)
40                .mode(OrbitMode::AutoRotate { speed: 0.3 });
41
42            let mut time = 0.0f32;
43
44            move |frame| {
45                time += frame.dt;
46
47                // Update camera
48                orbit.update(frame.input, frame.dt);
49                frame.set_camera(orbit.camera());
50
51                // Draw the floor
52                frame
53                    .mesh(plane)
54                    .transform(Transform::new())
55                    .color(Color::rgb(0.15, 0.15, 0.18))
56                    .draw();
57
58                // Draw the chess piece on a pedestal
59                // Pedestal base
60                frame
61                    .mesh(cube)
62                    .transform(
63                        Transform::new()
64                            .position(Vec3::new(0.0, 0.15, 0.0))
65                            .scale(Vec3::new(1.5, 0.3, 1.5)),
66                    )
67                    .color(Color::rgb(0.2, 0.2, 0.25))
68                    .draw();
69
70                // The chess piece - positioned on top of pedestal
71                // Slowly bobbing up and down
72                let bob = (time * 1.5).sin() * 0.05;
73                frame
74                    .mesh(chess_piece)
75                    .transform(
76                        Transform::new()
77                            .position(Vec3::new(0.0, 1.3 + bob, 0.0))
78                            .rotation(Quat::from_rotation_y(time * 0.2)),
79                    )
80                    .color(Color::rgb(0.9, 0.85, 0.7))
81                    .draw();
82
83                // Some decorative elements around the scene
84                let decoration_color = Color::rgb(0.3, 0.25, 0.35);
85                for i in 0..4 {
86                    let angle = (i as f32) * std::f32::consts::FRAC_PI_2 + time * 0.1;
87                    let radius = 3.0;
88                    let x = angle.cos() * radius;
89                    let z = angle.sin() * radius;
90                    let height = 0.3 + (time + i as f32).sin().abs() * 0.2;
91
92                    frame
93                        .mesh(cube)
94                        .transform(
95                            Transform::new()
96                                .position(Vec3::new(x, height, z))
97                                .scale(Vec3::new(0.4, height * 2.0, 0.4))
98                                .rotation(Quat::from_rotation_y(time + i as f32)),
99                        )
100                        .color(decoration_color)
101                        .draw();
102                }
103
104                // UI text
105                frame.text(10.0, 10.0, "STL Model Loading Demo");
106                frame.text_color(
107                    10.0,
108                    35.0,
109                    "Drag mouse to orbit, scroll to zoom",
110                    Color::rgb(0.6, 0.6, 0.6),
111                );
112                frame.text_color(
113                    10.0,
114                    55.0,
115                    &format!("FPS: {:.0}", frame.fps()),
116                    Color::rgb(0.5, 0.5, 0.5),
117                );
118            }
119        },
120    );
121}
examples/black_hole.rs (line 41)
4fn main() {
5    run_with_config(AppConfig::new().title("Black Hole"), |ctx| {
6        // Setup: configure render pipeline and load assets
7        ctx.default_font(16.0);
8
9        // Hot-reloadable shaders - edit the files and see changes live!
10        ctx.hot_effect_world("examples/shaders/black_hole.wgsl");
11
12        // Enable 3D mesh rendering (after background, before post-process)
13        ctx.enable_mesh_rendering();
14
15        // Add post-processing after mesh rendering
16        ctx.hot_post_process_world("examples/shaders/gravitational_lensing.wgsl");
17
18        // Create a cube mesh
19        let cube = ctx.mesh_cube();
20
21        // Create a procedural blocky noise texture (16x16 for that pixelated look)
22        let texture = ctx.texture_blocky_noise(16, 42);
23
24        // Create a 2D sprite for the UI (same procedural texture, rendered in 2D layer)
25        let sprite = ctx.sprite_blocky_noise(32, 123);
26
27        // Camera: auto-rotate or interactive orbit
28        let mut orbit = OrbitCamera::new()
29            .target(Vec3::ZERO)
30            .distance(32.0)
31            .elevation(0.3)
32            .fov(80.0)
33            .mode(OrbitMode::Interactive);
34
35        // State for toggling cube visibility
36        let mut cube_visible = true;
37
38        // Frame loop
39        move |frame| {
40            orbit.update(frame.input, frame.dt);
41            frame.set_camera(orbit.camera());
42
43            // Animate the cubes: hover above the black hole and rotate
44            let hover_height = 8.0 + (frame.time * 0.5).sin() * 0.5;
45
46            // Draw a 3x3 grid of textured cubes (if visible)
47            if cube_visible {
48                let spacing = 12.0;
49                for row in 0..3 {
50                    for col in 0..3 {
51                        let idx = row * 3 + col;
52                        // Offset rotation per cube for visual variety
53                        let phase = idx as f32 * 0.3;
54                        let rotation = Quat::from_euler(
55                            glam::EulerRot::YXZ,
56                            frame.time * 0.7 + phase,
57                            frame.time * 0.5 + phase,
58                            frame.time * 0.3 + phase,
59                        );
60
61                        let x = (col as f32 - 1.0) * spacing;
62                        let z = (row as f32 - 1.0) * spacing;
63
64                        frame
65                            .mesh(cube)
66                            .transform(
67                                Transform::new()
68                                    .position(Vec3::new(x, hover_height, z))
69                                    .rotation(rotation)
70                                    .uniform_scale(3.0),
71                            )
72                            .texture(texture)
73                            .draw();
74                    }
75                }
76            }
77
78            // Draw debug overlay
79            let y = frame.panel_titled(10.0, 10.0, 300.0, 120.0, "Debug Overlay");
80            frame.text(18.0, y + 8.0, &format!("FPS: {:.1}", frame.fps()));
81            frame.text_color(
82                18.0,
83                y + 28.0,
84                &format!("Time: {:.1}s", frame.time),
85                Color::rgba(0.7, 0.7, 0.7, 1.0),
86            );
87
88            // Draw the 2D sprite in the bottom-right corner (clickable toggle for cube visibility)
89            let sprite_x = frame.width() as f32 - 80.0;
90            let sprite_y = frame.height() as f32 - 80.0;
91            let sprite_w = 64.0;
92            let sprite_h = 64.0;
93
94            // Check for click on sprite
95            if frame.input.mouse_pressed(MouseButton::Left) {
96                let mouse_pos = frame.input.mouse_position();
97                if mouse_pos.x >= sprite_x
98                    && mouse_pos.x <= sprite_x + sprite_w
99                    && mouse_pos.y >= sprite_y
100                    && mouse_pos.y <= sprite_y + sprite_h
101                {
102                    cube_visible = !cube_visible;
103                }
104            }
105
106            // Draw sprite with tint based on cube visibility
107            let tint = if cube_visible {
108                Color::WHITE
109            } else {
110                Color::rgba(0.4, 0.4, 0.4, 1.0) // Grayed out when cube is hidden
111            };
112            frame.sprite_scaled_tinted(sprite, sprite_x, sprite_y, sprite_w, sprite_h, tint);
113
114            // Draw label above the sprite
115            let label = if cube_visible {
116                "Cubes: Shown"
117            } else {
118                "Cubes: Hidden"
119            };
120            frame.text(sprite_x - 40.0, sprite_y - 20.0, label);
121        }
122    });
123}
examples/scenes.rs (line 54)
18fn main() {
19    run_with_scenes_config(
20        AppConfig::new()
21            .title("Scene Management Demo")
22            .size(1280, 720),
23        |ctx| {
24            ctx.default_font(18.0);
25
26            // Shared assets - available to all scenes
27            let cube = ctx.mesh_cube();
28            let plane = ctx.mesh_plane(30.0);
29
30            // Track current transition type
31            let transition_type = std::rc::Rc::new(std::cell::RefCell::new(TransitionType::Fade));
32            let transition_type_1 = transition_type.clone();
33            let transition_type_2 = transition_type.clone();
34
35            // =========================================================
36            // Scene 1: External view (ship floating in space)
37            // =========================================================
38            ctx.scene("external", |scene| {
39                scene.background_color(Color::rgb(0.02, 0.02, 0.05));
40                scene.enable_mesh_rendering();
41
42                let mut orbit = OrbitCamera::new()
43                    .target(Vec3::ZERO)
44                    .distance(8.0)
45                    .elevation(0.3)
46                    .fov(75.0)
47                    .mode(OrbitMode::AutoRotate { speed: 0.2 });
48
49                let cube = cube;
50                let transition_type = transition_type_1;
51
52                move |frame| {
53                    orbit.update(frame.input, frame.dt);
54                    frame.set_camera(orbit.camera());
55
56                    // Update transition type based on key presses
57                    if frame.input.key_pressed(KeyCode::Digit1) {
58                        *transition_type.borrow_mut() = TransitionType::Instant;
59                    }
60                    if frame.input.key_pressed(KeyCode::Digit2) {
61                        *transition_type.borrow_mut() = TransitionType::Fade;
62                    }
63                    if frame.input.key_pressed(KeyCode::Digit3) {
64                        *transition_type.borrow_mut() = TransitionType::Crossfade;
65                    }
66
67                    // Capture time before building meshes
68                    let time = frame.time;
69                    let ship_rotation = Quat::from_rotation_y(time * 0.1);
70
71                    // Draw a simple "ship" - main body
72                    frame
73                        .mesh(cube)
74                        .transform(
75                            Transform::new()
76                                .scale(Vec3::new(2.0, 0.5, 3.0))
77                                .rotation(ship_rotation),
78                        )
79                        .color(Color::rgb(0.4, 0.4, 0.5))
80                        .draw();
81
82                    // Wings
83                    for x in [-1.5, 1.5] {
84                        frame
85                            .mesh(cube)
86                            .transform(
87                                Transform::new()
88                                    .position(Vec3::new(x, 0.0, 0.0))
89                                    .scale(Vec3::new(1.5, 0.1, 1.0))
90                                    .rotation(ship_rotation),
91                            )
92                            .color(Color::rgb(0.3, 0.3, 0.4))
93                            .draw();
94                    }
95
96                    // Cockpit (blue tinted)
97                    frame
98                        .mesh(cube)
99                        .transform(
100                            Transform::new()
101                                .position(Vec3::new(0.0, 0.3, 0.8))
102                                .scale(Vec3::new(0.6, 0.3, 0.4))
103                                .rotation(ship_rotation),
104                        )
105                        .color(Color::rgb(0.2, 0.3, 0.5))
106                        .draw();
107
108                    // Engine glow
109                    frame
110                        .mesh(cube)
111                        .transform(
112                            Transform::new()
113                                .position(Vec3::new(0.0, 0.0, -1.6))
114                                .scale(Vec3::new(0.4, 0.3, 0.2))
115                                .rotation(ship_rotation),
116                        )
117                        .color(Color::rgb(0.8, 0.4, 0.2))
118                        .draw();
119
120                    // Some "stars" (small cubes in the distance)
121                    let star_positions = [
122                        Vec3::new(10.0, 5.0, -15.0),
123                        Vec3::new(-12.0, 8.0, -20.0),
124                        Vec3::new(8.0, -3.0, -18.0),
125                        Vec3::new(-6.0, 10.0, -25.0),
126                        Vec3::new(15.0, -5.0, -22.0),
127                    ];
128                    for pos in star_positions {
129                        frame
130                            .mesh(cube)
131                            .transform(Transform::new().position(pos).scale(Vec3::splat(0.1)))
132                            .color(Color::rgb(0.9, 0.9, 1.0))
133                            .draw();
134                    }
135
136                    // UI
137                    frame.text(10.0, 10.0, "EXTERNAL VIEW");
138                    frame.text(10.0, 35.0, "Press ENTER to enter cockpit");
139                    frame.text_color(
140                        10.0,
141                        60.0,
142                        &format!(
143                            "Transition: {} (1-3 to change)",
144                            transition_type.borrow().name()
145                        ),
146                        Color::rgb(0.6, 0.6, 0.6),
147                    );
148
149                    // Switch to cockpit on Enter
150                    if frame.input.key_pressed(KeyCode::Enter) {
151                        let transition = transition_type.borrow().to_transition();
152                        frame.switch_to_with("cockpit", transition);
153                    }
154                }
155            });
156
157            // =========================================================
158            // Scene 2: Cockpit interior view
159            // =========================================================
160            ctx.scene("cockpit", |scene| {
161                scene.background_color(Color::rgb(0.05, 0.03, 0.03));
162                scene.enable_mesh_rendering();
163
164                let cube = cube;
165                let plane = plane;
166                let transition_type = transition_type_2;
167                let mut look_yaw = 0.0_f32;
168
169                move |frame| {
170                    // Simple look around with arrow keys
171                    if frame.input.key_down(KeyCode::ArrowLeft) {
172                        look_yaw += 1.5 * frame.dt;
173                    }
174                    if frame.input.key_down(KeyCode::ArrowRight) {
175                        look_yaw -= 1.5 * frame.dt;
176                    }
177
178                    // Build camera with current look direction
179                    let camera = hoplite::Camera::new()
180                        .at(Vec3::new(0.0, 1.0, 0.0))
181                        .looking_at(Vec3::new(look_yaw.sin(), 1.0, -look_yaw.cos()))
182                        .with_fov(90.0);
183                    frame.set_camera(camera);
184
185                    // Update transition type based on key presses
186                    if frame.input.key_pressed(KeyCode::Digit1) {
187                        *transition_type.borrow_mut() = TransitionType::Instant;
188                    }
189                    if frame.input.key_pressed(KeyCode::Digit2) {
190                        *transition_type.borrow_mut() = TransitionType::Fade;
191                    }
192                    if frame.input.key_pressed(KeyCode::Digit3) {
193                        *transition_type.borrow_mut() = TransitionType::Crossfade;
194                    }
195
196                    // Capture time for animations
197                    let time = frame.time;
198
199                    // Draw cockpit interior
200                    // Floor
201                    frame
202                        .mesh(plane)
203                        .transform(Transform::new().scale(Vec3::splat(0.3)))
204                        .color(Color::rgb(0.15, 0.12, 0.12))
205                        .draw();
206
207                    // Console in front
208                    frame
209                        .mesh(cube)
210                        .transform(
211                            Transform::new()
212                                .position(Vec3::new(0.0, 0.6, -1.5))
213                                .scale(Vec3::new(2.0, 0.8, 0.3)),
214                        )
215                        .color(Color::rgb(0.2, 0.2, 0.25))
216                        .draw();
217
218                    // Display screens on console
219                    let screen_positions = [-0.6, 0.0, 0.6];
220                    for (i, x) in screen_positions.iter().enumerate() {
221                        let glow = (time * 2.0 + i as f32).sin() * 0.1 + 0.5;
222                        frame
223                            .mesh(cube)
224                            .transform(
225                                Transform::new()
226                                    .position(Vec3::new(*x, 0.9, -1.3))
227                                    .scale(Vec3::new(0.4, 0.3, 0.05)),
228                            )
229                            .color(Color::rgb(0.1, glow * 0.5, glow))
230                            .draw();
231                    }
232
233                    // Side panels
234                    for x in [-1.2, 1.2] {
235                        frame
236                            .mesh(cube)
237                            .transform(
238                                Transform::new()
239                                    .position(Vec3::new(x, 1.0, -0.5))
240                                    .scale(Vec3::new(0.1, 1.5, 2.0)),
241                            )
242                            .color(Color::rgb(0.12, 0.1, 0.1))
243                            .draw();
244                    }
245
246                    // Ceiling
247                    frame
248                        .mesh(cube)
249                        .transform(
250                            Transform::new()
251                                .position(Vec3::new(0.0, 2.2, -0.5))
252                                .scale(Vec3::new(2.5, 0.1, 3.0)),
253                        )
254                        .color(Color::rgb(0.08, 0.08, 0.1))
255                        .draw();
256
257                    // Window (brighter area showing "space")
258                    frame
259                        .mesh(cube)
260                        .transform(
261                            Transform::new()
262                                .position(Vec3::new(0.0, 1.5, -2.0))
263                                .scale(Vec3::new(1.8, 0.8, 0.02)),
264                        )
265                        .color(Color::rgb(0.02, 0.02, 0.08))
266                        .draw();
267
268                    // Blinking warning lights
269                    let blink = if (time * 3.0).sin() > 0.0 { 0.8 } else { 0.2 };
270                    for x in [-0.9, 0.9] {
271                        frame
272                            .mesh(cube)
273                            .transform(
274                                Transform::new()
275                                    .position(Vec3::new(x, 1.8, -1.4))
276                                    .scale(Vec3::splat(0.08)),
277                            )
278                            .color(Color::rgb(blink, blink * 0.2, 0.0))
279                            .draw();
280                    }
281
282                    // UI
283                    frame.text(10.0, 10.0, "COCKPIT VIEW");
284                    frame.text(10.0, 35.0, "Arrow keys to look around");
285                    frame.text(10.0, 60.0, "Press ESCAPE for external view");
286                    frame.text_color(
287                        10.0,
288                        85.0,
289                        &format!(
290                            "Transition: {} (1-3 to change)",
291                            transition_type.borrow().name()
292                        ),
293                        Color::rgb(0.6, 0.6, 0.6),
294                    );
295
296                    // Switch back to external on Escape
297                    if frame.input.key_pressed(KeyCode::Escape) {
298                        let transition = transition_type.borrow().to_transition();
299                        frame.switch_to_with("external", transition);
300                    }
301                }
302            });
303
304            // Start in external view
305            ctx.start_scene("external");
306        },
307    );
308}

Trait Implementations§

Source§

impl Clone for OrbitCamera

Source§

fn clone(&self) -> OrbitCamera

Returns a duplicate of the value. Read more
1.0.0§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for OrbitCamera

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for OrbitCamera

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> CloneToUninit for T
where T: Clone,

§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> Component for T
where T: Send + Sync + 'static,

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,