perspective_space 0.1.1
perspective_space: ^0.1.1 copied to clipboard
Buttery-smooth 3D perspective and parallax widgets for Flutter. Tilt, shake, and stack layers with depth — gesture-driven or auto-animated. Zero dependencies, works on every Flutter platform.
perspective_space #
Buttery-smooth 3D perspective and parallax widgets for Flutter — tilt, shake, and stack layers with depth. Gesture-driven or auto-animated.
perspective_space gives you depth on every Flutter platform with two
primitives and three presets — and zero third-party dependencies.
🌐 Live demo → · 中文文档 →
Features #
PerspectiveSpace+PerspectiveLayer— a tiny pair of widgets that publish a shared rotation/perspective and let descendant layers render with depth-aware parallax.- Gesture-driven tilt — drag to rotate, configurable sensitivity, clamped max angle, elastic spring-back on release.
- Entry shake — one-shot 3D flip-and-settle when the widget mounts.
- Presets for the 90% case:
PerspectiveTiltCard— single tilting card, one-line setup.PerspectiveParallax— multi-layer parallax stack from a list.PerspectiveShakeEntry— wrap any widget, play a shake on entry.
- Controller for triggering shakes from outside the subtree.
- Zero dependencies, pure Dart + Flutter SDK.
Install #
dependencies:
perspective_space: ^0.1.0
flutter pub add perspective_space
Quick start #
A tilting card #
import 'package:perspective_space/perspective_space.dart';
PerspectiveTiltCard(
child: Container(
width: 280,
height: 360,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFFF5BAA), Color(0xFF8B5CF6)],
),
borderRadius: BorderRadius.circular(28),
),
alignment: Alignment.center,
child: const Text('TILT'),
),
);
Drag it — every Flutter platform, no glue code.
Multi-layer parallax #
PerspectiveParallax(
layers: [
PerspectiveLayerSpec(elevation: 0, child: backgroundCard),
PerspectiveLayerSpec(elevation: 40, child: middleCard),
PerspectiveLayerSpec(elevation: 90, child: foregroundContent),
],
)
Higher elevation = closer to the camera = stronger parallax offset.
One-shot entry shake #
PerspectiveShakeEntry(
delay: const Duration(milliseconds: 200),
child: yourRewardCard,
)
Hand-rolled with the primitives #
When you outgrow the presets, drop straight to PerspectiveSpace +
PerspectiveLayer:
PerspectiveSpace(
enableGesture: true,
maxRotation: 30,
child: Stack(
children: [
PerspectiveLayer(elevation: 0, child: background),
PerspectiveLayer(elevation: 50, child: card),
PerspectiveLayer(elevation: 90, child: content),
],
),
);
Imperative shake #
final controller = PerspectiveSpaceController();
PerspectiveSpace(
controller: controller,
child: ...,
);
// Later, from a button handler:
controller.shake();
API at a glance #
| Widget | Purpose |
|---|---|
PerspectiveSpace |
Root container; publishes rotation + perspective. |
PerspectiveLayer |
Child layer; applies a depth-aware transform. |
PerspectiveSpaceController |
Imperative handle (controller.shake()). |
PerspectiveTiltCard |
Preset: a single tilting card. |
PerspectiveParallax |
Preset: a parallax stack from PerspectiveLayerSpecs. |
PerspectiveShakeEntry |
Preset: shake on first mount, then rest. |
Useful PerspectiveSpace parameters #
| Parameter | Default | Notes |
|---|---|---|
rotateX, rotateY |
0 |
Initial tilt, in radians. |
perspective |
0.0015 |
1 / cameraDistance; bigger = stronger foreshortening (0.001–0.002 is the sweet spot). |
enableGesture |
false |
Drag to tilt in real time. |
sensitivity |
0.005 |
Radians per logical pixel of drag. |
maxRotation |
60 |
Hard cap on the gesture-driven tilt, in degrees. |
resetOnRelease |
true |
Spring back to (rotateX, rotateY) on pointer up. |
resetDuration |
800ms |
Spring-back duration. |
resetCurve |
Curves.elasticOut |
Spring-back curve. |
entryShake |
false |
Play a one-shot shake on first mount. |
Platform support #
| iOS | Android | Web | macOS | Windows | Linux |
|---|---|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
perspective_space is pure Dart; everything renders through Flutter's own
3D Transform. There are no plugin channels and no native code.
FAQ #
Q. How does PerspectiveSpace differ from a plain Transform?
It publishes its rotation to descendants and lets PerspectiveLayers
contribute their own Z offset. The result is a single, coherent perspective
camera with independent parallax depth per layer — instead of nested
Transforms that double-stack matrices.
Q. Why does my nested PerspectiveLayer look subtle?
By design — an inner PerspectiveLayer only contributes additional
parallax offset, never re-applies the perspective + rotation matrices.
Increase its elevation, or move it up to the same Stack as the outer
layer if you want a stronger effect.
Q. Is the entry shake configurable? Today the shake amplitude and timing are fixed for snappy feel. PRs welcome if you need it tunable.
Example #
A full showcase app (the source of the GIFs above) lives in
example/. To run it locally:
cd example
flutter run # any platform
Contributing #
Issues and PRs welcome — particularly around new presets, platform-specific tuning, and golden tests. Run the test suite with:
flutter test
cd example && flutter test
License #
MIT © 2026 cccmax.