hyperchad_renderer_egui 0.2.0

HyperChad egui renderer package
docs.rs failed to build hyperchad_renderer_egui-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: hyperchad_renderer_egui-0.1.0

HyperChad Egui Renderer

Native desktop UI renderer for HyperChad using the egui immediate mode GUI framework.

Overview

The HyperChad Egui Renderer provides:

  • Native Desktop UI: Render HyperChad components as native desktop applications
  • Immediate Mode GUI: Built on egui's immediate mode architecture
  • Hardware Acceleration: Optional WGPU backend for GPU-accelerated rendering
  • Cross-platform: Works on Windows, macOS, and Linux
  • Layout Engine: Complete CSS-like layout system with flexbox support
  • Interactive Elements: Full support for forms, buttons, and user interactions
  • Image Loading: Async image loading with caching
  • Viewport Management: Scrolling and viewport-aware rendering
  • Event System: Complete action and event handling

Features

Rendering Capabilities

  • Container Rendering: Full HyperChad container hierarchy support
  • Element Types: All HTML-equivalent elements (div, span, input, button, image, etc.)
  • Layout Systems: Flexbox, positioning, margins, padding, borders
  • Typography: Font sizing, text alignment, headings (H1-H6)
  • Styling: Colors, backgrounds, borders, opacity, visibility
  • Responsive Design: Conditional styling and responsive breakpoints

Interactive Features

  • Form Elements: Text inputs, checkboxes, buttons with validation
  • Event Handling: Click, hover, focus, resize, and custom events
  • Action System: Comprehensive action framework with effects
  • State Management: Component state and data binding
  • Navigation: Route handling and page navigation
  • Canvas Support: Canvas rendering for graphics (available in v1 renderer)

Performance Features

  • Efficient Rendering: Immediate mode rendering with minimal overhead
  • Layout Caching: Cached layout calculations for performance
  • Image Caching: Smart image loading and caching system
  • Viewport Culling: Only render visible elements
  • Profiling Support: Optional profiling with puffin and tracing

Installation

Add this to your Cargo.toml:

[dependencies]
hyperchad_renderer_egui = { path = "../hyperchad/renderer/egui" }

# Or with GPU acceleration
# hyperchad_renderer_egui = { path = "../hyperchad/renderer/egui", features = ["wgpu"] }

# Or with profiling
# hyperchad_renderer_egui = { path = "../hyperchad/renderer/egui", features = ["profiling", "profiling-puffin"] }

Usage

Basic Desktop Application

use hyperchad_renderer_egui::EguiRenderer;
use hyperchad_renderer::{Handle, Renderer, ToRenderRunner};
use hyperchad_router::Router;
use hyperchad_actions::logic::Value;
use flume::unbounded;
use std::sync::Arc;

// You need to implement a custom calculator that implements both
// hyperchad_transformer::layout::Calc and hyperchad_renderer_egui::layout::EguiCalc
// See packages/hyperchad/app/src/renderer.rs for a complete example

#[derive(Clone)]
struct MyCalculator;

impl hyperchad_transformer::layout::Calc for MyCalculator {
    fn calc(&self, container: &mut hyperchad_transformer::Container) -> bool {
        // Your layout calculation logic
        true
    }
}

impl hyperchad_renderer_egui::layout::EguiCalc for MyCalculator {
    fn with_context(self, context: eframe::egui::Context) -> Self {
        // Initialize with egui context
        self
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create async runtime
    let runtime = switchy::unsync::runtime::Builder::new().build()?;

    runtime.block_on(async {
        // Create communication channels
        let (action_tx, action_rx) = unbounded();
        let (resize_tx, resize_rx) = unbounded();

        // Create router
        let router = Router::new();

        // Create client info
        let client_info = Arc::new(hyperchad_router::ClientInfo::default());

        // Create layout calculator
        let calculator = MyCalculator;

        // Create renderer
        let mut renderer = EguiRenderer::new(
            router,
            action_tx,
            resize_tx,
            client_info,
            calculator,
        );

        // Initialize window
        renderer.init(
            800.0,    // width
            600.0,    // height
            None,     // x position
            None,     // y position
            None,     // background color
            Some("My App"), // title
            Some("My HyperChad App"), // description
            None,     // viewport
        ).await?;

        // Create and run the application
        let mut runner = renderer.to_runner(Handle::current())?;
        runner.run()?;

        Ok(())
    })
}

Navigation Events

EguiRenderer also exposes wait_for_navigation() for handling link navigation events generated by rendered anchors:

use switchy_async::runtime::Handle;

let renderer = renderer.clone();
Handle::current().spawn(async move {
    while let Some(path) = renderer.wait_for_navigation().await {
        // Route or handle the requested path
        println!("Navigate to: {path}");
    }
});

Rendering HyperChad Components

use hyperchad_template::container;
use hyperchad_renderer::{View, Renderer};

// Create HyperChad components
let view = container! {
    div
        width=800
        height=600
        background="#f0f0f0"
        direction="column"
        padding=20
    {
        h1
            color="blue"
            margin-bottom=20
        {
            "Welcome to HyperChad!"
        }

        div
            direction="row"
            gap=10
        {
            button
                background="green"
                color="white"
                padding=10
                fx-click=fx { show("message") }
            {
                "Show Message"
            }

            button
                background="red"
                color="white"
                padding=10
                fx-click=fx { hide("message") }
            {
                "Hide Message"
            }
        }

        div
            str_id="message"
            background="yellow"
            padding=15
            margin-top=20
            visibility="hidden"
        {
            "Hello from HyperChad!"
        }
    }
};

// Render the view
renderer.render(View::from(view)).await?;

Form Handling

use hyperchad_template::container;

let form_view = container! {
    div
        width=400
        background="white"
        padding=20
        border="1px solid #ccc"
        direction="column"
        gap=15
    {
        h2 { "User Registration" }

        input
            type="text"
            name="username"
            placeholder="Enter username"
            fx-change=fx { set_data_attr("username", event_value()) }
        {}

        input
            type="password"
            name="password"
            placeholder="Enter password"
            fx-change=fx { set_data_attr("password", event_value()) }
        {}

        input
            type="checkbox"
            name="agree"
            fx-change=fx { set_data_attr("agreed", event_value()) }
        {}

        span { "I agree to the terms" }

        button
            background="blue"
            color="white"
            padding="10px 20px"
            fx-click=fx { request_action("submit_form", data_attrs()) }
        {
            "Register"
        }
    }
};

renderer.render(View::from(form_view)).await?;

Image Display

use hyperchad_template::container;

let image_view = container! {
    div
        width=600
        height=400
        direction="column"
        align-items="center"
        gap=20
    {
        h2 { "Image Gallery" }

        img
            src="https://example.com/image.jpg"
            alt="Example Image"
            width=400
            height=300
            fit="cover"
            loading="lazy"
        {}

        div
            direction="row"
            gap=10
        {
            img
                src="/assets/thumb1.jpg"
                width=100
                height=100
                fit="cover"
                fx-click=fx { set_attr("main-image", "src", "/assets/image1.jpg") }
            {}

            img
                src="/assets/thumb2.jpg"
                width=100
                height=100
                fit="cover"
                fx-click=fx { set_attr("main-image", "src", "/assets/image2.jpg") }
            {}
        }
    }
};

renderer.render(View::from(image_view)).await?;

Custom Layout Calculator

For a complete working example of implementing a custom layout calculator with font metrics and default sizing, see packages/hyperchad/app/src/renderer.rs which demonstrates:

  • Creating a calculator that implements both Calc and EguiCalc traits
  • Using Calculator with CalculatorDefaults for font sizes and margins
  • Integrating EguiFontMetrics for accurate text measurement
  • Setting up H1-H6 heading sizes and margins

The calculator is initialized with the egui context via the with_context method when the renderer starts.

Event Handling

use hyperchad_actions::{ActionType, ActionEffect};
use switchy_async::runtime::Handle;

// Handle action events
Handle::current().spawn(async move {
    while let Ok((action_name, value)) = action_rx.recv_async().await {
        match action_name.as_str() {
            "submit_form" => {
                println!("Form submitted: {:?}", value);
                // Process form data
            }
            "navigate" => {
                if let Some(Value::String(url)) = value {
                    println!("Navigate to: {}", url);
                    // Handle navigation
                }
            }
            _ => {
                println!("Unknown action: {}", action_name);
            }
        }
    }
});

// Handle resize events
Handle::current().spawn(async move {
    while let Ok((width, height)) = resize_rx.recv_async().await {
        println!("Window resized: {}x{}", width, height);
        // Handle window resize
    }
});

Canvas Rendering

Note: Canvas rendering is implemented in the v1 renderer only. The v2 renderer has canvas rendering stubbed but not yet implemented.

use hyperchad_renderer::canvas::{CanvasUpdate, CanvasAction, Pos};
use hyperchad_renderer::Color;

let canvas_update = CanvasUpdate {
    target: "my-canvas".to_string(),
    canvas_actions: vec![
        CanvasAction::Clear,
        CanvasAction::StrokeColor(Color { r: 255, g: 0, b: 0, a: Some(255) }),
        CanvasAction::StrokeSize(2.0),
        CanvasAction::Line(Pos(10.0, 10.0), Pos(110.0, 10.0)),
        CanvasAction::FillRect(Pos(10.0, 20.0), Pos(110.0, 70.0)),
    ],
};

renderer.render_canvas(canvas_update).await?;

Feature Flags

  • wgpu: Enable WGPU backend for GPU acceleration (enabled by default)
  • glow: Enable OpenGL backend
  • wayland: Enable Wayland support on Linux
  • x11: Enable X11 support on Linux
  • profiling: Enable performance profiling support
  • profiling-puffin: Enable puffin profiler integration
  • profiling-tracing: Enable tracing profiler integration
  • profiling-tracy: Enable Tracy profiler integration
  • debug: Enable debug rendering features (enabled by default)
  • v1: Use v1 renderer implementation (enabled by default) - Full-featured renderer with complete canvas support, comprehensive action handling, and mature viewport management. This is the production-ready implementation (~3800 lines).
  • v2: Use v2 renderer implementation (enabled by default) - Refactored renderer with modular action handling using the new ActionHandler API from hyperchad_actions. This version uses simplified, more maintainable code architecture (~1000 lines). Canvas rendering and some advanced features are stubbed but not yet fully implemented. When both features are enabled, v2 takes precedence.

Performance Considerations

  • Immediate Mode: UI is rebuilt every frame for maximum flexibility
  • Layout Caching: Layout calculations are cached when possible
  • Image Caching: Images are cached to avoid repeated loading
  • Viewport Culling: Only visible elements are processed
  • GPU Acceleration: Use WGPU backend for better performance

Dependencies

  • eframe: egui application framework
  • egui: Immediate mode GUI library
  • HyperChad Core: Template, transformer, and action systems
  • switchy_async: Runtime abstraction for async operations
  • Image: Image processing and loading

Integration

This renderer is designed for:

  • Desktop Applications: Native desktop apps with rich UI
  • Development Tools: IDE-like applications and editors
  • Games: Game UI and tools with immediate mode benefits
  • Prototyping: Rapid UI prototyping and development
  • Cross-platform Apps: Applications targeting multiple desktop platforms

Limitations

  • Mobile Support: Not designed for mobile platforms
  • Web Deployment: Cannot run in web browsers
  • Immediate Mode: UI state must be managed externally
  • Memory Usage: Higher memory usage due to immediate mode architecture