feat: unified shell, diagnostics pack, native Office, sticky board
All checks were successful
CI / Windows build (push) Successful in 14m22s
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>
This commit is contained in:
@@ -25,12 +25,11 @@ const double kDefaultPenThinning = 0.85;
|
||||
/// perfect_freehand input-smoothing parameters, shared (single source of truth)
|
||||
/// by the on-screen painter and the export path so the two can never diverge
|
||||
/// (guarded by the screen==export parity test). [kPenStreamline] lowers the
|
||||
/// per-point lag from freehand's 0.5 default to 0.32: at 0.5 a quick flick lags
|
||||
/// so far behind the pen that a short fast stroke collapsed toward its start and
|
||||
/// rendered as a dot ("写字识别成单击") and the pen felt sluggish; 0.32 tracks the
|
||||
/// real path closely (crisper, lower-latency feel) while still damping digitizer
|
||||
/// jitter. [kPenSmoothing] keeps freehand's 0.5 corner rounding.
|
||||
const double kPenStreamline = 0.32;
|
||||
/// per-point lag from freehand's 0.5 default to 0.28: paired with
|
||||
/// [StrokePredictor] lookahead this tracks the Surface Pen more tightly while
|
||||
/// still damping digitizer jitter. [kPenSmoothing] keeps freehand's 0.5 corner
|
||||
/// rounding.
|
||||
const double kPenStreamline = 0.28;
|
||||
const double kPenSmoothing = 0.5;
|
||||
|
||||
/// THE single perfect_freehand outline recipe — the raw outline points for a
|
||||
|
||||
56
lib/editor/engine/stroke_predictor.dart
Normal file
56
lib/editor/engine/stroke_predictor.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user