DepthLift

pub package License: MIT

Transform any 2D image into a live, interactive 3D parallax scene with on-device depth estimation. Inspired by iPhone's depth wallpaper effect.

✨ What it does

Tilt your phone → the image comes alive in 3D

  • iPhone-like gyro motion — damped, interpolated, zero jitter
  • On-device depth estimation — Depth Anything v2 via TFLite / Core ML
  • Real-time GPU rendering — OpenGL ES 3.0 (Android) / Metal (iOS) at 60 FPS
  • 3-tier input fallback — Gyroscope → Touch drag → Idle float animation
  • 4 motion presets — iOS Natural, Cinematic, Soft, Intense
  • Frame export — capture PNG stills

🚀 Quick Start

dependencies:
  depthlift: ^0.2.0
import 'package:depthlift/depthlift.dart';

DepthLiftView(
  image: const AssetImage('assets/photo.jpg'),
  options: const DepthLiftOptions(
    effect: DepthEffect.parallax,
    useGyroscope: true,
  ),
);

That's it. The widget handles depth estimation, mesh construction, and rendering automatically.

🎬 Motion Presets

// iPhone wallpaper feel — ultra-smooth, subtle, premium
DepthLiftOptions.fromPreset(DepthPreset.iosNatural)

// Cinematic parallax — moderate, dramatic
DepthLiftOptions.fromPreset(DepthPreset.cinematic)

// Gentle movement — good for portraits
DepthLiftOptions.fromPreset(DepthPreset.soft)

// Bold, aggressive parallax
DepthLiftOptions.fromPreset(DepthPreset.intense)

🎛️ Controller

final ctrl = DepthLiftController();

DepthLiftView(
  image: const AssetImage('assets/photo.jpg'),
  controller: ctrl,
);

// Start the breathing animation
await ctrl.play();

// Switch effect on the fly
await ctrl.setEffect(DepthEffect.bokeh);

// Export a still frame
final Uint8List png = await ctrl.exportFrame();

// Listen to state changes
ctrl.stateStream.listen((state) {
  // DepthLiftState.loading | .ready | .error
});

// Always dispose when done
ctrl.dispose();

🎯 iPhone-Style Gyro Engine

The IOSStyleGyroController is the secret sauce. Unlike raw gyro mapping, it uses:

Technique Purpose
Ticker-based updates Frame-synced at 60 FPS, not raw stream events
lerpDouble smoothing Interpolates toward target each frame
Decay factor Prevents drift, gently returns to centre
Low sensitivity 0.01–0.02 range for subtle motion
Clamped range Max ±0.25 offset — keeps motion premium

The result: motion that feels floating, damped, and slightly delayed — just like iOS.

// Use it standalone if you want
final gyro = IOSStyleGyroController.iosNatural();
await gyro.init(vsync);

gyro.offset.addListener(() {
  final o = gyro.offset.value;
  // o.dx, o.dy = smoothed tilt values
});

gyro.dispose();

⚙️ Options Reference

Field Type Default Description
effect DepthEffect .parallax Active visual effect
depthModel DepthModel .depthAnythingV2 Depth estimation backend
depthScale double 0.6 Z-axis displacement (0.0–1.0)
parallaxFactor double 0.4 Motion multiplier (0.0–1.0)
meshResolution double 64 Grid subdivisions (16–256)
focusDepth double 0.5 Bokeh focal plane (0.0–1.0)
bokehIntensity double 0.5 Blur strength (0.0–1.0)
floatDuration Duration 3s Float animation cycle
useGyroscope bool true Enable gyroscope input
lowPowerMode bool false Halves mesh, disables bokeh

📱 Platform Setup

Android

Minimum SDK: 24 (Android 7.0)

android {
    defaultConfig {
        minSdkVersion 24
    }
}

The plugin declares android.hardware.sensor.gyroscope with required="false" — works on all devices including emulators and tablets without gyroscope.

iOS

Deployment target: 14.0

Add to Info.plist:

<key>NSMotionUsageDescription</key>
<string>Used for parallax depth effect</string>

In ios/Podfile:

platform :ios, '14.0'

🔄 Input Fallback System

The plugin automatically detects available input and falls back gracefully:

1. Gyroscope (if hardware available + useGyroscope: true)
   ↓ not available
2. Touch/Mouse drag (GestureDetector)
   ↓ finger lifted
3. Float animation (Lissajous idle breathing)

No configuration needed — it just works on every device.

🏗️ Architecture

┌──────────────────────────────────────────────────┐
│  Flutter (Dart)                                  │
│  ┌──────────────┐  ┌──────────────────────────┐  │
│  │DepthLiftView │──│ DepthLiftController      │  │
│  └──────┬───────┘  └──────────────────────────┘  │
│         │                                        │
│  ┌──────▼───────────────────────────────────┐    │
│  │ DepthLiftInputManager                    │    │
│  │  ├─ IOSStyleGyroController (Ticker+Lerp) │    │
│  │  ├─ PointerController (touch drag)       │    │
│  │  └─ FloatAnimationController (idle)      │    │
│  └──────┬───────────────────────────────────┘    │
│         │                                        │
│  ┌──────▼──────────────────────────────────┐     │
│  │ MethodChannel (dev.depthlift/engine)    │     │
│  └──────┬──────────────────────────────────┘     │
├─────────┼────────────────────────────────────────┤
│  Native │                                        │
│  ┌──────▼──────┐  ┌──────────────────────────┐   │
│  │ Plugin      │──│ DepthRenderer            │   │
│  │ (Kt/Swift)  │  │ GLES 3.0 / Metal         │   │
│  └─────────────┘  └──────────────────────────┘   │
└──────────────────────────────────────────────────┘

🧪 Testing

flutter test

📄 License

MIT License — see LICENSE for details.

Libraries

depthlift
DepthLift — Convert any 2D image into a live 3D parallax scene.