// lottie in shape

Lottie in shape

Fiber3DWidgetTexture renders any Flutter widget off-screen and copies it into a texture many times a second. Put that texture on a shape and the shape shows the widget live. This is how you put a Lottie animation, a video player, a chart or an animated counter onto a 3D surface.

flutter_fiber has no Lottie dependency. Your app brings whichever package produces the widget. This page uses the lottie package, but any widget works the same way.

// demo

Demo

A Lottie animation playing live on a Fiber3DPlane.

// how to use it

How to use it

Replace your_animation.json with your own Lottie file.

1. Add the Lottie package and your animation file:

bash
flutter pub add lottie
yaml
flutter:
  assets:
    - assets/lottie/your_animation.json

2. Create a placeholder texture and load the file. The texture starts as one white pixel and is replaced by the real animation as soon as the first frame is captured. In a State class:

dart
import 'dart:typed_data';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_fiber/flutter_fiber.dart';
import 'package:lottie/lottie.dart';

// A 1x1 white placeholder, shown until the first frame is captured.
final Fiber3DTexture _texture = Fiber3DTexture.raw(
  Uint8List.fromList([255, 255, 255, 255]),
  1,
  1,
);
Uint8List? _lottieBytes;

@override
void initState() {
  super.initState();
  rootBundle.load('assets/lottie/your_animation.json').then((data) {
    if (!mounted) return;
    setState(() {
      _lottieBytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    });
  });
}

3. Build the scene. Put a Stack around the canvas and add Fiber3DWidgetTexture as its sibling, with the animation as its child. The mesh that shows it uses the same texture as its map:

dart
// A Stack holds the canvas and the widget texture side by side.
Stack(
  children: [
    Fiber3DCanvas(
      // camera, lights, orbitEnabled ... as usual
      children: [
        Fiber3DMesh(
          geometry: Fiber3DPlane(width: 2, height: 2),
          material: Fiber3DStandardMaterial(
            map: _texture,
            roughness: 1.0,
            metalness: 0.0,
          ),
          showEdges: false,
          // Keeps the canvas rendering so it keeps re-reading the texture.
          onFrame: (elapsed, delta, transform) {},
        ),
      ],
    ),
    if (_lottieBytes != null)
      Fiber3DWidgetTexture(
        texture: _texture,
        child: Lottie.memory(_lottieBytes!),
      ),
  ],
)

// parameters

Parameters

Parameters of Fiber3DWidgetTexture:

child

default required

The widget to capture (here, the Lottie animation).

texture

default required

The Fiber3DTexture that is updated with each captured frame.

width

default 256

Off-screen render width in logical pixels. Larger = sharper, but slower.

height

default 256

Off-screen render height in logical pixels.

fps

default 30

How often the widget is captured, independent of the child's own animation rate.

// tips & limits

Tips & limits

  • Fiber3DWidgetTexture must be a direct child of a Stack. It keeps the widget painted off-screen, out of sight, so it can be captured.
  • Give the mesh an onFrame, even an empty one. Without any registered onFrame the canvas stops rendering after one frame and never picks up the texture's updates.
  • A larger width / height gives a sharper texture but costs more per capture. Match the aspect ratio of the surface you map it on (the default 256 x 256 suits a square plane).
  • fps only controls how often the widget is sampled. A lower value saves work; the animation itself keeps its own speed.
  • Only Fiber3DStandardMaterial accepts textures, and the texture is lit like any surface.
  • For text that never changes, use Text in shape instead: it rasterizes once, with no per-frame cost.