All checks were successful
CI / Windows build (push) Successful in 14m22s
Make Surface remote debugging and classroom workflows viable: always-on structured logs with one-click zip export, a single AppShell chrome, OOXML PPTX/DOCX annotation without LibreOffice, and a first-class sticky board. Also drop spike/legacy ink widgets and tighten pen feel (predictor, PenInfoHistory, page-tile layer). Co-authored-by: Cursor <cursoragent@cursor.com>
57 lines
1.7 KiB
Dart
57 lines
1.7 KiB
Dart
// Lightweight stroke prediction — extrapolates the next point from recent
|
|
// velocity so the live stroke tip leads the digitizer slightly (lower perceived
|
|
// latency). Not a full ink-stroke-modeler; intentionally small and testable.
|
|
|
|
import 'dart:ui';
|
|
|
|
class PredictedPoint {
|
|
const PredictedPoint(this.offset, this.pressure);
|
|
final Offset offset;
|
|
final double pressure;
|
|
}
|
|
|
|
class StrokePredictor {
|
|
StrokePredictor({this.lookaheadMs = 12});
|
|
|
|
/// How far ahead to project, in milliseconds of recent velocity.
|
|
final double lookaheadMs;
|
|
|
|
Offset? _prev;
|
|
double? _prevPressure;
|
|
DateTime? _prevAt;
|
|
Offset _velocity = Offset.zero;
|
|
|
|
void reset() {
|
|
_prev = null;
|
|
_prevPressure = null;
|
|
_prevAt = null;
|
|
_velocity = Offset.zero;
|
|
}
|
|
|
|
/// Feed a real sample; returns an optional predicted tip ahead of [point].
|
|
PredictedPoint? observe(Offset point, double pressure, {DateTime? at}) {
|
|
final now = at ?? DateTime.now();
|
|
if (_prev != null && _prevAt != null) {
|
|
final dtMs = now.difference(_prevAt!).inMicroseconds / 1000.0;
|
|
if (dtMs > 0.5 && dtMs < 80) {
|
|
final raw = (point - _prev!) * (1000.0 / dtMs);
|
|
// EMA blend to avoid jerky predictions.
|
|
_velocity = Offset(
|
|
_velocity.dx * 0.55 + raw.dx * 0.45,
|
|
_velocity.dy * 0.55 + raw.dy * 0.45,
|
|
);
|
|
}
|
|
}
|
|
_prev = point;
|
|
_prevPressure = pressure;
|
|
_prevAt = now;
|
|
|
|
if (_velocity.distance < 40) return null; // idle / slow — no predict
|
|
final tip = point + _velocity * (lookaheadMs / 1000.0);
|
|
return PredictedPoint(tip, pressure);
|
|
}
|
|
|
|
/// Last known pressure (for predicted tip).
|
|
double get lastPressure => _prevPressure ?? 0.5;
|
|
}
|