gesso-framework 0.6.18 → 0.6.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # gesso-framework
2
2
 
3
+ ## 0.6.20
4
+
5
+ ### Patch Changes
6
+
7
+ - `FrameMetrics`, the worker's frame message and the proof recording carry the display time a frame was drawn for and the scroll offset of the container the wheel last scrolled, which together show how evenly a scroll moves from one refresh to the next. `durationMs` now counts the phases before a frame's changes are collected (ticks, patches, trackpad pacing, lazy-list mounting); a frame that mounted rows for four milliseconds reported two.
8
+ - A render worker whose own refreshes keep no display's time draws on the display's beat. WebKit gives a worker a `requestAnimationFrame` from a timer near 65 Hz, so on a 120 Hz display frames fell 15 to 16.4 ms apart and a scroll juddered. The shell now measures the display's interval and sends it to the worker; once the worker's refreshes show themselves slower, the frame clock follows the shell's refreshes, stamps each frame with its refresh on the worker's own clock, and gives a frame too costly for one refresh an even two, so the pace does not change mid-scroll.
9
+
10
+ The stride between refreshes also follows the typical frame rather than the slow ones: it lengthens when the median frame passes three quarters of its refreshes and shortens once the median of the last thirty fits in six tenths of one fewer. It held Easel at 82 frames a second on a 165 Hz display whose typical frame took under half a refresh; measured since, 861 of 1,018 frames come a refresh apart, against 15.
11
+
12
+ - Updated dependencies
13
+ - Updated dependencies
14
+ - Updated dependencies
15
+ - Updated dependencies
16
+ - Updated dependencies
17
+ - Updated dependencies
18
+ - Updated dependencies
19
+ - gesso-core@0.6.20
20
+
21
+ ## 0.6.19
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [c047559]
26
+ - Updated dependencies
27
+ - gesso-core@0.6.19
28
+
3
29
  ## 0.6.18
4
30
 
5
31
  ### Patch Changes
@@ -3401,6 +3401,10 @@ declare class GessoRuntime {
3401
3401
  private constraints;
3402
3402
  private pixelRatio;
3403
3403
  private lastFrameMs;
3404
+ /** The display time the frame being drawn is for; see `FrameMetrics.time`. */
3405
+ private frameTime;
3406
+ /** When the frame's first phase began, before its changes were collected; see `FrameMetrics.durationMs`. */
3407
+ private frameBegan;
3404
3408
  private frameListener;
3405
3409
  private rendererErrorListener;
3406
3410
  private frameErrorListener;
@@ -4297,6 +4301,8 @@ declare class GessoRuntime {
4297
4301
  * every pass, so writing the raw offset here is enough.
4298
4302
  */
4299
4303
  private createScrollSink;
4304
+ /** Where the container the wheel last scrolled is; see `FrameMetrics.wheelScroll`. */
4305
+ private wheelScroll;
4300
4306
  /**
4301
4307
  * Work that must happen before the frame's dirty set is snapshotted.
4302
4308
  *
@@ -4501,6 +4507,11 @@ interface PatchSource {
4501
4507
  }
4502
4508
  interface FrameMetrics {
4503
4509
  frame: number;
4510
+ /**
4511
+ * How long the frame took, from its first phase (the ticks, the
4512
+ * patches, the lazy lists' mounting, which run before its changes are
4513
+ * collected) to its end.
4514
+ */
4504
4515
  durationMs: number;
4505
4516
  nodes: number;
4506
4517
  /** Nodes the layout phase measured (memo hits excluded). */
@@ -4545,6 +4556,20 @@ interface FrameMetrics {
4545
4556
  * input — see `GessoRuntime.noteInput`.
4546
4557
  */
4547
4558
  inputLatencyMs: number | null;
4559
+ /**
4560
+ * The display time the frame was drawn for: the refresh's timestamp,
4561
+ * on the same clock as `at`, or null for a frame with none.
4562
+ */
4563
+ time: number | null;
4564
+ /**
4565
+ * Where the container the wheel last scrolled is scrolled to after this
4566
+ * frame, or null before the wheel has scrolled anything. Read with
4567
+ * `time`, it says how evenly scrolling moves from frame to frame.
4568
+ */
4569
+ wheelScroll: {
4570
+ readonly x: number;
4571
+ readonly y: number;
4572
+ } | null;
4548
4573
  }
4549
4574
  /** Milliseconds per WebGPU stage of one frame. */
4550
4575
  interface GpuStageTimings {
@@ -4911,6 +4936,21 @@ UiFileDropMessage |
4911
4936
  {
4912
4937
  type: 'tick';
4913
4938
  time: number;
4939
+ } |
4940
+ /**
4941
+ * The display's interval as the shell's \`requestAnimationFrame\` sees
4942
+ * it, sent once the worker is ready, with the shell's \`timeOrigin\` so
4943
+ * the worker can read the shell's frame times on its own clock.
4944
+ *
4945
+ * A worker's own refreshes can be no display's at all: WebKit's come
4946
+ * from a timer near 65 Hz, on no display's beat. The frame clock then
4947
+ * keeps time by the shell's refreshes instead; see
4948
+ * \`UiHostFrameClock.displayInterval\`.
4949
+ */
4950
+ {
4951
+ type: 'displayInterval';
4952
+ ms: number;
4953
+ origin: number;
4914
4954
  } | {
4915
4955
  type: 'dispose';
4916
4956
  };
@@ -4968,6 +5008,11 @@ type RuntimeToShellMessage = {
4968
5008
  layoutPasses: number;
4969
5009
  at: number;
4970
5010
  inputLatencyMs: number | null;
5011
+ time: number | null;
5012
+ wheelScroll: {
5013
+ readonly x: number;
5014
+ readonly y: number;
5015
+ } | null;
4971
5016
  phases: FramePhaseTimings;
4972
5017
  renderer: RendererBackend | 'pending';
4973
5018
  gpu: GpuStageTimings | null;
@@ -5987,6 +6032,12 @@ declare class WorkerApp {
5987
6032
  * nothing costs nothing here.
5988
6033
  */
5989
6034
  private setFrameLoop;
6035
+ /**
6036
+ * Measures the display's interval on this thread's refreshes and tells
6037
+ * the worker, whose own may keep no display's time; see
6038
+ * `displayInterval` in the protocol. A dozen refreshes, once, at start.
6039
+ */
6040
+ private measureDisplay;
5990
6041
  dispose(): void;
5991
6042
  /**
5992
6043
  * The application worker talks to the render worker over the hub,
@@ -8593,4 +8644,4 @@ declare class RenderWorkerApp {
8593
8644
  }
8594
8645
  //#endregion
8595
8646
  export { StorageAdapter as $, UiNodeReport as $n, mutate as $r, UiFramePhase as $t, Presence as A, AudioService as An, ChannelRegistry as Ar, createShellHistory as At, PersistedOptions as B, ShellFileResult as Bn, themeTokenCell as Br, UiTreeNode as Bt, FocusService as C, buildPath as Cn, pick as Cr, createApp as Ct, FindService as D, AudioMetadata as Dn, createChannelRegistry as Dr, ShellHistory as Dt, TextService as E, AudioAction as En, ChannelRegistryHandle as Er, WorkerAppOptions as Et, AudioSinkOptions as F, SpringOptions as Fn, Output as Fr, ConsoleEntry as Ft, IndexedDbStorage as G, ShellStorageOp as Gn, Each as Gr, ShellToRuntimeMessage as Gt, persisted as H, ShellRecentFile as Hn, Show as Hr, treeText as Ht, AudioSinkOutput as I, UiDuration as In, ControlledOptions as Ir, DevtoolsEvent as It, OpfsFileHandle as J, ColorSchemePreference as Jn, each as Jr, GessoRuntime as Jt, IndexedDbStorageOptions as K, ShellStorageResult as Kn, EachKey as Kr, FrameMetrics as Kt, MediaSessionLike as L, UiEasingChoice as Ln, ControlledValue as Lr, DevtoolsRequest as Lt, RouterOutlet as M, AudioStatus as Mn, Define as Mr, ActionEntry as Mt, AudioElementLike as N, AnimateOptions as Nn, Inject as Nr, ChannelErrorEntry as Nt, observeMediaQuery as O, AudioRequest as On, findUnplainPath as Or, ShellHistoryMode as Ot, AudioSink as P, AnimationService as Pn, Input as Pr, CommandEntry as Pt, MemoryStorage as Q, UiEnvironmentReport as Qn, Mutation as Qr, UI_FRAME_PHASES as Qt, audioClock as R, ShellFile as Rn, controlled as Rr, FrameEntry as Rt, writeClipboard as S, RouteParams as Sn, structurallyEqual as Sr, CreateAppOptions as St, EditingService as T, parseUrl as Tn, ChannelRegistration as Tr, WorkerApp as Tt, ShellStorage as U, ShellRequest as Un, ShowProps as Ur, RuntimeErrorSource as Ut, PersistedState as V, ShellFileType as Vn, bind as Vr, UiTreeSnapshot as Vt, ShellStorageOptions as W, ShellService as Wn, show as Wr, RuntimeToShellMessage as Wt, OpfsStorageOptions as X, BoundStream as Xn, throttled as Xr, RendererChoice as Xt, OpfsStorage as Y, observeColorScheme as Yn, debounced as Yr, GessoRuntimeOptions as Yt, OpfsWritable as Z, NodePathTarget as Zn, MutateOptions as Zr, RuntimeInput as Zt, EditingMirrorTarget as _, Equality as _i, RouteGuard as _n, OverlayService as _r, GessoApp as _t, UiRole as a, SelectOptions as ai, FontService as an, describeStream as ar, storageReadValue as at, EditingProxy as b, route as bn, FrameworkChild as br, GessoAppBuilder as bt, UiSemanticsPatch as c, FanKey as ci, RouteAnswer as cn, formatNodeReport as cr, UndoableOptions as ct, markNow as d, fanOut as di, RouterRoutes as dn, ComponentHostResolver as dr, UndoStackOptions as dt, Resource as ei, FontFaceDeclaration as en, UiOwnerReport as er, StorageOutcome as et, measureSpan as f, ComputedCell as fi, RouterService as fn, ComponentHost as fr, UndoTransaction as ft, renderRoot as g, DeriveOptions as gi, RouteDefinition as gn, OverlayRect as gr, shellStorageDenied as gt, RenderWorkerApp as h, computed as hi, RouteContext as hn, OverlayPlacement as hr, performShellStorage as ht, UI_SEMANTIC_STATES as i, resource as ii, FontHost as in, UiStreamReport as ir, storageReadFailure as it, PresenceProps as j, AudioState as jn, Channel as jr, ActionCause as jt, observeReducedMotion as k, AudioSample as kn, requirePlainData as kr, ShellHistoryOptions as kt, UiSemanticsRecord$1 as l, FanOut as li, RouteMatch as ln, formatStream as lr, undoable as lt, setPerformanceMarks$1 as m, ReadSource as mi, OutletProps as mn, OverlayEntry as mr, ShellLocalStore as mt, MARK_PREFIX as n, ResourceState as ni, FontFamilyDeclaration as nn, UiPropReport as nr, classifyStorageError as nt, UiSemanticState as o, select as oi, MediaOptions as on, formatAge as or, UndoShortcutOptions as ot, performanceMarksEnabled as p, ComputedOptions as pi, RouteState as pn, OverlayLayer as pr, rememberedDirectory as pt, OpfsDirectory as q, ColorScheme as qn, EachProps as qr, FramePhaseTimings as qt, UI_ROLES as r, ResourceStatus as ri, FontFamilyStatus as rn, UiSemanticsReport as rr, storageErrorMessage as rt, UiSemanticsMap$1 as s, FanCell as si, MediaService as sn, formatNodePath as sr, registerUndoShortcuts as st, EditingState$1 as t, ResourceOptions as ti, FontFaceLike as tn, UiPropOrigin as tr, StorageRead as tt, markInstant as u, FanOutOptions as ui, RouterHistorySink as un, printPropValue as ur, UndoStack as ut, SemanticsMirror as v, derive as vi, RouteOptions as vn, createComponent as vr, GessoAppOptions as vt, ScrollService as w, formatUrl as wn, pickKeys as wr, AppLogicEndpoint as wt, EditingProxySink as x, to as xn, isComponentElement as xr, WebMcpChoice as xt, SemanticsMirrorSink as y, ServiceRegistry as yi, RouteTarget as yn, ComponentElement as yr, createSyncApp as yt, FrameService as z, ShellFileRequest as zn, ThemeTokenCell as zr, PatchEntry as zt };
8596
- //# sourceMappingURL=index-CGLXEx9R.d.ts.map
8647
+ //# sourceMappingURL=index-Deqs0FCn.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as channel, a as isChannelHostMessage, c as applyPatch, d as ChannelSpec, f as ChannelToken, g as ViewOf, h as CommandsOf, i as isChannelClientMessage, l as applyPatches, m as CommandMap, n as ChannelHostMessage, o as Patch, p as Command, r as ChannelPort, s as PatchPath, t as ChannelClientMessage, u as diffProjection, v as defineChannel, y as viewKeys } from "./ChannelProtocol-ByNoHujM.js";
2
2
  import { A as portHandle, C as MessageEndpoint, D as isHubMessage, E as WorkerHandle, F as JsonSchema, I as channelSchema, L as describeChannel, M as workerHandle, N as ChannelSchema, O as isPortErrorMessage, P as CommandSchema, S as APPLICATION_WORKER, T as PortHost, _ as serve, b as ProvidedChannel, g as ServedChannel, j as servePorts, k as isPortHandshake, v as serveChannels, w as PortHandshake, x as provide, y as ChannelSource } from "./ui-D90CiOhW.js";
3
3
  import { C as InternalState, S as output, T as Component, _ as OutputTarget, a as ComponentType, b as into, c as Inputs, d as BoundsCell, f as bounds, g as OutputCell, h as InputCell, i as ComponentProps, l as isClassComponent, m as EmitValue, o as FunctionComponent, p as EmitArgs, r as ComponentContext, s as InputValue, t as ClassComponent, u as ChannelReplica, v as ReadableCell, w as internalState, x as isOutputTarget, y as input } from "./FunctionComponent-B1TJED62.js";
4
- import { $ as StorageAdapter, $n as UiNodeReport, $r as mutate, $t as UiFramePhase, A as Presence, An as AudioService, Ar as ChannelRegistry, At as createShellHistory, B as PersistedOptions, Bn as ShellFileResult, Br as themeTokenCell, Bt as UiTreeNode, C as FocusService, Cn as buildPath, Cr as pick, Ct as createApp, D as FindService, Dn as AudioMetadata, Dr as createChannelRegistry, Dt as ShellHistory, E as TextService, En as AudioAction, Er as ChannelRegistryHandle, Et as WorkerAppOptions, F as AudioSinkOptions, Fn as SpringOptions, Fr as Output, Ft as ConsoleEntry, G as IndexedDbStorage, Gn as ShellStorageOp, Gr as Each, Gt as ShellToRuntimeMessage, H as persisted, Hn as ShellRecentFile, Hr as Show, Ht as treeText, I as AudioSinkOutput, In as UiDuration, Ir as ControlledOptions, It as DevtoolsEvent, J as OpfsFileHandle, Jn as ColorSchemePreference, Jr as each, Jt as GessoRuntime, K as IndexedDbStorageOptions, Kn as ShellStorageResult, Kr as EachKey, Kt as FrameMetrics, L as MediaSessionLike, Ln as UiEasingChoice, Lr as ControlledValue, Lt as DevtoolsRequest, M as RouterOutlet, Mn as AudioStatus, Mr as Define, Mt as ActionEntry, N as AudioElementLike, Nn as AnimateOptions, Nr as Inject, Nt as ChannelErrorEntry, O as observeMediaQuery, On as AudioRequest, Or as findUnplainPath, Ot as ShellHistoryMode, P as AudioSink, Pn as AnimationService, Pr as Input, Pt as CommandEntry, Q as MemoryStorage, Qn as UiEnvironmentReport, Qr as Mutation, Qt as UI_FRAME_PHASES, R as audioClock, Rn as ShellFile, Rr as controlled, Rt as FrameEntry, S as writeClipboard, Sn as RouteParams, Sr as structurallyEqual, St as CreateAppOptions, T as EditingService, Tn as parseUrl, Tr as ChannelRegistration, Tt as WorkerApp, U as ShellStorage, Un as ShellRequest, Ur as ShowProps, Ut as RuntimeErrorSource, V as PersistedState, Vn as ShellFileType, Vr as bind, Vt as UiTreeSnapshot, W as ShellStorageOptions, Wn as ShellService, Wr as show, Wt as RuntimeToShellMessage, X as OpfsStorageOptions, Xn as BoundStream, Xr as throttled, Xt as RendererChoice, Y as OpfsStorage, Yn as observeColorScheme, Yr as debounced, Yt as GessoRuntimeOptions, Z as OpfsWritable, Zn as NodePathTarget, Zr as MutateOptions, Zt as RuntimeInput, _ as EditingMirrorTarget, _i as Equality, _n as RouteGuard, _r as OverlayService, _t as GessoApp, a as UiRole, ai as SelectOptions, an as FontService, ar as describeStream, at as storageReadValue, b as EditingProxy, bn as route, br as FrameworkChild, bt as GessoAppBuilder, c as UiSemanticsPatch, ci as FanKey, cn as RouteAnswer, cr as formatNodeReport, ct as UndoableOptions, d as markNow, di as fanOut, dn as RouterRoutes, dr as ComponentHostResolver, dt as UndoStackOptions, ei as Resource, en as FontFaceDeclaration, er as UiOwnerReport, et as StorageOutcome, f as measureSpan, fi as ComputedCell, fn as RouterService, fr as ComponentHost, ft as UndoTransaction, g as renderRoot, gi as DeriveOptions, gn as RouteDefinition, gr as OverlayRect, gt as shellStorageDenied, h as RenderWorkerApp, hi as computed, hn as RouteContext, hr as OverlayPlacement, ht as performShellStorage, i as UI_SEMANTIC_STATES, ii as resource, in as FontHost, ir as UiStreamReport, it as storageReadFailure, j as PresenceProps, jn as AudioState, jr as Channel, jt as ActionCause, k as observeReducedMotion, kn as AudioSample, kr as requirePlainData, kt as ShellHistoryOptions, l as UiSemanticsRecord, li as FanOut, ln as RouteMatch, lr as formatStream, lt as undoable, m as setPerformanceMarks, mi as ReadSource, mn as OutletProps, mr as OverlayEntry, mt as ShellLocalStore, n as MARK_PREFIX, ni as ResourceState, nn as FontFamilyDeclaration, nr as UiPropReport, nt as classifyStorageError, o as UiSemanticState, oi as select, on as MediaOptions, or as formatAge, ot as UndoShortcutOptions, p as performanceMarksEnabled, pi as ComputedOptions, pn as RouteState, pr as OverlayLayer, pt as rememberedDirectory, q as OpfsDirectory, qn as ColorScheme, qr as EachProps, qt as FramePhaseTimings, r as UI_ROLES, ri as ResourceStatus, rn as FontFamilyStatus, rr as UiSemanticsReport, rt as storageErrorMessage, s as UiSemanticsMap, si as FanCell, sn as MediaService, sr as formatNodePath, st as registerUndoShortcuts, t as EditingState, ti as ResourceOptions, tn as FontFaceLike, tr as UiPropOrigin, tt as StorageRead, u as markInstant, ui as FanOutOptions, un as RouterHistorySink, ur as printPropValue, ut as UndoStack, v as SemanticsMirror, vi as derive, vn as RouteOptions, vr as createComponent, vt as GessoAppOptions, w as ScrollService, wn as formatUrl, wr as pickKeys, wt as AppLogicEndpoint, x as EditingProxySink, xn as to, xr as isComponentElement, xt as WebMcpChoice, y as SemanticsMirrorSink, yi as ServiceRegistry, yn as RouteTarget, yr as ComponentElement, yt as createSyncApp, z as FrameService, zn as ShellFileRequest, zr as ThemeTokenCell, zt as PatchEntry } from "./index-CGLXEx9R.js";
4
+ import { $ as StorageAdapter, $n as UiNodeReport, $r as mutate, $t as UiFramePhase, A as Presence, An as AudioService, Ar as ChannelRegistry, At as createShellHistory, B as PersistedOptions, Bn as ShellFileResult, Br as themeTokenCell, Bt as UiTreeNode, C as FocusService, Cn as buildPath, Cr as pick, Ct as createApp, D as FindService, Dn as AudioMetadata, Dr as createChannelRegistry, Dt as ShellHistory, E as TextService, En as AudioAction, Er as ChannelRegistryHandle, Et as WorkerAppOptions, F as AudioSinkOptions, Fn as SpringOptions, Fr as Output, Ft as ConsoleEntry, G as IndexedDbStorage, Gn as ShellStorageOp, Gr as Each, Gt as ShellToRuntimeMessage, H as persisted, Hn as ShellRecentFile, Hr as Show, Ht as treeText, I as AudioSinkOutput, In as UiDuration, Ir as ControlledOptions, It as DevtoolsEvent, J as OpfsFileHandle, Jn as ColorSchemePreference, Jr as each, Jt as GessoRuntime, K as IndexedDbStorageOptions, Kn as ShellStorageResult, Kr as EachKey, Kt as FrameMetrics, L as MediaSessionLike, Ln as UiEasingChoice, Lr as ControlledValue, Lt as DevtoolsRequest, M as RouterOutlet, Mn as AudioStatus, Mr as Define, Mt as ActionEntry, N as AudioElementLike, Nn as AnimateOptions, Nr as Inject, Nt as ChannelErrorEntry, O as observeMediaQuery, On as AudioRequest, Or as findUnplainPath, Ot as ShellHistoryMode, P as AudioSink, Pn as AnimationService, Pr as Input, Pt as CommandEntry, Q as MemoryStorage, Qn as UiEnvironmentReport, Qr as Mutation, Qt as UI_FRAME_PHASES, R as audioClock, Rn as ShellFile, Rr as controlled, Rt as FrameEntry, S as writeClipboard, Sn as RouteParams, Sr as structurallyEqual, St as CreateAppOptions, T as EditingService, Tn as parseUrl, Tr as ChannelRegistration, Tt as WorkerApp, U as ShellStorage, Un as ShellRequest, Ur as ShowProps, Ut as RuntimeErrorSource, V as PersistedState, Vn as ShellFileType, Vr as bind, Vt as UiTreeSnapshot, W as ShellStorageOptions, Wn as ShellService, Wr as show, Wt as RuntimeToShellMessage, X as OpfsStorageOptions, Xn as BoundStream, Xr as throttled, Xt as RendererChoice, Y as OpfsStorage, Yn as observeColorScheme, Yr as debounced, Yt as GessoRuntimeOptions, Z as OpfsWritable, Zn as NodePathTarget, Zr as MutateOptions, Zt as RuntimeInput, _ as EditingMirrorTarget, _i as Equality, _n as RouteGuard, _r as OverlayService, _t as GessoApp, a as UiRole, ai as SelectOptions, an as FontService, ar as describeStream, at as storageReadValue, b as EditingProxy, bn as route, br as FrameworkChild, bt as GessoAppBuilder, c as UiSemanticsPatch, ci as FanKey, cn as RouteAnswer, cr as formatNodeReport, ct as UndoableOptions, d as markNow, di as fanOut, dn as RouterRoutes, dr as ComponentHostResolver, dt as UndoStackOptions, ei as Resource, en as FontFaceDeclaration, er as UiOwnerReport, et as StorageOutcome, f as measureSpan, fi as ComputedCell, fn as RouterService, fr as ComponentHost, ft as UndoTransaction, g as renderRoot, gi as DeriveOptions, gn as RouteDefinition, gr as OverlayRect, gt as shellStorageDenied, h as RenderWorkerApp, hi as computed, hn as RouteContext, hr as OverlayPlacement, ht as performShellStorage, i as UI_SEMANTIC_STATES, ii as resource, in as FontHost, ir as UiStreamReport, it as storageReadFailure, j as PresenceProps, jn as AudioState, jr as Channel, jt as ActionCause, k as observeReducedMotion, kn as AudioSample, kr as requirePlainData, kt as ShellHistoryOptions, l as UiSemanticsRecord, li as FanOut, ln as RouteMatch, lr as formatStream, lt as undoable, m as setPerformanceMarks, mi as ReadSource, mn as OutletProps, mr as OverlayEntry, mt as ShellLocalStore, n as MARK_PREFIX, ni as ResourceState, nn as FontFamilyDeclaration, nr as UiPropReport, nt as classifyStorageError, o as UiSemanticState, oi as select, on as MediaOptions, or as formatAge, ot as UndoShortcutOptions, p as performanceMarksEnabled, pi as ComputedOptions, pn as RouteState, pr as OverlayLayer, pt as rememberedDirectory, q as OpfsDirectory, qn as ColorScheme, qr as EachProps, qt as FramePhaseTimings, r as UI_ROLES, ri as ResourceStatus, rn as FontFamilyStatus, rr as UiSemanticsReport, rt as storageErrorMessage, s as UiSemanticsMap, si as FanCell, sn as MediaService, sr as formatNodePath, st as registerUndoShortcuts, t as EditingState, ti as ResourceOptions, tn as FontFaceLike, tr as UiPropOrigin, tt as StorageRead, u as markInstant, ui as FanOutOptions, un as RouterHistorySink, ur as printPropValue, ut as UndoStack, v as SemanticsMirror, vi as derive, vn as RouteOptions, vr as createComponent, vt as GessoAppOptions, w as ScrollService, wn as formatUrl, wr as pickKeys, wt as AppLogicEndpoint, x as EditingProxySink, xn as to, xr as isComponentElement, xt as WebMcpChoice, y as SemanticsMirrorSink, yi as ServiceRegistry, yn as RouteTarget, yr as ComponentElement, yt as createSyncApp, z as FrameService, zn as ShellFileRequest, zr as ThemeTokenCell, zt as PatchEntry } from "./index-Deqs0FCn.js";
5
5
  export { APPLICATION_WORKER, type ActionCause, type ActionEntry, type AnimateOptions, AnimationService, type AppLogicEndpoint, type AudioAction, type AudioElementLike, type AudioMetadata, type AudioRequest, type AudioSample, AudioService, AudioSink, type AudioSinkOptions, type AudioSinkOutput, type AudioState, type AudioStatus, type BoundStream, BoundsCell, Channel, type ChannelClientMessage, type ChannelErrorEntry, type ChannelHostMessage, type ChannelPort, type ChannelRegistration, ChannelRegistry, type ChannelRegistryHandle, ChannelReplica, type ChannelSchema, type ChannelSource, type ChannelSpec, type ChannelToken, type ClassComponent, type ColorScheme, type ColorSchemePreference, type Command, type CommandEntry, type CommandMap, type CommandSchema, type CommandsOf, Component, type ComponentContext, type ComponentElement, ComponentHost, ComponentHostResolver, type ComponentProps, type ComponentType, ComputedCell, type ComputedOptions, type ConsoleEntry, type ControlledOptions, type ControlledValue, type CreateAppOptions, Define, type DeriveOptions, type DevtoolsEvent, type DevtoolsRequest, Each, type EachKey, type EachProps, type EditingMirrorTarget, EditingProxy, type EditingProxySink, EditingService, type EditingState, type EmitArgs, type EmitValue, type Equality, FanCell, type FanKey, FanOut, type FanOutOptions, FindService, FocusService, type FontFaceDeclaration, type FontFaceLike, type FontFamilyDeclaration, type FontFamilyStatus, type FontHost, FontService, type FrameEntry, type FrameMetrics, type FramePhaseTimings, FrameService, type FrameworkChild, type FunctionComponent, GessoApp, GessoAppBuilder, type GessoAppOptions, GessoRuntime, type GessoRuntimeOptions, IndexedDbStorage, type IndexedDbStorageOptions, Inject, Input, InputCell, type InputValue, type Inputs, InternalState, type JsonSchema, MARK_PREFIX, type MediaOptions, MediaService, type MediaSessionLike, MemoryStorage, type MessageEndpoint, type MutateOptions, type Mutation, type NodePathTarget, type OpfsDirectory, type OpfsFileHandle, OpfsStorage, type OpfsStorageOptions, type OpfsWritable, type OutletProps, Output, type OutputCell, type OutputTarget, type OverlayEntry, OverlayLayer, type OverlayPlacement, type OverlayRect, OverlayService, type Patch, type PatchEntry, type PatchPath, type PersistedOptions, PersistedState, type PortHandshake, type PortHost, Presence, type PresenceProps, ProvidedChannel, type ReadSource, type ReadableCell, RenderWorkerApp, type RendererChoice, Resource, type ResourceOptions, type ResourceState, type ResourceStatus, type RouteAnswer, type RouteContext, type RouteDefinition, type RouteGuard, type RouteMatch, type RouteOptions, type RouteParams, RouteState, type RouteTarget, type RouterHistorySink, RouterOutlet, type RouterRoutes, RouterService, type RuntimeErrorSource, type RuntimeInput, type RuntimeToShellMessage, ScrollService, type SelectOptions, SemanticsMirror, type SemanticsMirrorSink, type ServedChannel, ServiceRegistry, type ShellFile, type ShellFileRequest, type ShellFileResult, type ShellFileType, type ShellHistory, type ShellHistoryMode, type ShellHistoryOptions, type ShellLocalStore, type ShellRecentFile, type ShellRequest, ShellService, ShellStorage, type ShellStorageOp, type ShellStorageOptions, type ShellStorageResult, type ShellToRuntimeMessage, Show, type ShowProps, type SpringOptions, type StorageAdapter, type StorageOutcome, type StorageRead, TextService, ThemeTokenCell, UI_FRAME_PHASES, UI_ROLES, UI_SEMANTIC_STATES, type UiDuration, type UiEasingChoice, type UiEnvironmentReport, type UiFramePhase, type UiNodeReport, type UiOwnerReport, type UiPropOrigin, type UiPropReport, type UiRole, type UiSemanticState, type UiSemanticsMap, type UiSemanticsPatch, type UiSemanticsRecord, type UiSemanticsReport, type UiStreamReport, type UiTreeNode, type UiTreeSnapshot, type UndoShortcutOptions, UndoStack, type UndoStackOptions, type UndoTransaction, type UndoableOptions, type ViewOf, type WebMcpChoice, WorkerApp, type WorkerAppOptions, type WorkerHandle, applyPatch, applyPatches, audioClock, bind, bounds, buildPath, channel, channelSchema, classifyStorageError, computed, controlled, createApp, createChannelRegistry, createComponent, createShellHistory, createSyncApp, debounced, defineChannel, derive, describeChannel, describeStream, diffProjection, each, fanOut, findUnplainPath, formatAge, formatNodePath, formatNodeReport, formatStream, formatUrl, input, internalState, into, isChannelClientMessage, isChannelHostMessage, isClassComponent, isComponentElement, isHubMessage, isOutputTarget, isPortErrorMessage, isPortHandshake, markInstant, markNow, measureSpan, mutate, observeColorScheme, observeMediaQuery, observeReducedMotion, output, parseUrl, performShellStorage, performanceMarksEnabled, persisted, pick, pickKeys, portHandle, printPropValue, provide, registerUndoShortcuts, rememberedDirectory, renderRoot, requirePlainData, resource, route, select, serve, serveChannels, servePorts, setPerformanceMarks, shellStorageDenied, show, storageErrorMessage, storageReadFailure, storageReadValue, structurallyEqual, themeTokenCell, throttled, to, treeText, undoable, viewKeys, workerHandle, writeClipboard };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { a as Each, i as show, n as getComponentMetadata, o as each, r as Show,
4
4
  import { c as findUnplainPath, d as describeChannel, l as requirePlainData, t as AGENT_PORT, u as channelSchema } from "./remote-BoB8zh7z.js";
5
5
  import { n as serveApplicationAgent } from "./app-Yig59Ygf.js";
6
6
  import { BehaviorSubject, EMPTY, Observable, Subject, Subscription, distinctUntilChanged, map } from "rxjs";
7
- import { AnimationDriver, Box, Canvas2DRenderer, CanvasPlatformSurface, CanvasTextMeasurer, Constraints, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, EnvironmentNotifier, FocusNotifier, IconRasterizer, LayoutEngine, LayoutInspector, LayoutNotifier, MARK_PREFIX, Stack, TEXT_RUN_ID_SEPARATOR, UI_ROLES, UI_SEMANTIC_STATES, UiAnimationFrameClock, UiEditingController, UiEnvironmentKeys, UiEventType, UiFindController, UiFocusManager, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInsetRegistry, UiKeyboardController, UiNodeType, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiScheduler, UiSelectionController, UiSharedElements, UiSpring, UiTimerFrameClock, UiTouchScroller, UiVirtualSheet, UiVirtualWindow, UiWheelController, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPURenderer, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, capturePointer, createCanvasSurface, createTween, createWebGPUSurface, defaultMotion, defineModifier, describeOverrides, diffSemantics, dragSessionFor, dropIndexShifts, easings, fade, formatExplanation, insetsEqual, isComponentLikeElement, isImeKey, isObservable, isWebGPUAvailable, linear, linkOf, markInstant, markNow, measure, measureSpan, motion, noInsets, observeViewportInsets, percent, performanceMarksEnabled, pointerDeviceOf, prepareInputSurface, propertyEffects, recordsEqual, registerFontStack, resolveCursor, rewalkSemantics, scrollRange, scrollbarThumb, semanticsInertAbove, semanticsMemory, setPerformanceMarks, setPerformanceMarks as setPerformanceMarks$1, textRunOfRecordId, themeTokens, touchActionFor, wheelDeltaYOf } from "gesso-core";
7
+ import { AnimationDriver, Box, Canvas2DRenderer, CanvasPlatformSurface, CanvasTextMeasurer, Constraints, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, EnvironmentNotifier, FocusNotifier, IconRasterizer, LayoutEngine, LayoutInspector, LayoutNotifier, MARK_PREFIX, Stack, TEXT_RUN_ID_SEPARATOR, UI_ROLES, UI_SEMANTIC_STATES, UiAnimationFrameClock, UiEditingController, UiEnvironmentKeys, UiEventType, UiFindController, UiFocusManager, UiFrame, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInsetRegistry, UiKeyboardController, UiNodeType, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiScheduler, UiSelectionController, UiSharedElements, UiSpring, UiTimerFrameClock, UiTouchScroller, UiVirtualSheet, UiVirtualWindow, UiWheelController, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPURenderer, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, capturePointer, createCanvasSurface, createTween, createWebGPUSurface, defaultMotion, defineModifier, describeOverrides, diffSemantics, dragSessionFor, dropIndexShifts, easings, fade, formatExplanation, insetsEqual, isComponentLikeElement, isImeKey, isObservable, isWebGPUAvailable, linear, linkOf, markInstant, markNow, measure, measureSpan, motion, noInsets, observeViewportInsets, percent, performanceMarksEnabled, pointerDeviceOf, prepareInputSurface, propertyEffects, recordsEqual, registerFontStack, resolveCursor, rewalkSemantics, scrollRange, scrollbarThumb, semanticsInertAbove, semanticsMemory, setPerformanceMarks, setPerformanceMarks as setPerformanceMarks$1, textRunOfRecordId, themeTokens, touchActionFor, wheelDeltaYOf } from "gesso-core";
8
8
  //#region src/Component.ts
9
9
  /**
10
10
  * Base class for all Gesso framework components.
@@ -4341,6 +4341,8 @@ function watchPixelRatio(onChange, view = globalThis.window) {
4341
4341
  }
4342
4342
  //#endregion
4343
4343
  //#region src/app/worker/WorkerApp.ts
4344
+ /** Refreshes timed to tell the worker the display's interval. */
4345
+ const DISPLAY_SAMPLES = 12;
4344
4346
  /**
4345
4347
  * Main-thread half of a worker-hosted Gesso application.
4346
4348
  *
@@ -4831,6 +4833,29 @@ var WorkerApp = class {
4831
4833
  };
4832
4834
  this.frameHandle = requestAnimationFrame(step);
4833
4835
  }
4836
+ /**
4837
+ * Measures the display's interval on this thread's refreshes and tells
4838
+ * the worker, whose own may keep no display's time; see
4839
+ * `displayInterval` in the protocol. A dozen refreshes, once, at start.
4840
+ */
4841
+ measureDisplay() {
4842
+ if (typeof requestAnimationFrame !== "function") return;
4843
+ const times = [];
4844
+ const step = (time) => {
4845
+ times.push(time);
4846
+ if (times.length < DISPLAY_SAMPLES) {
4847
+ requestAnimationFrame(step);
4848
+ return;
4849
+ }
4850
+ const gaps = times.slice(1).map((value, index) => value - times[index]).sort((a, b) => a - b);
4851
+ this.post({
4852
+ type: "displayInterval",
4853
+ ms: gaps[Math.floor(gaps.length / 2)],
4854
+ origin: performance.timeOrigin
4855
+ });
4856
+ };
4857
+ requestAnimationFrame(step);
4858
+ }
4834
4859
  dispose() {
4835
4860
  this.disconnectWebMcp?.();
4836
4861
  this.disconnectWebMcp = null;
@@ -4905,6 +4930,8 @@ var WorkerApp = class {
4905
4930
  layoutPasses: message.layoutPasses,
4906
4931
  at: message.at,
4907
4932
  inputLatencyMs: message.inputLatencyMs,
4933
+ time: message.time,
4934
+ wheelScroll: message.wheelScroll,
4908
4935
  phases: message.phases,
4909
4936
  renderer: message.renderer,
4910
4937
  gpu: message.gpu
@@ -4917,6 +4944,7 @@ var WorkerApp = class {
4917
4944
  }
4918
4945
  if (message.type === "ready") {
4919
4946
  this.ready = true;
4947
+ this.measureDisplay();
4920
4948
  return;
4921
4949
  }
4922
4950
  if (message.type === "frameLoop") {
@@ -7410,6 +7438,10 @@ var GessoRuntime = class {
7410
7438
  constraints;
7411
7439
  pixelRatio;
7412
7440
  lastFrameMs = 0;
7441
+ /** The display time the frame being drawn is for; see `FrameMetrics.time`. */
7442
+ frameTime = null;
7443
+ /** When the frame's first phase began, before its changes were collected; see `FrameMetrics.durationMs`. */
7444
+ frameBegan = null;
7413
7445
  frameListener = null;
7414
7446
  rendererErrorListener = null;
7415
7447
  frameErrorListener = null;
@@ -9492,6 +9524,15 @@ var GessoRuntime = class {
9492
9524
  }
9493
9525
  };
9494
9526
  }
9527
+ /** Where the container the wheel last scrolled is; see `FrameMetrics.wheelScroll`. */
9528
+ wheelScroll() {
9529
+ const node = this.input.wheel.lastScrolled;
9530
+ const record = node === null ? void 0 : this.engine.recordFor(node);
9531
+ return record === void 0 ? null : {
9532
+ x: record.scrollX,
9533
+ y: record.scrollY
9534
+ };
9535
+ }
9495
9536
  /**
9496
9537
  * Work that must happen before the frame's dirty set is snapshotted.
9497
9538
  *
@@ -9511,7 +9552,9 @@ var GessoRuntime = class {
9511
9552
  * silently did nothing, so a theme change never reached descendants.
9512
9553
  */
9513
9554
  runPreCollectPhases(time) {
9555
+ this.frameBegan = now();
9514
9556
  this.phaseTimings = emptyPhaseTimings();
9557
+ this.frameTime = time;
9515
9558
  this.phaseTimings.ticks = this.timePhase(() => this.visible && this.animations.isRunning, () => this.animations.advance(time));
9516
9559
  this.scheduleAnimationTick(time);
9517
9560
  this.phaseTimings.patches = this.timePhase(() => this.replicas.some((replica) => replica.hasPendingPatches), () => {
@@ -9749,10 +9792,10 @@ var GessoRuntime = class {
9749
9792
  if (this.renderer.backend === "webgpu" && this.renderer.isLost) this.recoverWebGPU(this.renderer);
9750
9793
  const overlay = this.inspector.hasOverlay ? this.inspector.overlay(started) : null;
9751
9794
  this.gpuTimings = null;
9752
- const changes = this.graph.getDirtyNodes().isEmpty() ? {
9753
- frame,
9795
+ const changes = {
9796
+ frame: withPending(frame, this.graph.getDirtyNodes()),
9754
9797
  geometryVersion: this.engine.geometryVersion
9755
- } : void 0;
9798
+ };
9756
9799
  this.phaseTimings.render = this.timePhase(() => this.renderer.isReady, () => this.renderer.render(root, {
9757
9800
  layout: this.engine,
9758
9801
  text: this.textMeasurer,
@@ -9766,7 +9809,8 @@ var GessoRuntime = class {
9766
9809
  }
9767
9810
  this.sendDevtoolsUpdates(frame);
9768
9811
  const finished = now();
9769
- const elapsed = finished - started;
9812
+ const elapsed = finished - (this.frameBegan ?? started);
9813
+ this.frameBegan = null;
9770
9814
  this.lastFrameMs = elapsed;
9771
9815
  this.scheduleScrollbarFade(finished);
9772
9816
  this.scheduleCaretBlink(finished);
@@ -9781,6 +9825,8 @@ var GessoRuntime = class {
9781
9825
  layoutPasses: settled.passes,
9782
9826
  at: finished,
9783
9827
  inputLatencyMs: this.inputLatency.take(epochAt(finished)),
9828
+ time: this.frameTime,
9829
+ wheelScroll: this.wheelScroll(),
9784
9830
  phases: this.phaseTimings,
9785
9831
  renderer: this.rendererState,
9786
9832
  gpu: this.gpuTimings
@@ -10117,6 +10163,13 @@ function watchContextRestored(canvas, restored) {
10117
10163
  target.addEventListener("contextrestored", restored);
10118
10164
  return () => target.removeEventListener?.("contextrestored", restored);
10119
10165
  }
10166
+ /** A frame's changes and those made since it was collected, together. */
10167
+ function withPending(frame, pending) {
10168
+ if (pending.isEmpty()) return frame;
10169
+ const merged = new Map(frame.entries());
10170
+ for (const node of pending.values()) merged.set(node, (merged.get(node) ?? DirtyFlags.None) | node.dirtyFlags);
10171
+ return new UiFrame(frame.id, frame.time, merged);
10172
+ }
10120
10173
  //#endregion
10121
10174
  //#region src/app/GessoApp.ts
10122
10175
  /**
@@ -11741,6 +11794,9 @@ var RenderWorkerApp = class {
11741
11794
  case "tick":
11742
11795
  this.clock?.tick(message.time);
11743
11796
  break;
11797
+ case "displayInterval":
11798
+ this.clock?.displayInterval(message.ms, message.origin);
11799
+ break;
11744
11800
  case "fullscreenChanged":
11745
11801
  runtime.setFullscreen(message.active);
11746
11802
  return;
@@ -11969,6 +12025,8 @@ var RenderWorkerApp = class {
11969
12025
  layoutPasses: metrics.layoutPasses,
11970
12026
  at: metrics.at,
11971
12027
  inputLatencyMs: metrics.inputLatencyMs,
12028
+ time: metrics.time,
12029
+ wheelScroll: metrics.wheelScroll,
11972
12030
  phases: metrics.phases,
11973
12031
  renderer: metrics.renderer,
11974
12032
  gpu: metrics.gpu