depthlift 0.2.0 copy "depthlift: ^0.2.0" to clipboard
depthlift: ^0.2.0 copied to clipboard

Convert any 2D image into a live 3D parallax scene with on-device depth estimation. Inspired by iOS depth effects.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:depthlift/depthlift.dart';

void main() {
  runApp(const DepthLiftExampleApp());
}

class DepthLiftExampleApp extends StatelessWidget {
  const DepthLiftExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'DepthLift Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF6750A4),
        brightness: Brightness.dark,
        useMaterial3: true,
      ),
      home: const DepthLiftDemoPage(),
    );
  }
}

class DepthLiftDemoPage extends StatefulWidget {
  const DepthLiftDemoPage({super.key});

  @override
  State<DepthLiftDemoPage> createState() => _DepthLiftDemoPageState();
}

class _DepthLiftDemoPageState extends State<DepthLiftDemoPage> {
  final DepthLiftController _controller = DepthLiftController();

  DepthPreset _currentPreset = DepthPreset.iosNatural;
  DepthEffect _currentEffect = DepthEffect.parallax;
  double _depthScale = 0.4;
  double _parallaxFactor = 0.25;

  @override
  void initState() {
    super.initState();
    _controller.stateStream.listen((state) {
      debugPrint('DepthLift state: $state');
    });
    _applyPreset(_currentPreset);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _applyPreset(DepthPreset preset) {
    setState(() {
      _currentPreset = preset;
      _depthScale = preset.depthScale;
      _parallaxFactor = preset.parallaxFactor;
    });
  }

  DepthLiftOptions get _options => DepthLiftOptions(
        effect: _currentEffect,
        depthModel: DepthModel.depthAnythingV2,
        depthScale: _depthScale,
        parallaxFactor: _parallaxFactor,
        useGyroscope: true,
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: SafeArea(
        child: Column(
          children: [
            // ── Header ──────────────────────────────────────────
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 12, 20, 8),
              child: Row(
                children: [
                  const Icon(Icons.auto_awesome, color: Colors.white70, size: 20),
                  const SizedBox(width: 8),
                  const Text(
                    'DepthLift',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 22,
                      fontWeight: FontWeight.w600,
                      letterSpacing: -0.5,
                    ),
                  ),
                  const Spacer(),
                  Container(
                    padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
                    decoration: BoxDecoration(
                      color: Colors.white.withOpacity(0.1),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    child: Text(
                      _currentPreset.name.toUpperCase(),
                      style: const TextStyle(
                        color: Colors.white54,
                        fontSize: 11,
                        fontWeight: FontWeight.w600,
                        letterSpacing: 1.2,
                      ),
                    ),
                  ),
                ],
              ),
            ),

            // ── 3D Scene ────────────────────────────────────────
            Expanded(
              flex: 5,
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(28),
                  child: DepthLiftView(
                    image: const AssetImage('assets/sample.jpg'),
                    options: _options,
                    controller: _controller,
                    loadingWidget: const Center(
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          CircularProgressIndicator(strokeWidth: 2),
                          SizedBox(height: 16),
                          Text(
                            'Computing depth…',
                            style: TextStyle(color: Colors.white38, fontSize: 13),
                          ),
                        ],
                      ),
                    ),
                    onError: (e) => debugPrint('DepthLift error: $e'),
                  ),
                ),
              ),
            ),

            // ── Preset Selector ─────────────────────────────────
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: Row(
                children: DepthPreset.values.map((preset) {
                  final selected = preset == _currentPreset;
                  return Expanded(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 3),
                      child: GestureDetector(
                        onTap: () => _applyPreset(preset),
                        child: AnimatedContainer(
                          duration: const Duration(milliseconds: 200),
                          padding: const EdgeInsets.symmetric(vertical: 10),
                          decoration: BoxDecoration(
                            color: selected
                                ? Colors.white.withOpacity(0.15)
                                : Colors.white.withOpacity(0.05),
                            borderRadius: BorderRadius.circular(14),
                            border: Border.all(
                              color: selected
                                  ? Colors.white.withOpacity(0.3)
                                  : Colors.transparent,
                            ),
                          ),
                          child: Column(
                            children: [
                              Icon(
                                _presetIcon(preset),
                                color: selected ? Colors.white : Colors.white38,
                                size: 18,
                              ),
                              const SizedBox(height: 4),
                              Text(
                                _presetLabel(preset),
                                style: TextStyle(
                                  color: selected ? Colors.white : Colors.white38,
                                  fontSize: 10,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                }).toList(),
              ),
            ),

            // ── Sliders ─────────────────────────────────────────
            Expanded(
              flex: 2,
              child: ListView(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                children: [
                  _buildSlider(
                    label: 'Depth',
                    value: _depthScale,
                    onChanged: (v) => setState(() => _depthScale = v),
                  ),
                  _buildSlider(
                    label: 'Motion',
                    value: _parallaxFactor,
                    onChanged: (v) => setState(() => _parallaxFactor = v),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  IconData _presetIcon(DepthPreset preset) {
    switch (preset) {
      case DepthPreset.iosNatural:
        return Icons.phone_iphone;
      case DepthPreset.cinematic:
        return Icons.movie_filter;
      case DepthPreset.soft:
        return Icons.blur_on;
      case DepthPreset.intense:
        return Icons.bolt;
    }
  }

  String _presetLabel(DepthPreset preset) {
    switch (preset) {
      case DepthPreset.iosNatural:
        return 'iOS';
      case DepthPreset.cinematic:
        return 'Cinema';
      case DepthPreset.soft:
        return 'Soft';
      case DepthPreset.intense:
        return 'Intense';
    }
  }

  Widget _buildSlider({
    required String label,
    required double value,
    required ValueChanged<double> onChanged,
  }) {
    return Row(
      children: [
        SizedBox(
          width: 60,
          child: Text(
            label,
            style: const TextStyle(color: Colors.white54, fontSize: 12),
          ),
        ),
        Expanded(
          child: SliderTheme(
            data: SliderThemeData(
              trackHeight: 2,
              thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 6),
              overlayShape: const RoundSliderOverlayShape(overlayRadius: 14),
              activeTrackColor: Colors.white.withOpacity(0.6),
              inactiveTrackColor: Colors.white.withOpacity(0.1),
              thumbColor: Colors.white,
            ),
            child: Slider(
              value: value,
              onChanged: (v) {
                onChanged(v);
                _controller.setOptions(_options);
              },
            ),
          ),
        ),
        SizedBox(
          width: 36,
          child: Text(
            value.toStringAsFixed(2),
            style: const TextStyle(color: Colors.white38, fontSize: 11),
          ),
        ),
      ],
    );
  }
}
2
likes
120
points
34
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Convert any 2D image into a live 3D parallax scene with on-device depth estimation. Inspired by iOS depth effects.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, sensors_plus, tflite_flutter

More

Packages that depend on depthlift

Packages that implement depthlift