You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Bug fixes
Drag-to-scroll interference — CanvasScrollEvent could fire immediately
after releasing a drag when the hand briefly adopted a pointing-like shape
during the transition. Fixed by adding a scrollConfirmFrames gate (default 2, ~67 ms at 30 fps) that requires N consecutive pointing frames before
scroll activates, consistent with the existing pinchConfirmFrames guard for
drag. Set scrollConfirmFrames: 1 to restore the old single-frame-baseline
behaviour.
New
handLandmarkConnections — exported constant listing the 21 skeleton
bone pairs for the MediaPipe hand topology. Iterate over it to draw a
skeleton overlay without hand-coding the connections yourself.
CanvasGestureEvent.confidence (double, default 1.0) — ML
confidence of the gesture classification. Always 1.0 on web (rule-based
heuristic); populated from the backend's score on native when using a
model-based LandmarkProvider such as hand_detection.
HandDetectionFrame.gestureConfidence / secondHandGestureConfidence
(double, default 1.0) — per-gesture confidence fields for native backends
to expose ML scores that flow through to CanvasGestureEvent.confidence.
GestureInputSource confidence thresholds (web) — three new constructor
params minHandDetectionConfidence, minHandPresenceConfidence, and minTrackingConfidence (each default 0.5, matching MediaPipe defaults).
Tune these to trade sensitivity against false positives without modifying the
JS worker.
HandDetectionFrame.worldLandmarks / secondWorldLandmarks —
optional world-space landmark lists (metric scale, hand-centre origin) for
native backends to expose orientation-invariant landmark data. On web,
populated from MediaPipe's worldLandmarks result automatically.
GestureDebugInfo.worldLandmarks / secondWorldLandmarks — world
landmarks forwarded through the debug snapshot so overlays and classifiers
can consume them.
HandDetectionFrame.boundingBox / secondHandBoundingBox (Rect?)
— axis-aligned bounding box of each detected hand in normalised image
coordinates. Native backends set this from their ML model's output. On web,
computed automatically as the min/max envelope of the 21 image-space
landmarks.
GestureDebugInfo.boundingBox / secondHandBoundingBox (Rect?)
— bounding box forwarded through the debug snapshot for overlay rendering.
StylusInputSource — input source for Apple Pencil, Samsung S-Pen, and
any PointerDeviceKind.stylus / PointerDeviceKind.invertedStylus device.
Maps pen contact to element-drag canvas events (Down/Move/Up, tap, double-tap,
hover, cancel). Filters out mouse/touch/trackpad events so it can be combined
with MouseInputSource or TouchInputSource without duplicates. Exposes an eraserModeStream that emits true / false on eraser-vs-tip mode changes.
CanvasDownEvent.pressure / CanvasMoveEvent.pressure (double,
default 1.0) — hardware pen pressure (0.0–1.0) carried by stylus down and
move events. Backwards-compatible: non-stylus sources emit 1.0; existing
construction and pattern-matching compiles unchanged.
defaultPointerSource() — factory function that returns the best-fit CanvasInputSource for the current platform: TouchInputSource on Android /
iOS, MouseInputSource everywhere else (including web). Uses kIsWeb and defaultTargetPlatform from package:flutter/foundation.dart, so it is safe
to call on web without conditional imports. GestureInputSource is not
included — it requires platform-specific configuration that cannot be inferred
automatically.
TouchInputSource — mobile-native input source for Android and iOS.
Single-finger drag → CanvasScrollEvent (direct-manipulation pan); two-finger
pinch/spread → CanvasScaleEvent; fling → CanvasScrollEvent with non-zero velocity field for consumer momentum animations. Tap detection uses raw Listener events rather than GestureDetector so taps are never dropped by ScaleGestureRecognizer's kPanSlop movement threshold.
CanvasScrollEvent.velocity (Offset, default Offset.zero) — fling
velocity field added to CanvasScrollEvent. Non-zero only on fling events
emitted by TouchInputSource. Backwards-compatible: existing code that
constructs or pattern-matches CanvasScrollEvent compiles unchanged.
Documentation
README — Documented three previously undocumented public API surfaces: CanvasInputController muting (muteWhenActive/activeStream), GestureInputSource.statusStream lifecycle states, and GestureInputSource.setFilterParams().
README — Added self-hosting section documenting mediaPipeBaseUrl and modelAssetUrl constructor parameters (Flutter Web only); corrected the
"no self-hosted model" limitation which was inaccurate — self-hosting has
been wired since 0.1.0.
KNOWN_LIMITATIONS — Corrected "No rotation gesture" bullet: rotation IS
emitted by GestureInputSource via CanvasScaleEvent.rotation; only MouseInputSource omits it (Flutter's ScaleGestureRecognizer limitation).
SECURITY — Replaced GitHub default template with accurate policy for a
0.2.x package (correct version table, advisory link, SLA, scope table).
CLAUDE.md — Added architecture guide for AI-assisted development,
covering the js_interop boundary invariant, quality gates, testing philosophy,
and breaking-change rules.
Fixes
pubspec.yaml version bumped from 0.2.0 to 0.2.1 (was incorrectly
behind CHANGELOG.md); added homepage and issue_tracker fields.
GestureInputSource (native) — dispose() now wraps _frameSub?.cancel()
in unawaited(), consistent with the three StreamController.close() calls
below it.
Example
3D Room — Camera now starts inside the room (dist 900 → 250) for an
immersive interior view instead of a dollhouse perspective from outside.
3D Room — Furniture can now be rotated on its Y-axis: horizontal scroll
while a piece is selected rotates it in-place; two-finger twist
(CanvasScaleEvent.rotation) also rotates the selected piece instead of the
camera.