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

Basic Concepts

Understanding these fundamental concepts will help you make the most of bevy_cef in your projects.

Multi-Process Architecture

bevy_cef follows a multi-process architecture similar to modern web browsers:

Browser Process

  • Main Application: Your Bevy game/app runs here
  • CEF Management: Handles browser creation and management
  • IPC Coordination: Manages communication with render processes

Render Process

  • Web Content: Each webview runs in a separate process
  • Isolation: Crashes in web content don't affect your main application
  • Sandboxing: Enhanced security through process separation

Benefits

  • Stability: Web content crashes won't crash your game
  • Performance: CPU-intensive web content won't block your game loop
  • Security: Sandboxed execution of untrusted web content

Core Components

bevy_cef provides several key components that work together:

CefWebviewUri

The primary component that defines what web content to display:

#![allow(unused)]
fn main() {
// Remote web page
CefWebviewUri::new("https://example.com")

// Local HTML file from assets/
CefWebviewUri::local("ui/menu.html")

// Equivalent to above
CefWebviewUri::new("cef://localhost/ui/menu.html")
}

WebviewSize

Controls the rendering resolution of the webview (not the 3D object size):

#![allow(unused)]
fn main() {
WebviewSize(Vec2::new(1920.0, 1080.0))  // High resolution
WebviewSize(Vec2::new(800.0, 600.0))    // Standard resolution
WebviewSize::default()                   // 800x800 pixels
}

Material Integration

Webviews integrate with Bevy's material system:

#![allow(unused)]
fn main() {
// Standard material with webview texture
WebviewExtendStandardMaterial::default()

// Custom material properties
WebviewExtendStandardMaterial {
    base: StandardMaterial {
        unlit: true,
        emissive: Color::WHITE.into(),
        ..default()
    },
    ..default()
}
}

Component Requirements

When you add a CefWebviewUri component, bevy_cef automatically requires several other components:

#![allow(unused)]
fn main() {
#[require(WebviewSize, ZoomLevel, AudioMuted)]
pub struct CefWebviewUri(pub String);
}

This means every webview entity automatically gets:

  • WebviewSize: Default 800x800 resolution
  • ZoomLevel: Default zoom (0.0 = browser default)
  • AudioMuted: Default unmuted (false)

Rendering Modes

bevy_cef supports different rendering approaches:

3D Mesh Rendering

Render web content on 3D objects in your world:

#![allow(unused)]
fn main() {
commands.spawn((
    CefWebviewUri::local("interface.html"),
    Mesh3d(meshes.add(Plane3d::new(Vec3::Z, Vec2::ONE))),
    MeshMaterial3d(materials.add(WebviewExtendStandardMaterial::default())),
));
}

2D Sprite Rendering

Render web content as UI overlays:

#![allow(unused)]
fn main() {
commands.spawn((
    CefWebviewUri::local("hud.html"),
    Sprite::default(),
    WebviewSpriteMaterial::default(),
));
}

Local Asset Serving

bevy_cef includes a built-in web server that serves files from your assets/ directory:

Custom Scheme

  • Scheme: cef://localhost/
  • Path Mapping: assets/ directory maps to the root
  • Example: assets/ui/menu.htmlcef://localhost/ui/menu.html

Supported File Types

  • HTML, CSS, JavaScript
  • Images (PNG, JPG, SVG, etc.)
  • Fonts (WOFF, TTF, etc.)
  • JSON, XML, and other data files

Asset Organization

assets/
├── ui/
│   ├── menu.html
│   ├── styles.css
│   └── script.js
├── images/
│   └── logo.png
└── data/
    └── config.json

Inter-Process Communication (IPC)

bevy_cef provides three communication patterns:

1. JavaScript to Bevy (JS Emit)

Send events from web content to Bevy systems:

// In your HTML/JavaScript
window.cef.emit('player_action', { action: 'jump', power: 10 });
fn main(){
    App::new()
        .add_plugins(JsEmitEventPlugin::<PlayerAction>::default())
    // ...
}

// In your Bevy system
#[derive(Event, Deserialize)]
struct PlayerAction {
    action: String,
    power: i32,
}

fn handle_player_action(trigger: Trigger<PlayerAction>) {
    let action = trigger.event();
    info!("Player action: {} with power {}", action.action, action.power);
}

2. Bevy to JavaScript (Host Emit)

Send events from Bevy to web content:

#![allow(unused)]
fn main() {
// In your Bevy system
commands.entity(webview_entity).trigger(HostEmitEvent {
    event_name: "score_update".to_string(),
    data: json!({ "score": 1000, "level": 3 }),
});
}
// In your HTML/JavaScript
window.cef.listen('score_update', (data) => {
    document.getElementById('score').textContent = data.score;
    document.getElementById('level').textContent = data.level;
});

3. Bevy Remote Protocol (BRP)

Please see here for about the Bevy Remote Protocol (BRP).

Bidirectional RPC calls for complex interactions:

#![allow(unused)]
fn main() {
// Register BRP method in Bevy
app.add_plugins(RemotePlugin::default().with_method("get_player_stats", get_stats));
}
// Call from JavaScript
const stats = await window.cef.brp({ 
    method: 'get_player_stats',
    params: { playerId: 42 }
});

User Interaction

Input Handling

Webviews automatically receive keyboard and mouse input when focused:

  • Keyboard: All keyboard events are forwarded
  • Mouse: Click, scroll, and hover events work naturally
  • Focus: Multiple webviews can coexist; input goes to the focused one

Control web navigation programmatically:

#![allow(unused)]
fn main() {
commands.entity(webview).trigger(RequestGoBack);
commands.entity(webview).trigger(ReqeustGoForward);
}

Zoom Control

Manage zoom levels per webview:

#![allow(unused)]
fn main() {
// Set zoom level (0.0 = default, positive = zoom in, negative = zoom out)
commands.entity(webview).insert(ZoomLevel(1.2));

// Reset to default zoom
commands.entity(webview).insert(ZoomLevel(0.0));
}

Developer Experience

Developer Tools

Access Chrome DevTools for debugging:

#![allow(unused)]
fn main() {
// Show developer tools for a webview
commands.entity(webview).trigger(RequestShowDevTool);

// Close developer tools
commands.entity(webview).trigger(RequestCloseDevtool);
}

Hot Reload

Local assets automatically reload when changed during development.

Best Practices

Component Organization

#![allow(unused)]
fn main() {
// Good: Group related components
commands.spawn((
    // The uri convert to `cef://localhost/index.html`
    CefWebviewUri::local("index.html"),
    WebviewSize(Vec2::new(1920.0, 200.0)),
    ZoomLevel(0.8),
    AudioMuted(true),
    Transform::from_translation(Vec3::new(0.0, 5.0, 0.0)),
    Mesh3d(meshes.add(Quad::new(Vec2::new(4.0, 1.0)))),
    MeshMaterial3d(materials.add(WebviewExtendStandardMaterial::default())),
));
}

Next Steps

Now that you understand the basic concepts: