# Quick Start If all you need is a quick and easy route to rendering a single 3D model in your Flutter application, start with `ViewerWidget`. This is a simplified, Flutter-only wrapper around the underlying 3D rendering API with sane defaults for most people. `ViewerWidget` handles all the setup and configuration of the underlying Thermion API, including: - Loading 3D models (glTF assets) - Configuring skyboxes and image-based lighting - Setting up camera positions and manipulators - Managing the rendering lifecycle ## Setup Follow the steps listed in [Getting Started](./getting_started) to configure your Flutter installation and project. If you're running Windows, delete the `examples/flutter/quickstart/assets` symlink and copy the `assets` folder from `examples/assets` to `examples/flutter/quickstart/assets`. ## Basic Usage ```dart import 'package:flutter/material.dart'; import 'package:thermion_flutter/thermion_flutter.dart'; import 'path_to_your_viewer_widget.dart'; class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: ViewerWidget( assetPath: 'assets/my_model.glb', initialCameraPosition: Vector3(0, 0, 5), manipulatorType: ManipulatorType.ORBIT, ), ), ); } } ``` ## Properties | Property | Type | Default | Description | |----------|------|---------|-------------| | `initial` | `Widget` | Red decorated box | Widget to display while the viewer is loading | | `initialCameraPosition` | `Vector3` | `Vector3(0, 0, 5)` | The starting position for the camera (looking towards origin) | | `showFpsCounter` | `bool` | `false` | Whether to show an FPS counter overlay | | `assetPath` | `String?` | `null` | Path to the glTF asset to load | | `skyboxPath` | `String?` | `null` | Path to a KTX skybox image | | `iblPath` | `String?` | `null` | Path to a KTX image for image-based lighting | | `directLightType` | `LightType?` | `null` | Type of direct light to add to the scene | | `transformToUnitCube` | `bool` | `true` | If true, rescales the model to fit within a 1x1x1 cube | | `postProcessing` | `bool` | `true` | Enables ACES tone mapping and basic anti-aliasing | | `background` | `Color?` | `null` | Background color (not visible when skybox is provided) | | `destroyEngineOnUnload` | `bool` | `false` | If true, disposes the engine when widget is disposed | | `manipulatorType` | `ManipulatorType` | `ORBIT` | Type of camera control to use | | `onViewerAvailable` | `Future Function(ThermionViewer)?` | `null` | Callback when viewer is ready | ## Camera Manipulators `ViewerWidget` supports three different camera manipulation modes: - `ManipulatorType.NONE`: No camera controls, static view - `ManipulatorType.ORBIT`: Orbit controls (pinch to zoom, swipe to rotate) - `ManipulatorType.FREE_FLIGHT`: Free flight controls for unrestricted movement Example: ```dart ViewerWidget( assetPath: 'assets/model.glb', manipulatorType: ManipulatorType.FREE_FLIGHT, ) ``` ## Lighting You can set up lighting in multiple ways: ### Image-Based Lighting ```dart ViewerWidget( assetPath: 'assets/model.glb', iblPath: 'assets/environment.ktx', ) ``` ### Direct Light ```dart ViewerWidget( assetPath: 'assets/model.glb', directLightType: LightType.SUN, ) ``` ## Advanced Usage ### Accessing the Viewer You can get access to the underlying `ThermionViewer` object for more advanced control: ```dart ViewerWidget( assetPath: 'assets/model.glb', onViewerAvailable: (viewer) async { // Now you can use the viewer directly final camera = await viewer.getActiveCamera(); await camera.lookAt(Vector3(0, 1, 5)); // Add custom lights, manipulate materials, etc. }, ) ``` ### Changing Manipulator at Runtime The `manipulatorType` is the only property that can be changed after the widget is created: ```dart class _MyWidgetState extends State { ManipulatorType _manipulatorType = ManipulatorType.ORBIT; @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: ViewerWidget( assetPath: 'assets/model.glb', manipulatorType: _manipulatorType, ), ), Row( children: [ ElevatedButton( onPressed: () { setState(() { _manipulatorType = ManipulatorType.ORBIT; }); }, child: Text('Orbit'), ), ElevatedButton( onPressed: () { setState(() { _manipulatorType = ManipulatorType.FREE_FLIGHT; }); }, child: Text('Free Flight'), ), ], ), ], ); } } ``` ## Limitations - Only the `manipulatorType` property can be changed at runtime. For any other property changes, create a new widget. - The widget requires that you have the correct environment setup for Thermion (Flutter master channel with native assets enabled). ## Example Here's a complete example showing how to use `ViewerWidget` with multiple configuration options: ```dart import 'package:flutter/material.dart'; import 'package:thermion_flutter/thermion_flutter.dart'; import 'package:vector_math/vector_math_64.dart'; class ModelViewer extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('3D Model Viewer')), body: ViewerWidget( assetPath: 'assets/robot.glb', skyboxPath: 'assets/studio_skybox.ktx', iblPath: 'assets/studio_ibl.ktx', initialCameraPosition: Vector3(0, 1.5, 3), manipulatorType: ManipulatorType.ORBIT, showFpsCounter: true, background: Colors.grey, postProcessing: true, transformToUnitCube: true, onViewerAvailable: (viewer) async { // You can perform additional setup here print('Viewer is ready!'); }, ), ); } } ```