Embed and control hosted Spline 3D/interactive scenes inside your Flutter apps
with a simple widget + controller API powered by webview_flutter.
Features
- Display a Spline scene by URL with SplineViewer.
- Imperative control via SplineController(reload, run/evaluate JS helpers).
- Loading placeholder & error builder customization.
- Optional zoom enablement.
Getting started
Add dependency in pubspec.yaml (already done if you're reading the source):
dependencies:
	spline_flutter: ^0.0.1
Ensure your platform setup (iOS minimum, Android WebView) follows
webview_flutter requirements.
Usage
Basic
final controller = SplineController();
SplineViewer(
	sceneUrl: 'https://my.spline.design/your-scene-url',
	controller: controller,
	enableZoom: true,
	placeholder: const Center(child: CircularProgressIndicator()),
	errorBuilder: (context, error) => Center(child: Text('Failed: $error')),
);
Run JavaScript / helpers
controller.play(); // attempts to call window.spline.play()
controller.pause();
await controller.runJavaScript("console.log('Hello from Flutter');");
final value = await controller.evaluateJavaScript('2 + 2');
Runtime (.splinecode) mode
If you exported a Spline scene as .splinecode, pass that URL (or a self-hosted URL) instead of the hosted page. The widget detects the suffix and boots the Spline Runtime inside a lightweight HTML shell.
final controller = SplineController()
	..onLoaded = () => debugPrint('Runtime scene loaded')
	..onMessage = (m) => debugPrint('Raw message: $m');
SplineViewer(
	sceneUrl: 'https://prod.spline.design/xxxx/scene.splinecode',
	controller: controller,
);
// Add event listeners
final mouseDownId = controller.addEventListener('mouseDown', (payload) {
	debugPrint('mouseDown event: $payload');
});
// Later remove
controller.removeEventListenerById(mouseDownId);
// Switch to another scene code file
await controller.loadSceneUrl('https://prod.spline.design/yyyy/scene.splinecode');
Events are relayed through addEventListener; payload includes a target with id, name, and basic transforms when available.
Dispose the controller only if you created it and the viewer is unmounted.
Additional information
Planned improvements:
- Event channel for richer Spline runtime events (selection, camera moves).
- Support for offline/embedded export bundles.
- Example app under /example.
Contributions & issues welcome.
License
MIT. See LICENSE file.