@vitreajs/vitrea 0.1.0 → 0.2.0
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/README.md +226 -22
- package/dist/{dist-FGJI5LQM.js → dist-RQ4ZMA3D.js} +984 -98
- package/dist/dist-RQ4ZMA3D.js.map +1 -0
- package/dist/index.d.ts +555 -39
- package/dist/index.js +129 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/dist-FGJI5LQM.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface GPUBuffer {}
|
|
3
|
+
interface GPUCommandEncoder {}
|
|
4
|
+
interface GPUComputePassTimestampWrites {}
|
|
5
|
+
interface GPUDevice {}
|
|
6
|
+
interface GPUExternalTexture {}
|
|
7
|
+
interface GPUExternalTextureDescriptor {}
|
|
8
|
+
interface GPUQueue {}
|
|
9
|
+
interface GPURenderPassTimestampWrites {}
|
|
10
|
+
interface GPUSupportedLimits {}
|
|
11
|
+
interface GPUTexture {}
|
|
12
|
+
interface GPUTextureDescriptor {}
|
|
13
|
+
interface GPUTextureView {}
|
|
14
|
+
}
|
|
15
|
+
type GPUTextureFormat = "bgra8unorm" | "rgba8unorm" | "rgba16float" | (string & {});
|
|
16
|
+
|
|
1
17
|
/**
|
|
2
18
|
* X8 — the shape channel set, and the vocabulary every other module speaks.
|
|
3
19
|
*
|
|
@@ -164,13 +180,40 @@ type InteractionState = (typeof INTERACTION_STATES)[number];
|
|
|
164
180
|
* source — are *not* diagnostics. Those throw `GlassSceneError`, because
|
|
165
181
|
* continuing past them would leave a half-built scene. Diagnostics carry the
|
|
166
182
|
* recoverable, per-frame, policy-level findings instead.
|
|
183
|
+
*
|
|
184
|
+
* ## One channel, several code spaces
|
|
185
|
+
*
|
|
186
|
+
* The channel is generic over its code union and core's own union is only its
|
|
187
|
+
* default instantiation. That is what lets the browser layer — which detects
|
|
188
|
+
* things core cannot name, like a host placed outside its plane — have a code
|
|
189
|
+
* space of its own without a second copy of the machinery, and it is why the
|
|
190
|
+
* dedupe rule, the retention rule and the key separator have exactly one
|
|
191
|
+
* definition in the workspace (Decision Log #21(b), #23(c)).
|
|
192
|
+
*
|
|
193
|
+
* Two properties are load-bearing and deliberately *not* generalised:
|
|
194
|
+
*
|
|
195
|
+
* - **A diagnostic carries no origin tag.** Which code space a finding came
|
|
196
|
+
* from is the channel's business, added on the way out to a host's sink, not
|
|
197
|
+
* a field every emitter has to write. `platform-web`'s `layer-model.ts` is
|
|
198
|
+
* the proof: it is a pure function that takes a bare `report` callback, and
|
|
199
|
+
* an origin tag in the payload would have rewritten every emitter in it.
|
|
200
|
+
* - **`report` stays assignable to `(d) => void`.** Checkers take the
|
|
201
|
+
* capability to report, never the channel, so a module that emits findings
|
|
202
|
+
* knows nothing about retention or dedupe.
|
|
167
203
|
*/
|
|
168
204
|
type DiagnosticSeverity = "warning" | "error";
|
|
169
205
|
/** Everything core can report. Owned here so a host can switch exhaustively. */
|
|
170
|
-
declare const DIAGNOSTIC_CODES: readonly ["same-plane-overlap", "variant-mixing", "merge-distance-below-padding", "group-proxy-overlap", "clear-variant-needs-dimming", "foreground-mode-illegal", "foreground-rate-clamped", "backdrop-hint-out-of-range", "backdrop-hint-redundant-estimator", "reduced-transparency-undetectable", "frame-phase-violation"];
|
|
206
|
+
declare const DIAGNOSTIC_CODES: readonly ["same-plane-overlap", "variant-mixing", "tint-mixing", "merge-distance-below-padding", "group-proxy-overlap", "clear-variant-needs-dimming", "foreground-mode-illegal", "foreground-rate-clamped", "backdrop-hint-out-of-range", "backdrop-hint-redundant-estimator", "reduced-transparency-undetectable", "frame-phase-violation"];
|
|
171
207
|
type DiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];
|
|
172
|
-
|
|
173
|
-
|
|
208
|
+
/**
|
|
209
|
+
* One finding, over whichever code space the channel was opened on.
|
|
210
|
+
*
|
|
211
|
+
* `Code` defaults to core's own union, so `Diagnostic` unqualified still means
|
|
212
|
+
* exactly what it meant before the channel became generic and every existing
|
|
213
|
+
* annotation of it still reads.
|
|
214
|
+
*/
|
|
215
|
+
interface Diagnostic<Code extends string = DiagnosticCode> {
|
|
216
|
+
readonly code: Code;
|
|
174
217
|
readonly severity: DiagnosticSeverity;
|
|
175
218
|
/**
|
|
176
219
|
* The ids this finding is about — group, node, or source. Together with
|
|
@@ -180,21 +223,21 @@ interface Diagnostic {
|
|
|
180
223
|
readonly subjects: readonly string[];
|
|
181
224
|
readonly message: string;
|
|
182
225
|
}
|
|
183
|
-
type DiagnosticSink = (diagnostic: Diagnostic) => void;
|
|
184
|
-
interface DiagnosticsChannel {
|
|
185
|
-
report(diagnostic: Diagnostic): void;
|
|
226
|
+
type DiagnosticSink<Code extends string = DiagnosticCode> = (diagnostic: Diagnostic<Code>) => void;
|
|
227
|
+
interface DiagnosticsChannel<Code extends string = DiagnosticCode> {
|
|
228
|
+
report(diagnostic: Diagnostic<Code>): void;
|
|
186
229
|
/** Findings retained since construction or the last `clear()`. */
|
|
187
|
-
readonly reported: readonly Diagnostic[];
|
|
230
|
+
readonly reported: readonly Diagnostic<Code>[];
|
|
188
231
|
/** Forget what was seen, so a condition that returns is reported again. */
|
|
189
232
|
clear(): void;
|
|
190
233
|
}
|
|
191
|
-
interface DiagnosticsChannelOptions {
|
|
234
|
+
interface DiagnosticsChannelOptions<Code extends string = DiagnosticCode> {
|
|
192
235
|
/** Where findings go. Omitted in tests and in hosts that only read `reported`. */
|
|
193
|
-
readonly sink?: DiagnosticSink
|
|
236
|
+
readonly sink?: DiagnosticSink<Code>;
|
|
194
237
|
/** Collapse repeats of the same code+subjects. Default true. */
|
|
195
238
|
readonly dedupe?: boolean;
|
|
196
239
|
}
|
|
197
|
-
declare function createDiagnosticsChannel(options?: DiagnosticsChannelOptions): DiagnosticsChannel
|
|
240
|
+
declare function createDiagnosticsChannel<Code extends string = DiagnosticCode>(options?: DiagnosticsChannelOptions<Code>): DiagnosticsChannel<Code>;
|
|
198
241
|
|
|
199
242
|
/**
|
|
200
243
|
* Accessibility policy (§Accessibility policy, plus the Reduced Motion
|
|
@@ -399,6 +442,26 @@ declare const ACCESSIBILITY_PRECEDENCE: readonly ["reducedMotion", "reducedTrans
|
|
|
399
442
|
*/
|
|
400
443
|
declare function resolveAccessibilityPolicy(system: SystemAccessibilityPreferences, overrides?: AccessibilityOverrides, diagnostics?: DiagnosticsChannel): ResolvedAccessibilityPolicy;
|
|
401
444
|
|
|
445
|
+
/**
|
|
446
|
+
* The refraction ladder, weakest rung first.
|
|
447
|
+
*
|
|
448
|
+
* Two independent things cap refraction: the accessibility policy's ceiling
|
|
449
|
+
* (core's `ResolvedMaterialPolicy.refraction`, a regime — `nominal | reduced |
|
|
450
|
+
* none`) and the group's resolved capability state (X2's `RefractionQuality` —
|
|
451
|
+
* `true | approximate | none`, what the sampling backend can actually deliver).
|
|
452
|
+
* **Renderers honour the lower of the two** (Decision Log #19), which is only a
|
|
453
|
+
* meaningful sentence against an ordering — this one.
|
|
454
|
+
*
|
|
455
|
+
* Written out rather than derived from `RefractionQuality`, because that type's
|
|
456
|
+
* own declaration order is not an ordering.
|
|
457
|
+
*/
|
|
458
|
+
declare const REFRACTION_LADDER: readonly ["none", "approximate", "true"];
|
|
459
|
+
/**
|
|
460
|
+
* X2's capability-derived refraction level (`core/src/state.ts` re-exports this
|
|
461
|
+
* name). Derived from the ladder so the rungs and the type cannot drift apart.
|
|
462
|
+
*/
|
|
463
|
+
type RefractionQuality = (typeof REFRACTION_LADDER)[number];
|
|
464
|
+
|
|
402
465
|
/**
|
|
403
466
|
* X2 — the resolved-state model (§Backdrop & analysis contracts).
|
|
404
467
|
*
|
|
@@ -409,10 +472,10 @@ declare function resolveAccessibilityPolicy(system: SystemAccessibilityPreferenc
|
|
|
409
472
|
*
|
|
410
473
|
* C1 ships the shape; C4 ships the resolver.
|
|
411
474
|
*/
|
|
475
|
+
|
|
412
476
|
type ConfiguredSource = "texture" | "dom";
|
|
413
477
|
type ActiveRenderer = "webgpu" | "css";
|
|
414
478
|
type SamplingBackend = "gpu-texture" | "css-backdrop" | "none";
|
|
415
|
-
type RefractionQuality$1 = "true" | "approximate" | "none";
|
|
416
479
|
type AnalysisQuality = "exact" | "hint" | "none";
|
|
417
480
|
type GroupHealth = "ok" | "demoted";
|
|
418
481
|
declare const DEMOTION_REASONS: readonly ["no-webgpu", "no-backdrop-filter", "tainted-source", "incompatible-texture", "no-texture-supplied", "device-lost", "probe-failed", "governor"];
|
|
@@ -423,7 +486,7 @@ interface GlassGroupState {
|
|
|
423
486
|
/** What is actually drawing. */
|
|
424
487
|
readonly activeRenderer: ActiveRenderer;
|
|
425
488
|
readonly samplingBackend: SamplingBackend;
|
|
426
|
-
readonly refraction: RefractionQuality
|
|
489
|
+
readonly refraction: RefractionQuality;
|
|
427
490
|
readonly analysis: AnalysisQuality;
|
|
428
491
|
readonly health: GroupHealth;
|
|
429
492
|
readonly demotionReason?: DemotionReason;
|
|
@@ -781,6 +844,53 @@ interface FrameInfo {
|
|
|
781
844
|
|
|
782
845
|
declare const MATERIAL_VARIANTS$1: readonly ["regular", "clear"];
|
|
783
846
|
type MaterialVariant$1 = (typeof MATERIAL_VARIANTS$1)[number];
|
|
847
|
+
/**
|
|
848
|
+
* An author's tint seed, sRGB-encoded, 0..1 per channel.
|
|
849
|
+
*
|
|
850
|
+
* Encoded rather than linear because this is the number the author wrote: a CSS
|
|
851
|
+
* colour, parsed. The conversion into the working space belongs to whichever
|
|
852
|
+
* tier is drawing, and core carries no colour maths.
|
|
853
|
+
*/
|
|
854
|
+
type TintColor = readonly [r: number, g: number, b: number];
|
|
855
|
+
/**
|
|
856
|
+
* §Material tint — the author-facing half of Apple's `Glass.tint(_:)`.
|
|
857
|
+
*
|
|
858
|
+
* **A tint is a seed, not a fill.** Apple states the mechanism plainly:
|
|
859
|
+
* "selecting a color generates a range of tones that are **mapped to content
|
|
860
|
+
* brightness underneath** the tinted element… changing its hue, brightness and
|
|
861
|
+
* saturation depending on what's behind without deviating too much from the
|
|
862
|
+
* intended color" (WWDC25 session 219). A flat overlay of the seed is the
|
|
863
|
+
* failure Apple names in the same session — "completely opaque and breaks the
|
|
864
|
+
* visual character of Liquid Glass" — so this value is carried to the renderers
|
|
865
|
+
* as a seed and tone-mapped there, per pixel, against the backdrop the material
|
|
866
|
+
* is already sampling.
|
|
867
|
+
*
|
|
868
|
+
* Two axes, kept apart on purpose, because Apple's own vocabulary overloads the
|
|
869
|
+
* word:
|
|
870
|
+
*
|
|
871
|
+
* - **This is the colour axis.** It says what colour the material's tint layer
|
|
872
|
+
* is. It never changes how much of that layer there is.
|
|
873
|
+
* - The **alpha axis** — how opaque the tint layer is — is the material's
|
|
874
|
+
* calibrated `tintAlpha`, the same quantity reduced transparency lifts. That
|
|
875
|
+
* is where the *user's* system preference lives (iOS 26.1's Clear/Tinted
|
|
876
|
+
* toggle "increases the opacity of Liquid Glass and adds more contrast"; OS
|
|
877
|
+
* 27's slider runs the same axis continuously, "ultra clear to fully
|
|
878
|
+
* tinted"). A future reference migration therefore lands on the occlusion
|
|
879
|
+
* axis and cannot collide with an author's tint.
|
|
880
|
+
*
|
|
881
|
+
* `strength` is the author's own subtlety knob and comes from the seed colour's
|
|
882
|
+
* alpha — `rgba(255, 149, 0, 0.5)` is a half-strength orange, exactly as
|
|
883
|
+
* `Color.orange.opacity(0.5)` is in SwiftUI. It says how far the material's tint
|
|
884
|
+
* colour moves from its neutral (profile) tint toward the tone, and at 0 the
|
|
885
|
+
* material is byte-identical to an untinted one.
|
|
886
|
+
*/
|
|
887
|
+
interface GlassTint {
|
|
888
|
+
readonly color: TintColor;
|
|
889
|
+
/** How far the material's tint moves toward the tone, 0..1. */
|
|
890
|
+
readonly strength: number;
|
|
891
|
+
}
|
|
892
|
+
/** A tint with its channels clamped into range. `strength` defaults to fully tinted. */
|
|
893
|
+
declare function glassTint(color: TintColor, strength?: number): GlassTint;
|
|
784
894
|
/** The scrim laid beneath clear glass so foreground content stays legible. */
|
|
785
895
|
interface DimmingPolicy {
|
|
786
896
|
/** Scrim opacity, 0..1. */
|
|
@@ -794,11 +904,13 @@ interface DimmingPolicy {
|
|
|
794
904
|
* satisfy, not to be correct.
|
|
795
905
|
*/
|
|
796
906
|
declare const DEFAULT_CLEAR_DIMMING: DimmingPolicy;
|
|
797
|
-
/** A group's material defaults. A node inherits `variant` when it declares none. */
|
|
907
|
+
/** A group's material defaults. A node inherits `variant` and `tint` when it declares none. */
|
|
798
908
|
interface MaterialProfile$1 {
|
|
799
909
|
readonly variant: MaterialVariant$1;
|
|
800
910
|
/** Required for any clear surface in the group. */
|
|
801
911
|
readonly dimming?: DimmingPolicy;
|
|
912
|
+
/** Group-wide tint seed. A node overrides it, or clears it with `null`. */
|
|
913
|
+
readonly tint?: GlassTint;
|
|
802
914
|
}
|
|
803
915
|
interface ResolvedMaterial {
|
|
804
916
|
readonly variant: MaterialVariant$1;
|
|
@@ -806,15 +918,45 @@ interface ResolvedMaterial {
|
|
|
806
918
|
readonly adaptation: "adaptive" | "constrained";
|
|
807
919
|
/** Present exactly when `variant` is `"clear"`. */
|
|
808
920
|
readonly dimming?: DimmingPolicy;
|
|
921
|
+
/** Absent when the surface is untinted, or when its tint has no strength. */
|
|
922
|
+
readonly tint?: GlassTint;
|
|
809
923
|
}
|
|
810
924
|
interface MaterialRequest {
|
|
811
925
|
readonly variant: MaterialVariant$1;
|
|
812
926
|
readonly dimming?: DimmingPolicy;
|
|
927
|
+
/** The tint this surface resolved to — its own, or the group's. */
|
|
928
|
+
readonly tint?: GlassTint | null;
|
|
813
929
|
/** Named in diagnostics; also the dedupe subject. */
|
|
814
930
|
readonly nodeId?: string;
|
|
815
931
|
readonly diagnostics?: DiagnosticsChannel;
|
|
816
932
|
}
|
|
817
933
|
declare function resolveMaterial(request: MaterialRequest): ResolvedMaterial;
|
|
934
|
+
interface TintMixingCheck {
|
|
935
|
+
readonly groupId: string;
|
|
936
|
+
readonly members: readonly {
|
|
937
|
+
readonly nodeId: string;
|
|
938
|
+
readonly tint?: GlassTint;
|
|
939
|
+
}[];
|
|
940
|
+
readonly diagnostics?: DiagnosticsChannel;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Report a group whose members ask for **different** tint seeds.
|
|
944
|
+
*
|
|
945
|
+
* A group is one sampling region and one optics pass, so the GPU tier carries
|
|
946
|
+
* one seed per group and a per-pixel strength — which is exactly enough for the
|
|
947
|
+
* composition Apple's guidance describes ("apply color to the background rather
|
|
948
|
+
* than to symbols… refrain from adding color to the background of multiple
|
|
949
|
+
* controls"): one emphasised control inside a toolbar of plain ones. Two
|
|
950
|
+
* different hues in one group is outside that, and the two tiers would then
|
|
951
|
+
* disagree — the CSS tier styles each host element on its own and can honour
|
|
952
|
+
* both. So it warns and changes nothing, on the same reasoning as
|
|
953
|
+
* `checkVariantMixing`: coercing one of the two would silently discard an
|
|
954
|
+
* author's intent.
|
|
955
|
+
*
|
|
956
|
+
* Untinted members are not a mix. They are the ordinary case the mechanism is
|
|
957
|
+
* for, and their strength is simply zero.
|
|
958
|
+
*/
|
|
959
|
+
declare function checkTintMixing(check: TintMixingCheck): boolean;
|
|
818
960
|
interface VariantMixingCheck {
|
|
819
961
|
readonly groupId: string;
|
|
820
962
|
readonly members: readonly {
|
|
@@ -867,6 +1009,29 @@ declare function compareZSlot(a: ZSlot, b: ZSlot): number;
|
|
|
867
1009
|
declare function unionRect(a: Rect, b: Rect): Rect;
|
|
868
1010
|
/** Grow a rect outwards on every side — how a group's proxy gets its padding. */
|
|
869
1011
|
declare function inflateRect(rect: Rect, by: number): Rect;
|
|
1012
|
+
/**
|
|
1013
|
+
* The part of `rect` that survives every clip in the chain.
|
|
1014
|
+
*
|
|
1015
|
+
* A surface's border box is measured unclipped — `getBoundingClientRect` reports
|
|
1016
|
+
* the box wherever it is, whether or not an `overflow: scroll` ancestor is
|
|
1017
|
+
* actually showing it — so the box alone says nothing about what is visible. The
|
|
1018
|
+
* clip chain, measured alongside it, is what turns the box into the region the
|
|
1019
|
+
* surface can paint in (Decision Log #41(k)).
|
|
1020
|
+
*
|
|
1021
|
+
* A fully scrolled-out surface intersects to zero extent, and every consumer in
|
|
1022
|
+
* here already treats a zero-extent rect as "contributes nothing": `rectsOverlap`
|
|
1023
|
+
* refuses it, and the proxy geometry skips it as unmeasured. That is deliberate
|
|
1024
|
+
* — it means "scrolled out of view" needs no special case anywhere downstream.
|
|
1025
|
+
*
|
|
1026
|
+
* Rects only, and the approximation is stated rather than implied: a rounded
|
|
1027
|
+
* clipping ancestor is carried as its bounding box, so a surface tucked into a
|
|
1028
|
+
* rounded scroller's corner is treated as slightly more visible than it is. The
|
|
1029
|
+
* error is bounded by the ancestor's corner radius and always errs towards
|
|
1030
|
+
* reporting *more* surface, which is the safe direction for every consumer here
|
|
1031
|
+
* — an overlap check that over-reports warns about something real-ish, one that
|
|
1032
|
+
* under-reports misses a genuine double-filter.
|
|
1033
|
+
*/
|
|
1034
|
+
declare function clipRect(rect: Rect, clip: readonly Rect[] | undefined): Rect;
|
|
870
1035
|
/**
|
|
871
1036
|
* Positive-area intersection. Touching edges are not an overlap — adjacent
|
|
872
1037
|
* surfaces in a toolbar are the common case and are legal. A degenerate rect
|
|
@@ -1008,6 +1173,28 @@ interface GlassGroupRecord {
|
|
|
1008
1173
|
readonly state?: GlassGroupState;
|
|
1009
1174
|
/** Per-group governor override; falls back to the scene-wide pressure. */
|
|
1010
1175
|
readonly governor?: GovernorPressure;
|
|
1176
|
+
/**
|
|
1177
|
+
* Per-group platform probe override; falls back to the scene-wide probe.
|
|
1178
|
+
*
|
|
1179
|
+
* Most of `PlatformProbe` genuinely is scene-wide — there is one device per
|
|
1180
|
+
* root, and whether the engine has `backdrop-filter` is a fact about the
|
|
1181
|
+
* engine. `backdropProxyConformance` is the exception, and S1 measured why:
|
|
1182
|
+
* the backdrop-root audit is per group, "not per document, because different
|
|
1183
|
+
* groups can sit under different ancestors". A group whose proxy chain is
|
|
1184
|
+
* re-rooted must demote alone.
|
|
1185
|
+
*/
|
|
1186
|
+
readonly platform?: PlatformProbe;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* X8 rider 2: this surface is a level set of another surface's field, inset by a
|
|
1190
|
+
* fixed distance — a segmented control's indicator inside its track, drawn as
|
|
1191
|
+
* one field rather than two shapes that happen to nest.
|
|
1192
|
+
*/
|
|
1193
|
+
interface ConcentricParent {
|
|
1194
|
+
/** The parent surface. Must be registered, and must share this node's group. */
|
|
1195
|
+
readonly nodeId: string;
|
|
1196
|
+
/** CSS px inward from the parent's contour. */
|
|
1197
|
+
readonly inset: number;
|
|
1011
1198
|
}
|
|
1012
1199
|
interface GlassNodeDescriptor {
|
|
1013
1200
|
readonly id: string;
|
|
@@ -1015,8 +1202,33 @@ interface GlassNodeDescriptor {
|
|
|
1015
1202
|
readonly shapeFamily: ShapeFamily;
|
|
1016
1203
|
readonly shape: ShapeChannels;
|
|
1017
1204
|
readonly zSlot: ZSlot;
|
|
1205
|
+
/**
|
|
1206
|
+
* Which of geometry's two corner references this shape is fit against
|
|
1207
|
+
* (Decision Log #22(a) — two separate fits, not two points on one axis).
|
|
1208
|
+
* Defaults to `"apple-continuous"` at the renderer.
|
|
1209
|
+
*
|
|
1210
|
+
* A scene-model field since Decision Log #23(c). In v1 it was a render input
|
|
1211
|
+
* the browser layer never set, so a shape authored on the Figma smoothing axis
|
|
1212
|
+
* was silently resolved against the Apple fit, and a binding that wanted to
|
|
1213
|
+
* refuse a cross-reference morph had to mirror geometry's private mapping to
|
|
1214
|
+
* do it. The reference travels with the shape now.
|
|
1215
|
+
*/
|
|
1216
|
+
readonly reference?: CornerReference;
|
|
1217
|
+
/**
|
|
1218
|
+
* X8 rider 2's parent edge, likewise a scene-model field since #23(c).
|
|
1219
|
+
*
|
|
1220
|
+
* The link is validated here rather than at draw time: an unknown parent, a
|
|
1221
|
+
* parent in another group and a cycle are all refusals at registration, where
|
|
1222
|
+
* the caller that made the mistake is still on the stack.
|
|
1223
|
+
*/
|
|
1224
|
+
readonly concentricOf?: ConcentricParent;
|
|
1018
1225
|
/** Inherits the group's material profile when absent. */
|
|
1019
1226
|
readonly variant?: MaterialVariant$1;
|
|
1227
|
+
/**
|
|
1228
|
+
* Overrides the group's tint seed. `null` clears an inherited one, the way
|
|
1229
|
+
* `Glass.tint(nil)` does; absent inherits.
|
|
1230
|
+
*/
|
|
1231
|
+
readonly tint?: GlassTint | null;
|
|
1020
1232
|
readonly interaction?: InteractionState;
|
|
1021
1233
|
/** Overrides the group's adaptation for this surface. */
|
|
1022
1234
|
readonly foreground?: ForegroundAdaptation;
|
|
@@ -1074,7 +1286,10 @@ interface PlaneOverlap {
|
|
|
1074
1286
|
readonly plane: GlassPlane;
|
|
1075
1287
|
readonly nodeIds: readonly [string, string];
|
|
1076
1288
|
}
|
|
1077
|
-
/**
|
|
1289
|
+
/**
|
|
1290
|
+
* Two groups close enough in one plane that one group's padded proxy would
|
|
1291
|
+
* sample the pixels the other one paints (X1).
|
|
1292
|
+
*/
|
|
1078
1293
|
interface ProxyOverlap {
|
|
1079
1294
|
readonly plane: GlassPlane;
|
|
1080
1295
|
readonly groupIds: readonly [string, string];
|
|
@@ -1121,7 +1336,25 @@ interface GlassScene {
|
|
|
1121
1336
|
nodesOfGroup(groupId: string): readonly GlassNodeRecord[];
|
|
1122
1337
|
/** Measured viewport geometry, from the read phase. */
|
|
1123
1338
|
setNodeBounds(id: string, bounds: Rect, clip?: readonly Rect[]): void;
|
|
1124
|
-
|
|
1339
|
+
/**
|
|
1340
|
+
* Scene-wide by default; per group when `groupId` is given.
|
|
1341
|
+
*
|
|
1342
|
+
* The per-group form exists for `backdropProxyConformance` (Decision Log
|
|
1343
|
+
* #21(a), #23(c)). S1's backdrop-root audit is per group — different groups
|
|
1344
|
+
* sit under different ancestors — so a scene-wide-only probe forced the
|
|
1345
|
+
* browser layer either to demote every group when one failed, or to bypass
|
|
1346
|
+
* `resolve()` and call the pure resolver itself with the verdict folded in.
|
|
1347
|
+
* It chose the second, honestly and in the open, and this setter is what
|
|
1348
|
+
* retires it: with the verdict in the scene, `ResolvedGroup.state` and the
|
|
1349
|
+
* host's per-group answer are the same answer again.
|
|
1350
|
+
*
|
|
1351
|
+
* A per-group probe REPLACES the scene-wide one for that group rather than
|
|
1352
|
+
* merging with it, exactly as `setGovernorPressure` does. Merging would be a
|
|
1353
|
+
* second precedence rule sitting beside `REASON_PRECEDENCE`, and the caller
|
|
1354
|
+
* that knows the group's verdict is the same caller that holds the scene-wide
|
|
1355
|
+
* probe it was derived from.
|
|
1356
|
+
*/
|
|
1357
|
+
setPlatformProbe(probe: PlatformProbe, groupId?: string): void;
|
|
1125
1358
|
setSourceProbe(sourceId: string, probe: SourceProbe): void;
|
|
1126
1359
|
/** Scene-wide by default; per group when `groupId` is given. */
|
|
1127
1360
|
setGovernorPressure(pressure: GovernorPressure, groupId?: string): void;
|
|
@@ -1155,8 +1388,8 @@ interface GlassScene {
|
|
|
1155
1388
|
checkSamePlaneOverlap(): readonly PlaneOverlap[];
|
|
1156
1389
|
/**
|
|
1157
1390
|
* The cross-group half of X1's proxy geometry. `mergeDistance` only unions
|
|
1158
|
-
* members *within* a group, so
|
|
1159
|
-
*
|
|
1391
|
+
* members *within* a group, so a neighbouring group's proxy can still sample
|
|
1392
|
+
* the pixels this one paints — which S1 measured double-filtering.
|
|
1160
1393
|
*/
|
|
1161
1394
|
checkGroupProxyOverlap(): readonly ProxyOverlap[];
|
|
1162
1395
|
}
|
|
@@ -1337,15 +1570,15 @@ type Rgb = readonly [r: number, g: number, b: number];
|
|
|
1337
1570
|
* **The lower of the two wins**, and this module folds them into one scalar before
|
|
1338
1571
|
* anything reaches a uniform, so the shader has no way to honour the wrong one.
|
|
1339
1572
|
*
|
|
1340
|
-
* The ordering
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1573
|
+
* The ordering is `@vitrea/policy`'s, and so is the fold. It used to be restated
|
|
1574
|
+
* here — this package sits *below* core in the dependency graph and platform-web
|
|
1575
|
+
* sits above it, so for most of v1 there was no module both tiers could see and
|
|
1576
|
+
* the CSS tier carried a second copy. Decision Log #23(d) closed that seam by
|
|
1577
|
+
* putting the ladder in a pure leaf underneath everything, which the renderer can
|
|
1578
|
+
* depend on directly (alongside `@vitrea/geometry`) with no cycle to close. The
|
|
1579
|
+
* two copies can no longer disagree because there is only one.
|
|
1344
1580
|
*/
|
|
1345
1581
|
|
|
1346
|
-
/** X2's `RefractionQuality`, restated. Weakest first — the declaration order IS the ladder. */
|
|
1347
|
-
declare const REFRACTION_LADDER: readonly ["none", "approximate", "true"];
|
|
1348
|
-
type RefractionQuality = (typeof REFRACTION_LADDER)[number];
|
|
1349
1582
|
/**
|
|
1350
1583
|
* The slice of core's `ResolvedAccessibilityPolicy["material"]` the renderer
|
|
1351
1584
|
* reads. core's type is assignable to this; a test pins that.
|
|
@@ -1385,6 +1618,96 @@ interface MaterialRim {
|
|
|
1385
1618
|
readonly rimWidth: number;
|
|
1386
1619
|
readonly rimAlpha: number;
|
|
1387
1620
|
}
|
|
1621
|
+
/**
|
|
1622
|
+
* The outer shadow (W8) — the material's own occlusion of the backdrop *outside*
|
|
1623
|
+
* its contour, and the largest single facet the project has measured.
|
|
1624
|
+
*
|
|
1625
|
+
* Not the same quantity as `MaterialOptics.shadowDepth`/`shadowAlpha`, which are
|
|
1626
|
+
* the *inner* shadow: that one darkens the material's own body near its contour,
|
|
1627
|
+
* this one darkens what is behind and beside the surface. Profile-level rather
|
|
1628
|
+
* than per-variant, because the bed measures it per profile and never varied the
|
|
1629
|
+
* variant.
|
|
1630
|
+
*
|
|
1631
|
+
* ## The mechanism, as measured
|
|
1632
|
+
*
|
|
1633
|
+
* The reference's shadow is the component's OWN rounded silhouette, outset by
|
|
1634
|
+
* `spreadPx`, translated down by `offsetPx`, blurred by a Gaussian of standard
|
|
1635
|
+
* deviation `sigmaPx`, and applied MULTIPLICATIVELY: the backdrop keeps
|
|
1636
|
+
* `1 − occlusion·falloff` of its own light. Fitted in two dimensions against the
|
|
1637
|
+
* active bed, that model reproduces the reference to an RMS of 0.0021 in
|
|
1638
|
+
* occlusion over 142,550 pixels on the finest cell, and the same three lengths
|
|
1639
|
+
* describe every profile, backdrop, span and scale in the bed.
|
|
1640
|
+
*
|
|
1641
|
+
* **Multiplicative, and not additively.** Mirrored pixel pairs either side of a
|
|
1642
|
+
* capsule over the `photo` backdrop see the same shadow over different backdrop
|
|
1643
|
+
* luminances: the darkening's ratio tracks the backdrop's ratio to 4.5% while a
|
|
1644
|
+
* constant-subtraction model misses by 79% of the signal. So the shadow is
|
|
1645
|
+
* analytically INVISIBLE over black — `dark-solid` cells are byte-identical to
|
|
1646
|
+
* their background — and that property is what both tiers reproduce exactly,
|
|
1647
|
+
* because a fully transparent black composited over anything leaves it alone and
|
|
1648
|
+
* black times anything is black.
|
|
1649
|
+
*
|
|
1650
|
+
* ## Lengths, in points
|
|
1651
|
+
*
|
|
1652
|
+
* Every length below is in CSS px and the 2× bed proves it: `sigmaPx` measures
|
|
1653
|
+
* 15.5 at 1× and 31.0 at 2× device px, `offsetPx` 7.9 and 15.8. A shadow
|
|
1654
|
+
* specified in points is what doubles that way.
|
|
1655
|
+
*
|
|
1656
|
+
* They are also SPAN-INVARIANT, which is a positive measurement rather than an
|
|
1657
|
+
* absence: across spans of 32, 44, 96 and 160 px the fitted σ stays within
|
|
1658
|
+
* 15.4…15.9 and the offset within 6.9…8.1. The size law reaches the amplitude
|
|
1659
|
+
* (`sizeGain`) and nothing else.
|
|
1660
|
+
*/
|
|
1661
|
+
interface MaterialOuterShadow {
|
|
1662
|
+
/** Downward translation of the shadow's silhouette, CSS px. */
|
|
1663
|
+
readonly offsetPx: number;
|
|
1664
|
+
/** Gaussian σ the silhouette is blurred by, CSS px. A `box-shadow` blur is 2σ. */
|
|
1665
|
+
readonly sigmaPx: number;
|
|
1666
|
+
/** Outward spread of the silhouette before the blur, CSS px. */
|
|
1667
|
+
readonly spreadPx: number;
|
|
1668
|
+
/**
|
|
1669
|
+
* Peak occlusion: the fraction of the backdrop's own LINEAR light removed deep
|
|
1670
|
+
* inside the shadow. Zero stands the whole facet down, pad and all.
|
|
1671
|
+
*/
|
|
1672
|
+
readonly occlusion: number;
|
|
1673
|
+
/**
|
|
1674
|
+
* What reduced transparency does to `occlusion` — MEASURED, not assumed, which
|
|
1675
|
+
* is what the charter asked for before the fold was written.
|
|
1676
|
+
*
|
|
1677
|
+
* The reference's shadow under `reduce transparency` is the same shadow at
|
|
1678
|
+
* 0.566 of the amplitude: 0.1830/0.3259, 0.1884/0.3309 and 0.1882/0.3314 on the
|
|
1679
|
+
* three structured backdrops at a 44 px span, with σ, offset and spread
|
|
1680
|
+
* unmoved. It does not vanish and it does not intensify.
|
|
1681
|
+
*
|
|
1682
|
+
* The `increased contrast` reference reproduces the reduced-transparency
|
|
1683
|
+
* amplitude to four decimals (0.1830, 0.1884, 0.1882 — the same numbers), which
|
|
1684
|
+
* is Decision Log 8's finding again: macOS force-couples the two toggles, so the
|
|
1685
|
+
* contrast reference IS the reduced-transparency state and the bed cannot
|
|
1686
|
+
* separate them. The fold therefore keys on `frost`, the axis reduced
|
|
1687
|
+
* transparency alone sets, rather than on the contrast axes it would be
|
|
1688
|
+
* indistinguishable on here.
|
|
1689
|
+
*/
|
|
1690
|
+
readonly reducedTransparencyOcclusion: number;
|
|
1691
|
+
/**
|
|
1692
|
+
* The size law's grip on the amplitude: the fraction of the REMAINING
|
|
1693
|
+
* transparency a full-thickness surface's shadow closes, on
|
|
1694
|
+
* `sizeOcclusionGain`'s relative form.
|
|
1695
|
+
*
|
|
1696
|
+
* Ships at 0 — the identity — and the reason is a measurement rather than an
|
|
1697
|
+
* absence of one. Fitted per scene at a frozen geometry, the amplitude's span
|
|
1698
|
+
* dependence points in OPPOSITE directions in the two colour schemes: light
|
|
1699
|
+
* standard falls from 0.326 to 0.196 between a 44 px and a 96 px span over
|
|
1700
|
+
* `photo` (and 0.331 → 0.285 over `checkerboard`, 0.331 → 0.245 over
|
|
1701
|
+
* `hc-text`), while dark standard RISES from 0.060 to 0.177 to 0.274 across 44,
|
|
1702
|
+
* 96 and 160 px. Under reduced transparency it is flat (0.183, 0.192, 0.165).
|
|
1703
|
+
* One monotone gain on one thickness curve cannot be all three, and any
|
|
1704
|
+
* non-zero value fitted to one scheme is wrong in the other — the same shape of
|
|
1705
|
+
* finding Decision Log 13 recorded for W7's curve ("surface size is its own
|
|
1706
|
+
* axis"). The seam ships so the cascade can fit it if a two-axis rework lands;
|
|
1707
|
+
* the value stays at the identity until something can identify it.
|
|
1708
|
+
*/
|
|
1709
|
+
readonly sizeGain: number;
|
|
1710
|
+
}
|
|
1388
1711
|
/**
|
|
1389
1712
|
* Every number the material runs on, in one place.
|
|
1390
1713
|
*
|
|
@@ -1416,21 +1739,95 @@ interface MaterialProfile {
|
|
|
1416
1739
|
*/
|
|
1417
1740
|
readonly refractionScale: Readonly<Record<RefractionQuality, number>>;
|
|
1418
1741
|
/**
|
|
1419
|
-
* The size
|
|
1742
|
+
* **The size law's one curve** — the span band over which the material stops
|
|
1743
|
+
* reading as a thin sheet and starts reading as a thick slab (W2).
|
|
1420
1744
|
*
|
|
1421
|
-
*
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1425
|
-
*
|
|
1745
|
+
* Apple states one mechanism and lists its consequences: as glass "morphs to
|
|
1746
|
+
* larger sizes… its material characteristics change to simulate a thicker, more
|
|
1747
|
+
* substantial material. It casts deeper, richer shadows, has more pronounced
|
|
1748
|
+
* lensing and refraction effects, and a softer scattering of light" (S219). One
|
|
1749
|
+
* mechanism means one curve: `sizeThickness(span)` is a smoothstep from
|
|
1750
|
+
* `sizeSpanMin` to `sizeSpanMax`, and **every** thickness-derived facet is a
|
|
1751
|
+
* gain on it — the lens (`lensSizeGainMax`), the scattering
|
|
1752
|
+
* (`sizeScatterGainMax`), the occlusion (`sizeOcclusionGain`) and the inner
|
|
1753
|
+
* shadow (`sizeShadowGainMax`). Two curves would be two mechanisms, and the
|
|
1754
|
+
* reference only has one.
|
|
1426
1755
|
*
|
|
1427
1756
|
* A smoothstep rather than a straight ratio, so two surfaces of nearly the same
|
|
1428
|
-
* size never read as differently thick, and so
|
|
1429
|
-
* growing without bound on a full-width platter.
|
|
1757
|
+
* size never read as differently thick, and so every gain saturates instead of
|
|
1758
|
+
* growing without bound on a full-width platter. Below `sizeSpanMin` the whole
|
|
1759
|
+
* law is **exactly inert**: a small control renders as it did before the law
|
|
1760
|
+
* existed, which is what makes the law additive rather than a global retune.
|
|
1761
|
+
*
|
|
1762
|
+
* MEASURED (W2, on the settled bed): the band is where the reference's own
|
|
1763
|
+
* size-dependence happens. Over a fixed checkerboard backdrop the light-standard
|
|
1764
|
+
* reference passes 0.244 of the backdrop's contrast at a 32 px span, 0.230 at
|
|
1765
|
+
* 44 px and 0.144 at 96 px, and its backdrop correlation falls 0.634 → 0.606 →
|
|
1766
|
+
* 0.475 across the same three — so the movement is essentially complete by 96 px
|
|
1767
|
+
* and has barely started at 32. See the claims doc's size-law section.
|
|
1768
|
+
*/
|
|
1769
|
+
readonly sizeSpanMin: number;
|
|
1770
|
+
readonly sizeSpanMax: number;
|
|
1771
|
+
/**
|
|
1772
|
+
* The lens's gain on the size curve — "more pronounced lensing and refraction".
|
|
1773
|
+
*
|
|
1774
|
+
* `lensDepthPx` is `thickness × lensSizeGain(span)`, clamped to the shorter
|
|
1775
|
+
* *half* extent. The clamp is what keeps a small control from being all lens: a
|
|
1776
|
+
* 24 px-tall button cannot bend more than 12 px of backdrop however thick it is
|
|
1777
|
+
* authored.
|
|
1430
1778
|
*/
|
|
1431
|
-
readonly lensSpanMin: number;
|
|
1432
|
-
readonly lensSpanMax: number;
|
|
1433
1779
|
readonly lensSizeGainMax: number;
|
|
1780
|
+
/**
|
|
1781
|
+
* The scattering gain — "a softer scattering of light". How many times wider
|
|
1782
|
+
* the material's body blur runs at full size.
|
|
1783
|
+
*
|
|
1784
|
+
* **The facet the settled bed identifies most directly.** Two backdrops
|
|
1785
|
+
* disagree in exactly the way a widening kernel predicts and an opacity change
|
|
1786
|
+
* does not. Over the checkerboard — all of whose structure sits at one 16 px
|
|
1787
|
+
* period, and whose surroundings carry the same mean as its interior — the
|
|
1788
|
+
* reference's retained contrast falls 41% from a 32 px span to a 96 px one while
|
|
1789
|
+
* its interior *level* stays put (0.607 → 0.641). Over the synthetic photo —
|
|
1790
|
+
* broadband, and with surroundings whose mean differs from the mask's — the
|
|
1791
|
+
* retained contrast barely moves between 44 px and 96 px (0.546 → 0.544) while
|
|
1792
|
+
* the level converges toward the neighbourhood (0.585 → 0.628). A larger alpha
|
|
1793
|
+
* would have moved both backdrops' contrast together and pulled both levels
|
|
1794
|
+
* toward the tint; a wider kernel moves exactly what moved.
|
|
1795
|
+
*
|
|
1796
|
+
* Both tiers carry it, from one function (`sizeScatterSigma`): the CSS tier
|
|
1797
|
+
* multiplies its `blur()` σ, and the GPU tier lerps its body sample toward the
|
|
1798
|
+
* chain level whose blur is that σ.
|
|
1799
|
+
*/
|
|
1800
|
+
readonly sizeScatterGainMax: number;
|
|
1801
|
+
/**
|
|
1802
|
+
* The occlusion gain — "a larger size is more opaque. A smaller size is
|
|
1803
|
+
* clearer" (S284). The fraction of the *remaining* transparency the size law
|
|
1804
|
+
* closes at full size.
|
|
1805
|
+
*
|
|
1806
|
+
* Relative rather than absolute, for `increasedOcclusionLift`'s reason: a floor
|
|
1807
|
+
* dies silently the moment nominal passes it, and a fraction of the headroom
|
|
1808
|
+
* cannot. It also composes correctly with the accessibility lift — under reduced
|
|
1809
|
+
* transparency nominal is already near 1, so the size law has almost no headroom
|
|
1810
|
+
* left to close, which is exactly what the reference does there (its transmission
|
|
1811
|
+
* reads 0.011 at a 44 px span and 0.014 at 96 px — no size dependence, because
|
|
1812
|
+
* there is none left to have).
|
|
1813
|
+
*/
|
|
1814
|
+
readonly sizeOcclusionGain: number;
|
|
1815
|
+
/**
|
|
1816
|
+
* The inner shadow's gain — "casts deeper, richer shadows". A multiplier on
|
|
1817
|
+
* `shadowDepth` at full size.
|
|
1818
|
+
*
|
|
1819
|
+
* **Coupled by construction, not fitted, and the difference is stated rather
|
|
1820
|
+
* than hidden.** The fixtures cannot identify it: the reference's peak darkening
|
|
1821
|
+
* outside its contour measures 0.0000–0.0001 on almost every calibration scene
|
|
1822
|
+
* and vitrea's measures the same order (C9a, `shadowFalloff`), so there is no
|
|
1823
|
+
* measured gap for a sweep to close, and what this renderer's `shadowDepth`
|
|
1824
|
+
* scales is an *inner* shadow whose contribution to the interior level is
|
|
1825
|
+
* degenerate with the tint's — two constants, one observable. So the direction
|
|
1826
|
+
* comes from Apple's sentence and the magnitude is held to what the objective is
|
|
1827
|
+
* flat over, with that flatness recorded. GPU tier only: the CSS tier's shadow is
|
|
1828
|
+
* an outer `box-shadow` the reference does not cast at all (Decision Log #32(c)).
|
|
1829
|
+
*/
|
|
1830
|
+
readonly sizeShadowGainMax: number;
|
|
1434
1831
|
/** Chain LOD per CSS px of lens depth, and how much sharper the rim samples. */
|
|
1435
1832
|
readonly lensBodyLodPerPx: number;
|
|
1436
1833
|
readonly lensRimLodBias: number;
|
|
@@ -1455,12 +1852,74 @@ interface MaterialProfile {
|
|
|
1455
1852
|
* (0.62 − 0.28) / (1 − 0.28) = 0.4722, which reproduces the old floor exactly at
|
|
1456
1853
|
* the old nominal. At today's nominal it reads 0.62 → 0.799.
|
|
1457
1854
|
*
|
|
1458
|
-
* Mirrored by `@vitrea
|
|
1855
|
+
* Mirrored by `@vitreajs/vitrea-web`'s `INCREASED_OCCLUSION_LIFT`, and pinned in
|
|
1459
1856
|
* both directions by `packages/calibration/test/tier-coherence.test.ts`.
|
|
1460
1857
|
*/
|
|
1461
1858
|
readonly increasedOcclusionLift: number;
|
|
1462
1859
|
readonly strongBorderRim: MaterialRim;
|
|
1463
1860
|
readonly reducedTintAdaptation: number;
|
|
1861
|
+
/**
|
|
1862
|
+
* The author tint's tone map — Apple's "range of tones **mapped to content
|
|
1863
|
+
* brightness underneath**" (S219), as four numbers.
|
|
1864
|
+
*
|
|
1865
|
+
* The seed the author gives is not the colour the material paints. It is the
|
|
1866
|
+
* middle of a range: over a dark backdrop the material shows a shade of the
|
|
1867
|
+
* seed (`tintToneFloor`, a multiple of it in linear light, so hue and
|
|
1868
|
+
* chromaticity survive); over a bright one it shows the seed washed toward
|
|
1869
|
+
* white (`tintToneCeilMix`), which is what Apple's "changing its hue,
|
|
1870
|
+
* brightness and saturation… without deviating too much from the intended
|
|
1871
|
+
* color" describes. `tintToneLow`/`tintToneHigh` are the backdrop luminances
|
|
1872
|
+
* the two ends are reached at, crossed with a smoothstep for the same reason
|
|
1873
|
+
* `lensSpanMin`/`lensSpanMax` are.
|
|
1874
|
+
*
|
|
1875
|
+
* **Advisory and calibration-delegated**, like every other number in this
|
|
1876
|
+
* profile: they are chosen so a tinted surface reads as coloured glass rather
|
|
1877
|
+
* than as paint, and the tinted-capture extension fits them. Nothing here is
|
|
1878
|
+
* measured yet, and no claim rests on these values.
|
|
1879
|
+
*/
|
|
1880
|
+
readonly tintToneFloor: number;
|
|
1881
|
+
readonly tintToneCeilMix: number;
|
|
1882
|
+
readonly tintToneLow: number;
|
|
1883
|
+
readonly tintToneHigh: number;
|
|
1884
|
+
/**
|
|
1885
|
+
* **Backdrop tone adaptation (W7)** — the axis Apple's material has and this
|
|
1886
|
+
* one did not: over a dark enough backdrop the material stops being a lighter
|
|
1887
|
+
* thing in front of it and takes the backdrop's own tone.
|
|
1888
|
+
*
|
|
1889
|
+
* The mechanism is one mix, and it is deliberately the *tint colour* rather
|
|
1890
|
+
* than the tint alpha: `backdropToneMax` at full strength makes the tint equal
|
|
1891
|
+
* the sampled backdrop, so `mix(backdrop, tint, tintAlpha)` collapses to the
|
|
1892
|
+
* backdrop exactly and the surface is left with its rim, its inner shadow and
|
|
1893
|
+
* its lensing and nothing else. That is what the settled reference does —
|
|
1894
|
+
* `dark-solid__capsule-button__rest` is byte-identical to its own background
|
|
1895
|
+
* in every standard profile, at both scales, in both colour schemes.
|
|
1896
|
+
*
|
|
1897
|
+
* `backdropToneLow`/`backdropToneHigh` are the backdrop luminances (linear)
|
|
1898
|
+
* the two ends are reached at, crossed with a smoothstep for the same reason
|
|
1899
|
+
* `tintToneLow`/`High` are.
|
|
1900
|
+
*
|
|
1901
|
+
* `backdropToneSizeBias` is the size gate, and it is not decoration: the same
|
|
1902
|
+
* backdrop moves a small surface and a large one by very different amounts.
|
|
1903
|
+
* Over `dark-solid` the reference's 44 px capsule adapts completely while its
|
|
1904
|
+
* 96 px rrect keeps three quarters of its own appearance, measured on both
|
|
1905
|
+
* scales independently and agreeing to three decimals. The bias enters the
|
|
1906
|
+
* curve's *argument* rather than its amplitude — a thicker surface behaves as
|
|
1907
|
+
* though its backdrop were brighter, which is what more material between the
|
|
1908
|
+
* viewer and the backdrop means — because an amplitude gate cannot reproduce
|
|
1909
|
+
* the second dark backdrop (`impulse`) and this does.
|
|
1910
|
+
*
|
|
1911
|
+
* The axis is WITHIN a colour scheme. The scheme picks the neutral; this moves
|
|
1912
|
+
* the material away from that neutral toward what is actually behind it. So the
|
|
1913
|
+
* dark profile runs the same law with the same constants and does not
|
|
1914
|
+
* double-adapt: over `dark-solid` its capsule collapses onto the backdrop too,
|
|
1915
|
+
* and the light and dark references become the same pixels there.
|
|
1916
|
+
*/
|
|
1917
|
+
readonly backdropToneMax: number;
|
|
1918
|
+
readonly backdropToneLow: number;
|
|
1919
|
+
readonly backdropToneHigh: number;
|
|
1920
|
+
readonly backdropToneSizeBias: number;
|
|
1921
|
+
/** The outer shadow (W8) — see `MaterialOuterShadow`. */
|
|
1922
|
+
readonly outerShadow: MaterialOuterShadow;
|
|
1464
1923
|
/**
|
|
1465
1924
|
* Advisory light direction, in viewport coordinates with y pointing down: a
|
|
1466
1925
|
* little left of straight overhead, which is where Apple's material reads its
|
|
@@ -1487,15 +1946,27 @@ interface MaterialProfilePatch {
|
|
|
1487
1946
|
readonly adaptiveLuminanceLow?: number;
|
|
1488
1947
|
readonly adaptiveLuminanceHigh?: number;
|
|
1489
1948
|
readonly refractionScale?: Readonly<Partial<Record<RefractionQuality, number>>>;
|
|
1490
|
-
readonly
|
|
1491
|
-
readonly
|
|
1949
|
+
readonly sizeSpanMin?: number;
|
|
1950
|
+
readonly sizeSpanMax?: number;
|
|
1492
1951
|
readonly lensSizeGainMax?: number;
|
|
1952
|
+
readonly sizeScatterGainMax?: number;
|
|
1953
|
+
readonly sizeOcclusionGain?: number;
|
|
1954
|
+
readonly sizeShadowGainMax?: number;
|
|
1493
1955
|
readonly lensBodyLodPerPx?: number;
|
|
1494
1956
|
readonly lensRimLodBias?: number;
|
|
1495
1957
|
readonly reducedTransparencyFrost?: number;
|
|
1496
1958
|
readonly increasedOcclusionLift?: number;
|
|
1497
1959
|
readonly strongBorderRim?: Readonly<Partial<MaterialRim>>;
|
|
1498
1960
|
readonly reducedTintAdaptation?: number;
|
|
1961
|
+
readonly tintToneFloor?: number;
|
|
1962
|
+
readonly tintToneCeilMix?: number;
|
|
1963
|
+
readonly tintToneLow?: number;
|
|
1964
|
+
readonly tintToneHigh?: number;
|
|
1965
|
+
readonly backdropToneMax?: number;
|
|
1966
|
+
readonly backdropToneLow?: number;
|
|
1967
|
+
readonly backdropToneHigh?: number;
|
|
1968
|
+
readonly backdropToneSizeBias?: number;
|
|
1969
|
+
readonly outerShadow?: Readonly<Partial<MaterialOuterShadow>>;
|
|
1499
1970
|
readonly lightDirection?: readonly [number, number];
|
|
1500
1971
|
readonly sweepBandRadians?: number;
|
|
1501
1972
|
readonly glowRadiusCss?: number;
|
|
@@ -1893,6 +2364,11 @@ interface SurfaceChannels {
|
|
|
1893
2364
|
/** Press point in viewport CSS px. Defaults to the surface's centre. */
|
|
1894
2365
|
readonly pressPoint?: readonly [number, number];
|
|
1895
2366
|
}
|
|
2367
|
+
/** An author tint as this package takes it: a seed in linear light, and a strength. */
|
|
2368
|
+
interface MaterialTintInput {
|
|
2369
|
+
readonly color: readonly [number, number, number];
|
|
2370
|
+
readonly strength: number;
|
|
2371
|
+
}
|
|
1896
2372
|
interface SurfaceInput {
|
|
1897
2373
|
readonly nodeId: string;
|
|
1898
2374
|
readonly family: ShapeFamily;
|
|
@@ -1901,6 +2377,17 @@ interface SurfaceInput {
|
|
|
1901
2377
|
/** Defaults to `"apple-continuous"` — see the module note. */
|
|
1902
2378
|
readonly reference?: CornerReference;
|
|
1903
2379
|
readonly variant?: MaterialVariant;
|
|
2380
|
+
/**
|
|
2381
|
+
* The author's tint (core's `ResolvedMaterial.tint`), in **linear** light —
|
|
2382
|
+
* the host converts, because this package's whole optical model is linear and
|
|
2383
|
+
* the seed is about to be mixed into it.
|
|
2384
|
+
*
|
|
2385
|
+
* The strength travels per surface and reaches the fragment stage per pixel;
|
|
2386
|
+
* the seed colour is resolved once per group, because a group is one optics
|
|
2387
|
+
* pass. Core warns when a group's members ask for different seeds
|
|
2388
|
+
* (`tint-mixing`), and the first tinted member's colour is the one drawn.
|
|
2389
|
+
*/
|
|
2390
|
+
readonly tint?: MaterialTintInput;
|
|
1904
2391
|
readonly channels?: Partial<SurfaceChannels>;
|
|
1905
2392
|
/**
|
|
1906
2393
|
* X8 rider 2. When present this surface renders as `parentField + inset`, and
|
|
@@ -1935,6 +2422,24 @@ interface GroupRenderInput {
|
|
|
1935
2422
|
readonly refraction: RefractionQuality;
|
|
1936
2423
|
/** True where X2 resolved `analysis: "exact"`; gates adaptive tint. */
|
|
1937
2424
|
readonly analysisExact: boolean;
|
|
2425
|
+
/**
|
|
2426
|
+
* The backdrop source's own average colour, linear light — what backdrop tone
|
|
2427
|
+
* adaptation (W7) adapts toward, and the luminance it decides from.
|
|
2428
|
+
*
|
|
2429
|
+
* A **per-source scalar rather than a per-pixel sample**, and that is why it
|
|
2430
|
+
* arrives from outside rather than being read off the pyramid. The host measures
|
|
2431
|
+
* it once from the pixels it already supplied and both tiers then read the
|
|
2432
|
+
* identical number: the CSS tier cannot sample per pixel at all, and a per-pixel
|
|
2433
|
+
* GPU adaptation beside a per-surface CSS one puts the two tiers on different
|
|
2434
|
+
* pictures wherever the backdrop has structure — measured on the impulse cell at
|
|
2435
|
+
* an interior level ratio of 79 against a gated band of 0.80…1.25. It is also
|
|
2436
|
+
* what the reference does: its capsule over a sparse bright grid is a *flat*
|
|
2437
|
+
* body, not a window onto the grid.
|
|
2438
|
+
*
|
|
2439
|
+
* Absent means the adaptation stands down for this group, rather than falling
|
|
2440
|
+
* back to a level nobody measured.
|
|
2441
|
+
*/
|
|
2442
|
+
readonly backdropTone?: Rgb;
|
|
1938
2443
|
readonly variant?: MaterialVariant;
|
|
1939
2444
|
/** Overrides the calibration-delegated union defaults. */
|
|
1940
2445
|
readonly union?: GroupUnionParams;
|
|
@@ -2138,6 +2643,17 @@ interface PyramidResources {
|
|
|
2138
2643
|
readonly sizeEpoch: number;
|
|
2139
2644
|
/** The dirty epoch the last successful rebuild satisfied. */
|
|
2140
2645
|
readonly builtEpoch: number;
|
|
2646
|
+
/**
|
|
2647
|
+
* The body blur's σ in **level-0 texels** — the CSS-px σ the material asked
|
|
2648
|
+
* for, through the same cover fit and plan downscale the build applied.
|
|
2649
|
+
*
|
|
2650
|
+
* Published because the conversion is only knowable here: it needs the frame's
|
|
2651
|
+
* real extent, which is exactly why `bodySigmaCss` arrives in CSS px. The size
|
|
2652
|
+
* law's scattering facet consumes it (W2) — the optics pass widens the body blur
|
|
2653
|
+
* per surface by sampling the chain, and it cannot find the level to measure
|
|
2654
|
+
* from without knowing where the body already sits.
|
|
2655
|
+
*/
|
|
2656
|
+
readonly bodySigmaTexels: number;
|
|
2141
2657
|
}
|
|
2142
2658
|
interface PyramidInstrumentation {
|
|
2143
2659
|
/** Successful rebuilds since the store was created. */
|
|
@@ -2417,7 +2933,7 @@ declare function loadWebGPURenderer(): Promise<GlassRenderer>;
|
|
|
2417
2933
|
*
|
|
2418
2934
|
* Pure and passive: no DOM, no Node built-ins (X4), no timers and no clocks.
|
|
2419
2935
|
* Every probe result, media-query answer and layout rect arrives as plain data;
|
|
2420
|
-
* @vitrea
|
|
2936
|
+
* @vitreajs/vitrea-web owns the browser and drives the frames.
|
|
2421
2937
|
*
|
|
2422
2938
|
* The modules, roughly in dependency order:
|
|
2423
2939
|
*
|
|
@@ -2447,4 +2963,4 @@ declare const VITREA_CONTRACTS: {
|
|
|
2447
2963
|
declare const RENDERER_TIERS: readonly ["webgpu", "css"];
|
|
2448
2964
|
type RendererTier = (typeof RENDERER_TIERS)[number];
|
|
2449
2965
|
|
|
2450
|
-
export { ACCESSIBILITY_BEHAVIOR_TABLE, ACCESSIBILITY_FLAGS, ACCESSIBILITY_PRECEDENCE, type AccessibilityConsequences, type AccessibilityFlag, type AccessibilityOverride, type AccessibilityOverrides, type ActiveRenderer, type AnalysisQuality, type BackdropEstimatorProvider, type BackdropHint, type BackdropHintRequest, type BackdropProvider, type BackdropRebuildRequest, type BackdropResolutionPolicy, type BackdropSourceDescriptor, type BackdropSourceRecord, type BackdropTone, type CapabilityInputs, type ConfiguredSource, type CopyProviderOptions, type CornerProfile, type CornerRadii, DEFAULT_BACKDROP_RESOLUTION, DEFAULT_CLEAR_DIMMING, DEFAULT_GROUP_SAMPLING, DEMOTION_REASONS, DEMOTION_RECOVERY, DIAGNOSTIC_CODES, type DemotionReason, type DescriptorPatch, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type DiagnosticSink, type DiagnosticsChannel, type DiagnosticsChannelOptions, type DimmingPolicy, type DomBackdropSource, FOREGROUND_MODES, FRAME_PHASES, type ForegroundAdaptation, type ForegroundMode, type ForegroundResolutionOptions, type FrameContext, type FrameInfo, type FrameParticipant, type FramePhase, type FrameReport, type FrameScheduler, type FrameSchedulerOptions, GLASS_PLANES, GOVERNOR_PRESSURES, type GlassGroupDescriptor, type GlassGroupRecord, type GlassGroupState, type GlassNodeDescriptor, type GlassNodeRecord, type GlassPlane, type GlassRenderer, type GlassScene, GlassSceneError, type GlassSceneErrorCode, type GlassSceneOptions, type GovernorPressure, type GroupHealth, type GroupSamplingGeometry, type GroupStateChange, HINT_AVAILABILITIES, type HintAvailability, type InteractionState, MATERIAL_VARIANTS$1 as MATERIAL_VARIANTS, type MaterialProfile$1 as MaterialProfile, type MaterialRequest, type MaterialVariant$1 as MaterialVariant, type MotionChannel, type MotionDriverKind, NOMINAL_ACCESSIBILITY_POLICY, OVERRIDABLE_ACCESSIBILITY_FLAGS, type OverridableAccessibilityFlag, type PlaneOverlap, type PlatformProbe, type ProxyOverlap, RENDERER_TIERS, type RecoveryContract, type RecoveryTrigger, type Rect, type RefractionQuality
|
|
2966
|
+
export { ACCESSIBILITY_BEHAVIOR_TABLE, ACCESSIBILITY_FLAGS, ACCESSIBILITY_PRECEDENCE, type AccessibilityConsequences, type AccessibilityFlag, type AccessibilityOverride, type AccessibilityOverrides, type ActiveRenderer, type AnalysisQuality, type BackdropEstimatorProvider, type BackdropHint, type BackdropHintRequest, type BackdropProvider, type BackdropRebuildRequest, type BackdropResolutionPolicy, type BackdropSourceDescriptor, type BackdropSourceRecord, type BackdropTone, type CapabilityInputs, type ConcentricParent, type ConfiguredSource, type CopyProviderOptions, type CornerProfile, type CornerRadii, type CornerReference, DEFAULT_BACKDROP_RESOLUTION, DEFAULT_CLEAR_DIMMING, DEFAULT_GROUP_SAMPLING, DEMOTION_REASONS, DEMOTION_RECOVERY, DIAGNOSTIC_CODES, type DemotionReason, type DescriptorPatch, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type DiagnosticSink, type DiagnosticsChannel, type DiagnosticsChannelOptions, type DimmingPolicy, type DomBackdropSource, FOREGROUND_MODES, FRAME_PHASES, type ForegroundAdaptation, type ForegroundMode, type ForegroundResolutionOptions, type FrameContext, type FrameInfo, type FrameParticipant, type FramePhase, type FrameReport, type FrameScheduler, type FrameSchedulerOptions, GLASS_PLANES, GOVERNOR_PRESSURES, type GlassGroupDescriptor, type GlassGroupRecord, type GlassGroupState, type GlassNodeDescriptor, type GlassNodeRecord, type GlassPlane, type GlassRenderer, type GlassScene, GlassSceneError, type GlassSceneErrorCode, type GlassSceneOptions, type GlassTint, type GovernorPressure, type GroupHealth, type GroupSamplingGeometry, type GroupStateChange, HINT_AVAILABILITIES, type HintAvailability, type InteractionState, MATERIAL_VARIANTS$1 as MATERIAL_VARIANTS, type MaterialProfile$1 as MaterialProfile, type MaterialRequest, type MaterialVariant$1 as MaterialVariant, type MotionChannel, type MotionDriverKind, NOMINAL_ACCESSIBILITY_POLICY, OVERRIDABLE_ACCESSIBILITY_FLAGS, type OverridableAccessibilityFlag, type PlaneOverlap, type PlatformProbe, type ProxyOverlap, RENDERER_TIERS, type RecoveryContract, type RecoveryTrigger, type Rect, type RefractionQuality, type RendererTier, type ResolvedAccessibilityPolicy, type ResolvedBackdropHint, type ResolvedForegroundAdaptation, type ResolvedGroup, type ResolvedMaterial, type ResolvedMaterialPolicy, type ResolvedMotionPolicy, type ResolvedNode, SAMPLED_ASYNC_DEFAULTS, SAMPLED_ASYNC_RATE_LIMITS, type SamplingBackend, type SceneResolution, type ShapeChannels, type ShapeFamily, type SourceProbe, type StateChange, type SystemAccessibilityPreferences, type TextureBackdropSource, type TintColor, type TintMixingCheck, VITREA_CONTRACTS, type VariantMixingCheck, type Vec2, type VideoProviderOptions, WEBGPU_AVAILABILITIES, type WebGPUAvailability$1 as WebGPUAvailability, type WebGPURendererModule, type ZSlot, checkTintMixing, checkVariantMixing, classifyStateChange, clipRect, compareZSlot, createDiagnosticsChannel, createFrameScheduler, createGlassScene, defaultForegroundAdaptation, glassTint, inflateRect, isHealthy, loadWebGPURenderer, loadWebGPURendererModule, rectsOverlap, resolveAccessibilityPolicy, resolveBackdropHint, resolveForegroundAdaptation, resolveGlassGroupState, resolveMaterial, unionRect };
|