tactile 0.1.0 copy "tactile: ^0.1.0" to clipboard
tactile: ^0.1.0 copied to clipboard

Make any widget feel physical: it tilts toward your finger, depresses at the press point, and a glare tracks where you press. Compositor-only, no shaders.

tactile #

Make any Flutter widget feel physical when you touch it. It tilts toward your finger, depresses at the exact press point, and a specular highlight tracks where you press.

No shaders. Compositor-only. Works on iOS, Android, web, macOS, Windows, and Linux at full frame rate.

Tactile(
  onTap: () => print('tapped'),
  child: const FlutterLogo(size: 120),
)

[A card tilting toward the finger with a glare that tracks the press point]

Why #

Flutter has neumorphism packages for the static soft-extruded look. None of them make interaction press-position-aware — the visual response that follows where and how you touch. That's what tactile does, and it works on any child, not just buttons.

Install #

dependencies:
  tactile: ^0.1.0

Usage #

Wrap anything:

Tactile(
  borderRadius: BorderRadius.circular(16),
  onTap: () {},
  child: myWidget,
)

Presets #

Tactile.subtle(child: ...)   // restrained — cards, list rows, dense UI
Tactile.playful(child: ...)  // exaggerated — hero buttons, demo scenes

Styled components #

Batteries-included widgets built on Tactile that own their surface, so they also morph their neumorphic shadows from extruded to flush as you press:

TactileButton(onTap: () {}, child: const Text('Press me'))

TactileCard(child: ...)               // leans like a held card

TactileTile(                          // list row
  leading: const Icon(Icons.bolt),
  title: const Text('Title'),
  subtitle: const Text('Subtitle'),
  trailing: const Icon(Icons.chevron_right),
  onTap: () {},
)

Pass a TactileStyle to control the surface (color, gradient, borderRadius, elevation, lightDirection) and the feel (tilt, depress, glareIntensity). Neumorphic shadows read best when color is close to the surrounding background.

Tuning #

Parameter Default What it does
tilt 0.15 Max perspective rotation toward the press point (radians). 0 disables.
depress 0.04 Fractional scale-in at the touch point. 0.04 → shrinks to 96%.
glare true Moving specular highlight overlay.
glareColor Colors.white Highlight color.
glareIntensity 0.35 Peak glare opacity at full press.
borderRadius BorderRadius.zero Clips the glare to the child's rounded shape.
springBack true Release uses spring physics (vs. reversed curve).
pressCurve Curves.easeOut Curve while pressing in.
pressDuration 90ms Press-in duration.
enabled true When false, no effects and callbacks don't fire.

How it works #

The press point drives everything — touch position is normalized to [-1, 1] from the child's center, and a single press-progress value scales both the tilt magnitude and depress depth, so release springs them back together:

  • Tilt — a perspective Matrix4 rotation about X/Y toward the finger.
  • DepressTransform.scale with its origin offset to the touch point, so the child shrinks toward your finger rather than its center.
  • Glare — a radial gradient painted on top, centered at the finger and clipped to borderRadius.
  • Spring-back — a SpringSimulation returns press-progress to rest on release, with a little overshoot.

Effects are transform + overlay only and wrapped in a RepaintBoundary, so they run on the compositor and never touch the child's layout.

Accessibility #

  • Respects the platform reduce-motion setting: tilt and glare are dropped, leaving only a quiet depress as the press affordance.
  • Exposes button semantics and a tap action when onTap is provided.
  • Supports keyboard activation (Enter/Space) when focused.
  • enabled: false disables all effects and callbacks.
  • Tracks a single pointer; multi-touch can't tear the effect in two directions.
  • The effect follows your finger as you drag, while onTap is suppressed once the press becomes a drag (so dragging never counts as a tap).

Scrollables: Tactile observes pointers passively (it doesn't claim the gesture arena), so a ListView/PageView still scrolls normally — the effect simply animates alongside the drag. A dedicated gesture recognizer for tighter coexistence is planned.

Example #

A gallery with recordable scenes lives in example/. Run it with:

cd example && flutter run

Status #

v0.1.0 ships the core Tactile wrapper plus the styled components (TactileButton, TactileCard, TactileTile) with neumorphic shadow-morph. A dedicated gesture recognizer for tighter scrollable coexistence is next.

Development #

This repo is pinned to a Flutter version with FVM (see .fvmrc). With FVM installed:

fvm install              # gets the pinned Flutter version
fvm flutter pub get
fvm flutter test
fvm flutter analyze

(Plain flutter works too if your global SDK satisfies the constraints in pubspec.yaml.)

License #

MIT © 2026

1
likes
0
points
20
downloads

Publisher

verified publishermouazanan.dev

Weekly Downloads

Make any widget feel physical: it tilts toward your finger, depresses at the press point, and a glare tracks where you press. Compositor-only, no shaders.

Repository (GitHub)
View/report issues

Topics

#ui #animation #gestures #button #interaction

License

unknown (license)

Dependencies

flutter

More

Packages that depend on tactile