Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Core Components

bevy_cef provides several essential components that control webview behavior. Understanding these components is crucial for effective use of the library.

Component Overview

ComponentPurposeDefault ValueRequired
CefWebviewUriSpecifies web content URLNone✅ Primary
WebviewSizeControls rendering resolution800×800✅ Auto-added
ZoomLevelControls webview zoom0.0 (default)✅ Auto-added
AudioMutedControls audio outputfalse (unmuted)✅ Auto-added
HostWindowParent window specificationPrimary window❌ Optional

CefWebviewUri

The primary component that defines what web content to display.

Usage

#![allow(unused)]
fn main() {
use bevy_cef::prelude::*;

// Remote web page
let webview = CefWebviewUri::new("https://example.com");

// Local HTML file from assets/ directory
let webview = CefWebviewUri::local("ui/menu.html");

// Equivalent to local() method
let webview = CefWebviewUri::new("cef://localhost/ui/menu.html");
}

Implementation Details

#![allow(unused)]
fn main() {
#[derive(Component, Debug, Clone, PartialEq, Eq, Hash, Reflect)]
#[require(WebviewSize, ZoomLevel, AudioMuted)]
pub struct CefWebviewUri(pub String);
}

The #[require(...)] attribute ensures that every webview automatically gets the essential supporting components.

Methods

  • new(uri): Create with any valid URL (http, https, cef://localhost/)
  • local(path): Create with local file path, automatically prefixed with cef://localhost/

Local File Serving

When using local files, bevy_cef serves them through a custom scheme:

  • Scheme: cef://localhost/
  • Root Directory: Your project's assets/ folder
  • Path Resolution: Relative paths from assets/ root

Example File Structure:

assets/
├── index.html          → cef://localhost/index.html
├── ui/
│   ├── menu.html      → cef://localhost/ui/menu.html
│   └── styles.css     → cef://localhost/ui/styles.css
└── js/
    └── app.js         → cef://localhost/js/app.js

WebviewSize

Controls the internal rendering resolution of the webview, independent of the 3D object size.

Usage

#![allow(unused)]
fn main() {
use bevy::math::Vec2;

// High resolution webview
WebviewSize(Vec2::new(1920.0, 1080.0))

// Standard resolution
WebviewSize(Vec2::new(800.0, 600.0))

// Square webview
WebviewSize(Vec2::splat(512.0))

// Default size
WebviewSize::default () // 800×800
}

Performance Considerations

  • Higher Resolution: Better quality, more memory usage
  • Lower Resolution: Better performance, potential pixelation
  • Aspect Ratio: Match your 3D mesh proportions for best results
#![allow(unused)]
fn main() {
// Example: Widescreen webview for cinematic content
commands.spawn((
CefWebviewUri::local("video-player.html"),
WebviewSize(Vec2::new(1920.0, 800.0)),  // 21:9 aspect ratio
Mesh3d(meshes.add(Quad::new(Vec2::new(4.8, 2.0)))), // Match aspect in 3D
MeshMaterial3d(materials.add(WebviewExtendStandardMaterial::default ())),
));
}

Dynamic Resizing

You can change webview size at runtime:

#![allow(unused)]
fn main() {
fn resize_webview(
    mut webviews: Query<&mut WebviewSize>,
    keyboard: Res<ButtonInput<KeyCode>>,
) {
    if keyboard.just_pressed(KeyCode::KeyR) {
        for mut size in webviews.iter_mut() {
            size.0 *= 1.5; // Increase resolution by 50%
        }
    }
}
}

ZoomLevel

Controls the zoom level of web content within the webview.

Usage

#![allow(unused)]
fn main() {
// Default zoom (browser default)
ZoomLevel(0.0)

// Zoom in 20%
ZoomLevel(1.2)

// Zoom out 20%
ZoomLevel(0.8)

// Maximum zoom in
ZoomLevel(3.0)

// Maximum zoom out  
ZoomLevel(0.25)
}

Zoom Behavior

  • 0.0: Browser default zoom level
  • Positive values: Zoom in (1.2 = 120% of default)
  • Negative values: Zoom out (0.8 = 80% of default)
  • Range: Typically 0.25 to 3.0 (25% to 300%)

Dynamic Zoom Control

#![allow(unused)]
fn main() {
fn zoom_control(
    mut webviews: Query<&mut ZoomLevel>,
    keyboard: Res<ButtonInput<KeyCode>>,
) {
    for mut zoom in webviews.iter_mut() {
        if keyboard.just_pressed(KeyCode::Equal) {
            zoom.0 = (zoom.0 + 0.1).min(3.0); // Zoom in
        }
        if keyboard.just_pressed(KeyCode::Minus) {
            zoom.0 = (zoom.0 - 0.1).max(0.25); // Zoom out
        }
        if keyboard.just_pressed(KeyCode::Digit0) {
            zoom.0 = 0.0; // Reset zoom
        }
    }
}
}

Use Cases

  • Accessibility: Larger text for readability
  • Dense Content: Fit more information in limited space
  • Responsive Design: Adapt to different screen sizes
  • User Preference: Allow users to adjust comfortable viewing size

AudioMuted

Controls whether audio from the webview is muted.

Usage

#![allow(unused)]
fn main() {
// Audio enabled (default)
AudioMuted(false)

// Audio muted
AudioMuted(true)
}

Dynamic Audio Control

#![allow(unused)]
fn main() {
fn toggle_audio(
    mut webviews: Query<&mut AudioMuted>,
    keyboard: Res<ButtonInput<KeyCode>>,
) {
    if keyboard.just_pressed(KeyCode::KeyM) {
        for mut muted in webviews.iter_mut() {
            muted.0 = !muted.0; // Toggle mute state
        }
    }
}
}

Use Cases

  • Background Content: Mute decorative webviews
  • Multiple Webviews: Prevent audio conflicts
  • User Control: Provide mute/unmute functionality
  • Game State: Mute during pause or cutscenes

HostWindow (Optional)

Specifies which Bevy window should be the parent of the webview. If not provided, the primary window is used.

Usage

#![allow(unused)]
fn main() {
// Use primary window (default behavior)
commands.spawn((
CefWebviewUri::local("ui.html"),
// No HostWindow component needed
));

// Specify a particular window
commands.spawn((
CefWebviewUri::local("ui.html"),
HostWindow(secondary_window_entity),
));
}

Multi-Window Applications

#![allow(unused)]
fn main() {
fn setup_multi_window(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>,
) {
    // Create secondary window
    let secondary_window = commands.spawn(Window {
        title: "Secondary Display".to_string(),
        resolution: (800.0, 600.0).into(),
        ..default()
    }).id();

    // Main webview in primary window
    commands.spawn((
        CefWebviewUri::local("main-ui.html"),
        Mesh3d(meshes.add(Plane3d::new(Vec3::Z, Vec2::ONE))),
        MeshMaterial3d(materials.add(WebviewExtendStandardMaterial::default())),
    ));

    // Secondary webview in secondary window
    commands.spawn((
        CefWebviewUri::local("secondary-ui.html"),
        HostWindow(secondary_window),
        Mesh3d(meshes.add(Plane3d::new(Vec3::Z, Vec2::ONE))),
        MeshMaterial3d(materials.add(WebviewExtendStandardMaterial::default())),
    ));
}
}

Component Combinations

Common Patterns

High-Resolution Interactive Display:

#![allow(unused)]
fn main() {
commands.spawn((
CefWebviewUri::local("dashboard.html"),
WebviewSize(Vec2::new(2560.0, 1440.0)),
ZoomLevel(0.0),
AudioMuted(false),
));
}

Compact Information Panel:

#![allow(unused)]
fn main() {
commands.spawn((
CefWebviewUri::local("info-panel.html"),
WebviewSize(Vec2::new(400.0, 300.0)),
ZoomLevel(0.8),
AudioMuted(true),
));
}

Video Player:

#![allow(unused)]
fn main() {
commands.spawn((
CefWebviewUri::new("https://player.example.com"),
WebviewSize(Vec2::new(1920.0, 1080.0)),
ZoomLevel(0.0),
AudioMuted(false), // Keep audio for video
));
}

Background Decoration:

#![allow(unused)]
fn main() {
commands.spawn((
CefWebviewUri::local("animated-bg.html"),
WebviewSize(Vec2::new(1024.0, 1024.0)),
ZoomLevel(0.0),
AudioMuted(true), // No audio for decoration
));
}

Component Lifecycle

Automatic Requirements

When you add CefWebviewUri, the required components are automatically added with default values:

#![allow(unused)]
fn main() {
// You only need to specify this:
commands.spawn(CefWebviewUri::local("page.html"));

// But the entity automatically gets:
// - WebviewSize(Vec2::splat(800.0))
// - ZoomLevel(0.0)  
// - AudioMuted(false)
}

Manual Override

You can override the defaults by adding components explicitly:

#![allow(unused)]
fn main() {
commands.spawn((
CefWebviewUri::local("page.html"),
WebviewSize(Vec2::new(1024.0, 768.0)), // Override default
ZoomLevel(1.2),                        // Override default
AudioMuted(true),                      // Override default
));
}

Runtime Modification

All components can be modified at runtime through standard Bevy systems:

#![allow(unused)]
fn main() {
fn modify_webview_properties(
    mut query: Query<(&mut WebviewSize, &mut ZoomLevel, &mut AudioMuted)>,
    time: Res<Time>,
) {
    for (mut size, mut zoom, mut muted) in query.iter_mut() {
        // Dynamic effects based on time, input, game state, etc.
        let scale = (time.elapsed_secs().sin() + 1.0) / 2.0;
        zoom.0 = 0.8 + scale * 0.4; // Oscillate between 0.8 and 1.2
    }
}
}

Best Practices

Performance Optimization

#![allow(unused)]
fn main() {
// Good: Appropriate resolution for use case
WebviewSize(Vec2::new(800.0, 600.0))   // Standard UI

// Avoid: Excessive resolution unless needed
WebviewSize(Vec2::new(4096.0, 4096.0)) // Only for high-detail content
}

Memory Management

#![allow(unused)]
fn main() {
// Good: Mute background content
commands.spawn((
CefWebviewUri::local("ambient-display.html"),
AudioMuted(true), // Prevent memory usage for audio processing
));
}

User Experience

#![allow(unused)]
fn main() {
// Good: Consistent zoom across related webviews
let ui_zoom = ZoomLevel(1.1);
for ui_component in ["menu.html", "inventory.html", "settings.html"] {
commands.spawn((
CefWebviewUri::local(ui_component),
ui_zoom,
));
}
}

Next Steps