/** Calm ease while live: remaining debt shrinks ~63% every τ_max ms. */ export declare const TIP_FOLLOW_TAU_MAX_MS: number; /** Catch-up ease under large tip-debt (reader far behind / big paste). */ export declare const TIP_FOLLOW_TAU_MIN_MS: number; /** * Idle settle τ — stream quiet, soft landing into the tip. Longer than live * calm so the last pixels decelerate instead of linear-crawling then stopping. */ export declare const TIP_FOLLOW_SETTLE_TAU_MS: number; /** Debt that saturates urgency toward τ_min. */ export declare const TIP_FOLLOW_CATCHUP_DEBT_PX = 240; /** Keep the rAF alive this long after the last height growth. */ export declare const TIP_FOLLOW_HOT_IDLE_MS: number; /** Cold oversized debt snaps (session switch / huge fold), not eases. */ export declare const TIP_FOLLOW_SNAP_PX = 480; /** Soft speed floor while live with tiny debt (px/s). */ export declare const TIP_FOLLOW_CALM_MAX_PX_S: number; /** Soft speed ceiling while catching a fast stream / modest tip-debt (px/s). */ export declare const TIP_FOLLOW_BURST_MAX_PX_S: number; /** Ceiling for huge tip-debt / large single-frame walls (px/s). */ export declare const TIP_FOLLOW_SURGE_MAX_PX_S: number; /** * @deprecated Position growth-track removed — camera is velocity-smoothed. * Kept so older tests/imports do not break. */ export declare const TIP_FOLLOW_GROWTH_TRACK = 0; /** @deprecated */ export declare const TIP_FOLLOW_LINE_TRACK = 0; /** @deprecated Sub-line special-case removed with growth-track. */ export declare const TIP_FOLLOW_TOKEN_GROWTH_PX = 10; /** Hot line-sized tip-debt uses the short {@link TIP_FOLLOW_LINE_TAU_MS}. */ export declare const TIP_FOLLOW_LINE_GROWTH_PX = 48; /** Hot τ ceiling while closing a line-sized tip-debt (ms). */ export declare const TIP_FOLLOW_LINE_TAU_MS: number; /** * Velocity ease-in/out: scrollVel approaches desiredVel with this fraction of τ. * Lower → snappier accel; higher → softer start (and slower reaction). */ export declare const TIP_FOLLOW_ACCEL_TAU_FRAC = 0.45; /** @deprecated Soft-rise FLIP removed — line glue was the bug. */ export declare const TIP_FOLLOW_SOFT_RISE_MS = 0; /** @deprecated */ export declare const TIP_FOLLOW_SOFT_RISE_MAX_PX = 96; /** @deprecated */ export declare const TIP_FOLLOW_SOFT_RISE_EASING = "cubic-bezier(0.22, 1, 0.36, 1)"; /** Ignore sub-pixel / reflow height noise for shrink compensate. */ export declare const TIP_FOLLOW_SHRINK_EPS_PX = 4; /** Growth speed (px/s) that saturates velocity urgency. */ export declare const TIP_FOLLOW_VELOCITY_REF_PX_S: number; /** * Tip-debt below which growth velocity must not tighten τ. * Sparse tokens are high-velocity by nature; only arm once actually behind. */ export declare const TIP_FOLLOW_VELOCITY_ARM_DEBT_PX = 72; /** EMA decay τ for growthVelocity when height is flat (ms). */ export declare const TIP_FOLLOW_VELOCITY_DECAY_MS: number; /** Reader-up pixels above clamp budget that count as leaving the tip. */ export declare const TIP_FOLLOW_READER_UP_EPS_PX = 2; /** * Browsers snap scrollTop writes to device pixels (whole px at dpr 1). A DOM * position within this window of the camera's own fractional position is that * quantization echo, not external motion — keep the fraction so sub-pixel * settle steps accumulate. Anything larger (clamp, user, glue) re-bases. */ export declare const TIP_FOLLOW_QUANTIZE_WINDOW_PX = 1; /** @internal */ export declare function setScrollEndSupportForTests(value: boolean | null): void; /** True when the engine exposes element `scrollend` (prefer over rAF leave). */ export declare function supportsScrollEndEvent(): boolean; /** @deprecated Shrink lock removed; kept so old imports do not break. */ export declare const TIP_FOLLOW_SHRINK_LOCK_MS = 0; /** @deprecated Absorb thresholds removed — growth track is continuous. */ export declare const TIP_FOLLOW_GROWTH_ABSORB_PX = 96; /** * ScrollTop decrease not explained by a maxScroll clamp (fold / composer * shrink). Fold clamp: top falls by ≈ maxScroll fall → 0. Real scroll-up: * top falls while maxScroll holds → positive. No timers. */ export declare function readerScrollUpPx(prevTop: number, nextTop: number, prevMaxScroll: number, nextMaxScroll: number): number; export type TipFollowState = { running: boolean; hotUntil: number; lastTs: number; lastHeight: number; /** Last observed scroller clientHeight — viewport shrink heats like tip growth. */ lastClientHeight: number; lastGrowthAt: number; /** EMA of recent height growth (px/s); nudges τ / ceiling under bursts. */ growthVelocity: number; /** Camera velocity toward tip (px/s). Smoothed — never jumps with debt. */ scrollVelocity: number; /** * Fractional camera position. The DOM quantizes scrollTop to device pixels, * so settle steps under 1px would be discarded every frame if the camera * re-based on the DOM — it then parks 20-50px short of the tip forever. * `null` = no fraction in flight; adopt the DOM position. */ cameraTop: number | null; }; export type TipFollowStepInput = { scrollTop: number; scrollHeight: number; clientHeight: number; now: number; pinned: boolean; reducedMotion: boolean; revealed: boolean; }; export type TipFollowStepResult = { scrollTop: number; state: TipFollowState; }; export declare function createTipFollowState(): TipFollowState; export declare function tipFollowCancel(state: TipFollowState): TipFollowState; /** * Record content height. Positive growth extends the hot window so sparse * lines do not tear down the follow loop between appends. */ export declare function tipFollowNoteGrowth(state: TipFollowState, height: number, now: number): TipFollowState; /** * Record scroller viewport height. A shrink (composer / SessionChrome / * window) raises tip debt (`scrollHeight - clientHeight`) without growing * content — the same debt content-growth would create. Heat the camera so * catch-up does not fall into cold soft-settle (~42px/s) and leave the tip * parked under the chrome. */ export declare function tipFollowNoteViewportShrink(state: TipFollowState, clientHeight: number, now: number): TipFollowState; /** * Adaptive τ: small debt → calm; large debt / armed velocity → catch-up. * While hot, floor urgency so live streams are not stuck on calm τ. * Idle settle uses the longer settle τ. */ export declare function tipFollowTauMs(debtPx: number, growthVelocityPxPerSec?: number, settling?: boolean, hot?: boolean): number; /** * Soft speed ceiling from continuous signals (debt, velocity EMA, this-frame * growth). No mode switches — larger inputs raise the ceiling smoothly. */ export declare function tipFollowMaxStepPx(debtPx: number, growthVelocityPxPerSec: number, dtMs: number, frameGrowthPx?: number, hot?: boolean): number; /** * Counter-offset for soft-rise after tip-glue: start from the mid-flight * translateY (if any) plus this frame's glued scroll delta, capped. * Shell applies translateY(from) → 0 over {@link TIP_FOLLOW_SOFT_RISE_MS}. */ export declare function tipFollowSoftRiseFrom(currentTranslateY: number, gluedScrollDelta: number, maxPx?: number): number; /** Read live translateY from a transformed content column (mid soft-rise). */ export declare function readTranslateY(el: HTMLElement): number; /** * Cancel the tip-glue pop: start at translateY(+δ) and ease to 0. * Uses WAAPI — a same-frame CSS transition never paints the counter-offset, * so the scroll jump stays an instant one-line pop. */ export declare function tipFollowPlaySoftRise(el: HTMLElement, gluedScrollDelta: number, opts?: { durationMs?: number; maxPx?: number; easing?: string; }): void; /** Stop soft-rise and clear any CSS transform residue. */ export declare function tipFollowClearSoftRise(el: HTMLElement): void; /** * Height left the document (settle collapse / composer). Keep the same pixels * on screen: scrollTop -= Δh, clamped to the new max. */ export declare function tipFollowCompensateShrink(scrollTop: number, previousHeight: number, nextHeight: number, clientHeight: number, epsPx?: number): number; export type TipFollowContentShrinkBaseline = { scrollHeight: number; scrollTop: number; }; export type TipFollowContentShrinkObservation = { baseline: TipFollowContentShrinkBaseline | null; compensatedScrollTop: number | null; }; /** * Retain the geometry from the first sub-epsilon content-shrink frame until * the cumulative collapse crosses the deadband. Browsers may clamp scrollTop * after every tiny frame, so compensating from the latest DOM top would count * those already-applied clamps twice and make the result animation-cadence * dependent. */ export declare function tipFollowObserveContentShrink(baseline: TipFollowContentShrinkBaseline | null, previousHeight: number, previousScrollTop: number, nextHeight: number, clientHeight: number, epsPx?: number): TipFollowContentShrinkObservation; /** * Viewport shrank (SessionChrome / composer / window). maxScroll rises by ≈Δc; * keep the same tip distance: scrollTop += Δc. Without this, pinned follow only * sees new tip debt and soft-settles under the chrome. */ export declare function tipFollowCompensateViewportShrink(scrollTop: number, previousClientHeight: number, nextClientHeight: number, scrollHeight: number, epsPx?: number): number; /** * One camera step. Shell schedules the next rAF while `result.state.running`. */ export declare function tipFollowStep(state: TipFollowState, input: TipFollowStepInput): TipFollowStepResult;