App Module Architecture
The App module implements a Manager-based Architecture where the App class serves as a slim orchestrator. Responsibilities are separated into dedicated managers that handle specific domains: data management, file loading, rendering, animation, and user interaction. This design improves modularity, testability, and scalability for scenes that mix static and ONNX-driven splats.
High-level layout
┌────────────────────────────────────────────────────────────┐
│ Presentation layer │
│ UIController ◄───► DOMElements ◄───► Canvas/Events │
└───────────────▲────────────────────────────────────────────┘
│ callbacks
┌───────────────┴────────────────────────────────────────────┐
│ Application layer │
│ App (orchestrator) │
│ - initWebGPU_onnx() │
│ - create GaussianRenderer │
│ - wire managers & start RenderLoop │
└───────────────┬────────────────────────────────────────────┘
│ owns
┌───────────────┴────────────────────────────────────────────┐
│ Manager layer │
│ ModelManager FileLoader ONNXManager │
│ CameraManager AnimationManager RenderLoop │
└───────────────┬────────────────────────────────────────────┘
│ uses
┌───────────────┴────────────────────────────────────────────┐
│ Core subsystems │
│ PointCloud / DynamicPointCloud • GaussianRenderer │
│ Preprocess (SH/RGB) • GPURSSorter │
└────────────────────────────────────────────────────────────┘
Key Design Principles
- Separation of Concerns: Each manager handles a specific domain (models, files, camera, animation, rendering)
- Facade Pattern: App class provides a simple public API while delegating to managers
- Multiple Model Support:
ModelManagersupports concurrent models (PLY, SPZ, KSplat, SPLAT, SOG, ONNX, FBX) - Format Agnostic: Uses
defaultLoaderfrom IO module for unified format handling - ORT Integration: WebGPU device sharing with ONNX Runtime for efficient GPU usage
- Render Loop Ownership:
RenderLoopencapsulates the RAF lifecycle; App only launches and monitors it - Dynamic Content: ONNX integration runs GPU-only with shared devices—no CPU readbacks
Responsibility Quick Reference
| Manager | Responsibility | Key Features |
|---|---|---|
| App | Orchestration, dependency injection, UI callback surface | Public API facade, initialization coordination |
| ModelManager | Metadata storage, visibility filters, model tracking | ModelEntry management, ID generation, capacity limits |
| FileLoader | Unified asset ingestion | Supports PLY, SPZ, KSplat, SPLAT, SOG, compressed PLY, FBX |
| ONNXManager | ONNX model lifecycle | Device sharing, session management, dynamic generators |
| CameraManager | Camera and controller management | Orbit/FPS switching, auto-framing, resize handling |
| AnimationManager | Dynamic content updates | Per-frame updates, throttling, performance tracking |
| RenderLoop | Frame cycle coordination | RAF loop, FPS counting, render pipeline, state management |
Initialization Flow
- DOM Validation - Query and cache DOM elements via
DOMElements - Manager Creation - Instantiate all managers (Model, File, ONNX, Camera, Animation, RenderLoop)
- ORT Environment - Initialize ONNX Runtime environment with WASM paths
- WebGPU Context - Acquire shared WebGPU device with
initWebGPU_onnx(with fallback) - Renderer Setup - Instantiate
GaussianRendererand ensure sorter is ready - Camera Initialization - Initialize perspective camera and default controller (FPS)
- UI Binding - Bind event listeners via
UIController - Resize Handler - Setup window resize handler
- RenderLoop Configuration - Initialize RenderLoop with GPU context and callbacks
- Start Loop - Begin the animation frame loop
Event & Data Flow
Example Flows
File Loading (Gaussian formats):
File dropped → UIController.onFileLoad → App.loadFile →
App.loadGaussianModel → FileLoader.loadFile →
defaultLoader (IO module) → PointCloud creation →
ModelManager.addModel → RenderLoop renders
ONNX Model Loading:
App.loadONNXModel → ONNXManager.loadONNXModel →
ONNXGenerator creation → DynamicPointCloud creation →
ModelManager.addModel → AnimationManager tracks →
RenderLoop updates per-frame → Renderer renders
Camera Control:
UI button click → UIController.onControllerSwitch →
App.switchController → CameraManager.switchController →
Controller update → RenderLoop uses new camera matrix
Dynamic Animation:
App.controlDynamicAnimation → AnimationManager.controlDynamicAnimation →
RenderLoop.updateDynamicPointClouds → DynamicPointCloud.update →
ONNX inference → GPU buffer update → Renderer renders
WebGPU Context Sharing
initWebGPU_onnx() implements a two-stage initialization:
- ORT Integration Attempt: Tries to reuse the ONNX Runtime device (optionally forcing creation with a dummy model)
- Fallback: If ORT integration fails, falls back to standalone WebGPU initialization
Benefits
- Single Device: Both ONNX inference and rendering use the same GPU device
- Resource Efficiency: Shared device reduces memory overhead
- Feature Consistency: Requested limits and features (
shader-f16, timestamp queries) are applied once - Buffer Compatibility: No hidden devices, eliminating buffer compatibility issues
- Graceful Degradation: Fallback ensures the app works even if ORT integration fails
Configuration Options
interface WebGPUInitOptions {
preferShareWithOrt?: boolean; // Prefer ORT device sharing
dummyModelUrl?: string | null; // Force ORT device creation
adapterPowerPreference?: 'high-performance' | 'low-power';
allowOwnDeviceWhenOrtPresent?: boolean; // Allow separate device
}
Render Loop Ownership
RenderLoop owns the entire frame cycle:
- Scheduling:
requestAnimationFramelifecycle management - Timing: Delta time calculation and FPS counting
- State: Background color, Gaussian scale, render state
- Coordination: Per-frame calls to managers and renderer
Frame Cycle
Each frame executes in order:
- Calculate Delta Time -
dt = currentTime - lastTime - Camera Update -
CameraManager.update(dt) - Dynamic Updates -
AnimationManager.updateDynamicPointClouds(view, proj, time) - FPS Counting - Update internal counters
- Rendering -
GaussianRenderer.prepareMulti(...)/renderMulti(...) - Callback Invocation - FPS and point count callbacks
App Public API
App exposes test-friendly helpers that delegate to managers:
Model Management:
- getModels() - Get simplified model info
- getModelWithPointCloud(type, id?) - Get full model entry
- getFullModels() - Get all model entries
Loading:
- loadGaussian(input, options?) - Load any Gaussian format
- loadSPZ(input, options?) - Load SPZ format
- loadKSplat(input, options?) - Load KSplat format
- loadSplat(input, options?) - Load SPLAT format
- loadSOG(input, options?) - Load SOG format
- loadONNXModel(path, name?, staticInference?) - Load ONNX model
Camera:
- resetCamera() - Reset to default position
- switchController('orbit'|'fps') - Switch camera mode
- getCameraMatrix() - Get current view matrix
- getProjectionMatrix() - Get current projection matrix
Rendering:
- setGaussianScale(scale) - Set splat size
- getGaussianScale() - Get current scale
- setBackgroundColor(color) - Set background RGBA
- getBackgroundColor() - Get current background
Animation:
- controlDynamicAnimation(action, speed?) - Control dynamic models
- setDynamicAnimationTime(time) - Set animation time
- getDynamicPerformanceStats() - Get performance metrics
Diagnostics & Debugging
Debug Information
App.getDebugInfo() aggregates comprehensive state from all managers:
{
app: {
initialized: boolean,
canvas: { width, height },
supportedFormats: { gaussian, onnx, models, all }
},
models: {
count: number,
capacity: number,
totalPoints: number,
visiblePoints: number
},
camera: CameraManager.getDebugInfo(),
animation: AnimationManager.getDebugInfo(),
renderLoop: RenderLoop.getDebugInfo(),
onnx: {
hasModels: boolean,
modelCount: number,
performanceStats: object
}
}
Manager Access
For advanced usage, managers can be accessed directly:
app.getModelManager()- Direct ModelManager accessapp.getONNXManager()- Direct ONNXManager accessapp.getCameraManager()- Direct CameraManager accessapp.getAnimationManager()- Direct AnimationManager accessapp.getRenderLoop()- Direct RenderLoop access
Format Support
App.getSupportedFormats() returns all supported file extensions:
{
gaussian: ['.ply', '.spz', '.ksplat', '.splat', '.sog', '.compressed.ply'],
onnx: ['.onnx'],
models: ['.gltf', '.glb', '.obj', '.fbx', '.stl'],
all: [...all extensions]
}
Performance Monitoring
RenderLoop.getPerformanceInfo()- Real-time FPS and frame timesAnimationManager.getDynamicPerformanceStats()- ONNX inference metricsONNXManager.getONNXPerformanceStats()- Generator and point cloud counts
The manager architecture improves modularity, testability, and scalability for scenes that mix static and ONNX-driven splats.