@buoy-gg/shared-ui 7.0.22 → 7.0.24

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.
Files changed (154) hide show
  1. package/lib/commonjs/JsModal.js +39 -16
  2. package/lib/commonjs/dataViewer/JsonStringNotice.js +59 -0
  3. package/lib/commonjs/dataViewer/ThemedSplitView.js +20 -1
  4. package/lib/commonjs/dataViewer/TimestampDeltaBar.js +96 -0
  5. package/lib/commonjs/dataViewer/index.js +52 -0
  6. package/lib/commonjs/dataViewer/jsonStringValue.js +94 -0
  7. package/lib/commonjs/dataViewer/timestampDiff.js +146 -0
  8. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  9. package/lib/commonjs/index.js +50 -1
  10. package/lib/commonjs/license/FeatureGate.js +43 -10
  11. package/lib/commonjs/license/FreeAccountPrompt.js +181 -0
  12. package/lib/commonjs/license/index.js +57 -42
  13. package/lib/commonjs/license/licenseModule.js +99 -0
  14. package/lib/commonjs/license/tierLimits.js +165 -0
  15. package/lib/commonjs/ui/backgrounds/BackgroundSwitcher.js +180 -0
  16. package/lib/commonjs/ui/backgrounds/README.md +115 -0
  17. package/lib/commonjs/ui/backgrounds/ToolBackground.js +74 -0
  18. package/lib/commonjs/ui/backgrounds/backgroundStore.js +116 -0
  19. package/lib/commonjs/ui/backgrounds/index.js +70 -0
  20. package/lib/commonjs/ui/backgrounds/primitives.js +333 -0
  21. package/lib/commonjs/ui/backgrounds/registry.js +112 -0
  22. package/lib/commonjs/ui/backgrounds/rng.js +72 -0
  23. package/lib/commonjs/ui/backgrounds/types.js +1 -0
  24. package/lib/commonjs/ui/backgrounds/variants/deepField.js +351 -0
  25. package/lib/commonjs/ui/backgrounds/variants/lattice.js +579 -0
  26. package/lib/commonjs/ui/backgrounds/variants/starfield.js +210 -0
  27. package/lib/commonjs/ui/index.js +15 -3
  28. package/lib/module/JsModal.js +39 -16
  29. package/lib/module/dataViewer/JsonStringNotice.js +54 -0
  30. package/lib/module/dataViewer/ThemedSplitView.js +20 -1
  31. package/lib/module/dataViewer/TimestampDeltaBar.js +91 -0
  32. package/lib/module/dataViewer/index.js +4 -0
  33. package/lib/module/dataViewer/jsonStringValue.js +89 -0
  34. package/lib/module/dataViewer/timestampDiff.js +139 -0
  35. package/lib/module/hooks/safe-area-impl.js +1 -1
  36. package/lib/module/index.js +1 -1
  37. package/lib/module/license/FeatureGate.js +43 -10
  38. package/lib/module/license/FreeAccountPrompt.js +176 -0
  39. package/lib/module/license/index.js +5 -40
  40. package/lib/module/license/licenseModule.js +92 -0
  41. package/lib/module/license/tierLimits.js +158 -0
  42. package/lib/module/ui/backgrounds/BackgroundSwitcher.js +176 -0
  43. package/lib/module/ui/backgrounds/README.md +115 -0
  44. package/lib/module/ui/backgrounds/ToolBackground.js +70 -0
  45. package/lib/module/ui/backgrounds/backgroundStore.js +111 -0
  46. package/lib/module/ui/backgrounds/index.js +9 -0
  47. package/lib/module/ui/backgrounds/primitives.js +328 -0
  48. package/lib/module/ui/backgrounds/registry.js +105 -0
  49. package/lib/module/ui/backgrounds/rng.js +65 -0
  50. package/lib/module/ui/backgrounds/types.js +1 -0
  51. package/lib/module/ui/backgrounds/variants/deepField.js +347 -0
  52. package/lib/module/ui/backgrounds/variants/lattice.js +575 -0
  53. package/lib/module/ui/backgrounds/variants/starfield.js +206 -0
  54. package/lib/module/ui/index.js +3 -0
  55. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts +6 -0
  57. package/lib/typescript/commonjs/dataViewer/JsonStringNotice.d.ts.map +1 -0
  58. package/lib/typescript/commonjs/dataViewer/ThemedSplitView.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts +7 -0
  60. package/lib/typescript/commonjs/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  61. package/lib/typescript/commonjs/dataViewer/index.d.ts +6 -0
  62. package/lib/typescript/commonjs/dataViewer/index.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts +25 -0
  64. package/lib/typescript/commonjs/dataViewer/jsonStringValue.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts +55 -0
  66. package/lib/typescript/commonjs/dataViewer/timestampDiff.d.ts.map +1 -0
  67. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  68. package/lib/typescript/commonjs/index.d.ts +2 -2
  69. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/license/FeatureGate.d.ts +19 -3
  71. package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts +23 -0
  73. package/lib/typescript/commonjs/license/FreeAccountPrompt.d.ts.map +1 -0
  74. package/lib/typescript/commonjs/license/index.d.ts +6 -15
  75. package/lib/typescript/commonjs/license/index.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/license/licenseModule.d.ts +55 -0
  77. package/lib/typescript/commonjs/license/licenseModule.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/license/tierLimits.d.ts +143 -0
  79. package/lib/typescript/commonjs/license/tierLimits.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  81. package/lib/typescript/commonjs/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts +30 -0
  83. package/lib/typescript/commonjs/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  84. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts +43 -0
  85. package/lib/typescript/commonjs/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  86. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts +7 -0
  87. package/lib/typescript/commonjs/ui/backgrounds/index.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts +106 -0
  89. package/lib/typescript/commonjs/ui/backgrounds/primitives.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts +28 -0
  91. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts.map +1 -0
  92. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts +27 -0
  93. package/lib/typescript/commonjs/ui/backgrounds/rng.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts +14 -0
  95. package/lib/typescript/commonjs/ui/backgrounds/types.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts +65 -0
  97. package/lib/typescript/commonjs/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  98. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts +33 -0
  99. package/lib/typescript/commonjs/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts +12 -0
  101. package/lib/typescript/commonjs/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/ui/index.d.ts +1 -0
  103. package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
  104. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  105. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts +6 -0
  106. package/lib/typescript/module/dataViewer/JsonStringNotice.d.ts.map +1 -0
  107. package/lib/typescript/module/dataViewer/ThemedSplitView.d.ts.map +1 -1
  108. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts +7 -0
  109. package/lib/typescript/module/dataViewer/TimestampDeltaBar.d.ts.map +1 -0
  110. package/lib/typescript/module/dataViewer/index.d.ts +6 -0
  111. package/lib/typescript/module/dataViewer/index.d.ts.map +1 -1
  112. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts +25 -0
  113. package/lib/typescript/module/dataViewer/jsonStringValue.d.ts.map +1 -0
  114. package/lib/typescript/module/dataViewer/timestampDiff.d.ts +55 -0
  115. package/lib/typescript/module/dataViewer/timestampDiff.d.ts.map +1 -0
  116. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  117. package/lib/typescript/module/index.d.ts +2 -2
  118. package/lib/typescript/module/index.d.ts.map +1 -1
  119. package/lib/typescript/module/license/FeatureGate.d.ts +19 -3
  120. package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
  121. package/lib/typescript/module/license/FreeAccountPrompt.d.ts +23 -0
  122. package/lib/typescript/module/license/FreeAccountPrompt.d.ts.map +1 -0
  123. package/lib/typescript/module/license/index.d.ts +6 -15
  124. package/lib/typescript/module/license/index.d.ts.map +1 -1
  125. package/lib/typescript/module/license/licenseModule.d.ts +55 -0
  126. package/lib/typescript/module/license/licenseModule.d.ts.map +1 -0
  127. package/lib/typescript/module/license/tierLimits.d.ts +143 -0
  128. package/lib/typescript/module/license/tierLimits.d.ts.map +1 -0
  129. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts +13 -0
  130. package/lib/typescript/module/ui/backgrounds/BackgroundSwitcher.d.ts.map +1 -0
  131. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts +30 -0
  132. package/lib/typescript/module/ui/backgrounds/ToolBackground.d.ts.map +1 -0
  133. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts +43 -0
  134. package/lib/typescript/module/ui/backgrounds/backgroundStore.d.ts.map +1 -0
  135. package/lib/typescript/module/ui/backgrounds/index.d.ts +7 -0
  136. package/lib/typescript/module/ui/backgrounds/index.d.ts.map +1 -0
  137. package/lib/typescript/module/ui/backgrounds/primitives.d.ts +106 -0
  138. package/lib/typescript/module/ui/backgrounds/primitives.d.ts.map +1 -0
  139. package/lib/typescript/module/ui/backgrounds/registry.d.ts +28 -0
  140. package/lib/typescript/module/ui/backgrounds/registry.d.ts.map +1 -0
  141. package/lib/typescript/module/ui/backgrounds/rng.d.ts +27 -0
  142. package/lib/typescript/module/ui/backgrounds/rng.d.ts.map +1 -0
  143. package/lib/typescript/module/ui/backgrounds/types.d.ts +14 -0
  144. package/lib/typescript/module/ui/backgrounds/types.d.ts.map +1 -0
  145. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts +65 -0
  146. package/lib/typescript/module/ui/backgrounds/variants/deepField.d.ts.map +1 -0
  147. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts +33 -0
  148. package/lib/typescript/module/ui/backgrounds/variants/lattice.d.ts.map +1 -0
  149. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts +12 -0
  150. package/lib/typescript/module/ui/backgrounds/variants/starfield.d.ts.map +1 -0
  151. package/lib/typescript/module/ui/index.d.ts +1 -0
  152. package/lib/typescript/module/ui/index.d.ts.map +1 -1
  153. package/package.json +4 -4
  154. package/scripts/detect-safe-area.js +0 -20
@@ -0,0 +1,347 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Deep Field — a faithful port of the Everlights `ParallaxDriftBackground`.
5
+ *
6
+ * The sibling `Starfield` preset is a cheap approximation of the same idea: 99
7
+ * stars quantised into five depth bands. This one reproduces the original's
8
+ * field exactly — same seed, same generator call order, same 160 stars, same
9
+ * `z = zNear + zSpan·√rnd()` far-plane bias, same sizes, brightnesses, palette
10
+ * and drift. Drop the constants below into the Skia version and you get the
11
+ * same sky.
12
+ *
13
+ * WHAT COULDN'T COME ACROSS 1:1, and what was done instead:
14
+ *
15
+ * - **Continuous per-star speed.** The original runs a worklet per star, so
16
+ * every one of the 160 drifts at its own `drift/z`. Here a distinct speed
17
+ * means a distinct animated node, so SPEED (and only speed) is quantised
18
+ * into 18 bands — banded uniformly in 1/z, which is what speed is
19
+ * proportional to, so the steps are even. Size, brightness, colour and
20
+ * twinkle phase all stay per-star and exact, and those are the properties
21
+ * the eye actually reads as depth.
22
+ *
23
+ * - **The soft bulb sprite.** The original bakes one 64px sprite (blurred halo
24
+ * at r=6/α.30 over a blurred core at r=4/α1) and stamps it at `dia`. That is
25
+ * why stars stay fine points even at dia=20 — the lit core is only ~13% of
26
+ * the stamp. There is no blur primitive here, so each star is a small solid
27
+ * core at that same 13%, and the nearer ones get one or two concentric
28
+ * discs standing in for the halo. Far stars end up a single ~1px dot, which
29
+ * is what the sprite renders them as anyway.
30
+ *
31
+ * - **Additive blending.** `blendMode="plus"` becomes ordinary alpha
32
+ * compositing. Over a near-black base the two agree except where stars
33
+ * overlap, which at this density is rare.
34
+ *
35
+ * It costs roughly twice the cheap Starfield — see `registry.tsx` — which is
36
+ * the whole reason both are in the catalogue.
37
+ */
38
+
39
+ import { memo } from "react";
40
+ import { Animated, View } from "react-native";
41
+ import { absoluteFill } from "../../../utils/absoluteFill.js";
42
+ import { Base, RadialGlow, RasterLayer, useLoop, usePulse } from "../primitives.js";
43
+ import { flattenOver, mulberry32, withAlpha } from "../rng.js";
44
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
45
+ // ---------------------------------------------------------------------------
46
+ // The original's shipping constants, verbatim.
47
+ // ---------------------------------------------------------------------------
48
+ const COUNT = 160;
49
+ const DRIFT = 0.016; // horizontal travel/sec at z=1, as a fraction of width
50
+ const BASE_DIA = 5; // sprite diameter px at z=1
51
+ const Z_NEAR = 0.25;
52
+ const Z_FAR = 1.0;
53
+ const Z_SPAN = Z_FAR - Z_NEAR;
54
+ const MAX_DIA = BASE_DIA / Z_NEAR;
55
+ const TWINKLE = 0.08;
56
+
57
+ /** The classic white/blue mix — `[r,g,b]` 0..1 in the original. */
58
+ const PALETTE = ["#FFFFFF", "#B3D9FF", "#8CB3FF"];
59
+
60
+ /** The backdrop the field sits on — also what `opaque` mode flattens against. */
61
+ const BASE_COLOR = "#050609";
62
+
63
+ /**
64
+ * Default speed bands. 18 is the point where stepping stops being visible:
65
+ * adjacent bands differ by ~6% in speed, well under what reads as a seam. The
66
+ * bench route sweeps this, since it is the main lever on cost.
67
+ */
68
+ const BAND_COUNT = 18;
69
+ /** Twinkle groups — bands are round-robined across these. */
70
+ const TWINKLE_GROUPS = 4;
71
+ const TWINKLE_MS = [4200, 4900, 5600, 6300];
72
+
73
+ /** How the ±8% brightness wobble is applied. */
74
+
75
+ /** How many concentric discs stand in for the sprite's blurred halo. */
76
+
77
+ /**
78
+ * The original field, regenerated.
79
+ *
80
+ * The generator order matters as much as the seed: the source pulls fx, fy, z
81
+ * and tw off ONE mulberry32 stream per star, so drawing them in any other order
82
+ * — four separate `scatter()` calls, say — gives a different sky from the same
83
+ * seed. Built once at module load.
84
+ */
85
+ function buildField(count) {
86
+ const rnd = mulberry32((0x5747 ^ count) >>> 0);
87
+ const stars = [];
88
+ for (let i = 0; i < count; i++) {
89
+ const fx = rnd();
90
+ const fy = rnd();
91
+ // Bias toward the far plane so close, fast streaks stay sparse.
92
+ const z = Z_NEAR + Z_SPAN * Math.sqrt(rnd());
93
+ const tw = rnd() * Math.PI * 2;
94
+ const dia = Math.min(BASE_DIA / z, MAX_DIA);
95
+ const near = (Z_FAR - z) / Z_SPAN; // 0 far → 1 near
96
+ stars.push({
97
+ fx,
98
+ fy,
99
+ z,
100
+ tw,
101
+ // 0.15·dia ≈ the sprite's lit core (r=4 of 64, blurred), with a 1.1px
102
+ // floor so the farthest stars still land on a pixel.
103
+ core: Math.max(1.1, dia * 0.15),
104
+ halo: dia * 0.3,
105
+ haloDiscs: z < 0.45 ? 2 : z < 0.7 ? 1 : 0,
106
+ alpha: 0.2 + 0.8 * near,
107
+ color: PALETTE[Math.floor((tw * 0.5 + 0.5) * PALETTE.length) % PALETTE.length]
108
+ });
109
+ }
110
+ return stars;
111
+ }
112
+
113
+ /**
114
+ * Fields by star count, built on demand.
115
+ *
116
+ * 160 is the real preset. The larger counts exist for AMPLIFIED benchmarking:
117
+ * at 160 the difference between two rendering structures is ~2 CPU points,
118
+ * which on real hardware sits under a noise floor several times that — so the
119
+ * variants are compared at a scale where the difference is unmistakable, and
120
+ * the structure that wins there is the one worth shipping at 160.
121
+ *
122
+ * Note the seed is `0x5747 ^ count`, exactly as the original does it, so each
123
+ * count is its own field rather than a prefix of a bigger one. That is fine
124
+ * here: only the 160 field has to match Everlights.
125
+ */
126
+ const fieldCache = new Map();
127
+ function getField(count) {
128
+ const cached = fieldCache.get(count);
129
+ if (cached) return cached;
130
+ const built = buildField(count);
131
+ fieldCache.set(count, built);
132
+ return built;
133
+ }
134
+ const FIELD = getField(COUNT);
135
+
136
+ /**
137
+ * Bucket by 1/z (∝ speed) rather than by z, so the bands are evenly spaced in
138
+ * the quantity being quantised. Each band carries its member stars and the
139
+ * speed of its centre. Cached per count — the bench route asks for several.
140
+ */
141
+ const bandCache = new Map();
142
+ function buildBands(count, starCount) {
143
+ const key = `${count}:${starCount}`;
144
+ const cached = bandCache.get(key);
145
+ if (cached) return cached;
146
+ const field = getField(starCount);
147
+ const invNear = 1 / Z_NEAR; // 4
148
+ const invFar = 1 / Z_FAR; // 1
149
+ const span = invNear - invFar;
150
+ const buckets = Array.from({
151
+ length: count
152
+ }, () => []);
153
+ for (const star of field) {
154
+ const t = (1 / star.z - invFar) / span;
155
+ const idx = Math.min(count - 1, Math.max(0, Math.floor(t * count)));
156
+ buckets[idx].push(star);
157
+ }
158
+ const bands = buckets.map((stars, i) => ({
159
+ stars,
160
+ // z at the band's centre, back out of the 1/z bucketing.
161
+ z: 1 / (invFar + (i + 0.5) / count * span)
162
+ }));
163
+ bandCache.set(key, bands);
164
+ return bands;
165
+ }
166
+ const DeepBand = /*#__PURE__*/memo(function DeepBand({
167
+ bands,
168
+ index,
169
+ width,
170
+ height,
171
+ animated,
172
+ raster,
173
+ halo,
174
+ opaque,
175
+ drift,
176
+ opacity
177
+ }) {
178
+ const band = bands[index];
179
+ // One full width of travel takes z / DRIFT seconds, exactly as in the
180
+ // original's `phase = fx - t·(drift/z)`.
181
+ const driftValue = useLoop(band.z / DRIFT * 1000, animated && drift);
182
+ const translateX = driftValue.interpolate({
183
+ inputRange: [0, 1],
184
+ outputRange: [0, -width]
185
+ });
186
+ // Over a known backdrop an opaque colour is pixel-identical to the
187
+ // translucent one — the GPU just skips the blend.
188
+ const paint = (color, alpha) => opaque ? flattenOver(color, alpha, BASE_COLOR) : withAlpha(color, alpha);
189
+ const parts = [];
190
+ for (let i = 0; i < band.stars.length; i++) {
191
+ const star = band.stars[i];
192
+ const y = star.fy * height;
193
+ const discs = halo === "none" ? 0 : halo === "flat" ? star.haloDiscs > 0 ? 1 : 0 : star.haloDiscs;
194
+ // Drawn twice, one width apart, so the layer tiles seamlessly when the
195
+ // loop snaps back to 0.
196
+ for (let copy = 0; copy < 2; copy++) {
197
+ const x = star.fx * width + copy * width;
198
+ const key = `${i}-${copy}`;
199
+ for (let h = 0; h < discs; h++) {
200
+ const d = star.halo * (h === 0 ? 1 : 0.6);
201
+ parts.push(/*#__PURE__*/_jsx(View, {
202
+ style: {
203
+ position: "absolute",
204
+ left: x - d / 2,
205
+ top: y - d / 2,
206
+ width: d,
207
+ height: d,
208
+ borderRadius: d / 2,
209
+ // The sprite's halo is α.30 of the core; scaled by the star's own
210
+ // depth brightness like everything else.
211
+ backgroundColor: paint(star.color, star.alpha * 0.3)
212
+ }
213
+ }, `${key}-h${h}`));
214
+ }
215
+ parts.push(/*#__PURE__*/_jsx(View, {
216
+ style: {
217
+ position: "absolute",
218
+ left: x - star.core / 2,
219
+ top: y - star.core / 2,
220
+ width: star.core,
221
+ height: star.core,
222
+ borderRadius: star.core / 2,
223
+ backgroundColor: paint(star.color, star.alpha)
224
+ }
225
+ }, key));
226
+ }
227
+ }
228
+ return /*#__PURE__*/_jsx(Animated.View, {
229
+ style: [{
230
+ position: "absolute",
231
+ left: 0,
232
+ top: 0,
233
+ width: width * 2,
234
+ height
235
+ },
236
+ // Fused mode puts the wobble on THIS layer instead of a wrapper above
237
+ // it, so the twinkle costs no extra composited surface.
238
+ opacity ? {
239
+ opacity,
240
+ transform: [{
241
+ translateX
242
+ }]
243
+ } : {
244
+ transform: [{
245
+ translateX
246
+ }]
247
+ }],
248
+ pointerEvents: "none",
249
+ children: /*#__PURE__*/_jsx(RasterLayer, {
250
+ raster: raster,
251
+ style: {
252
+ width: width * 2,
253
+ height
254
+ },
255
+ children: parts
256
+ })
257
+ });
258
+ });
259
+
260
+ /**
261
+ * The four wobble values. The original wobbles each star by
262
+ * `1 + 0.08·sin(t·3 + tw)`; per-star that would be 160 nodes, so bands are
263
+ * round-robined across four pulses at slightly different periods — same ±8%
264
+ * amplitude, and the differing periods keep the sky from pulsing as a unit.
265
+ *
266
+ * Fixed count, called unconditionally, so hook order never varies with props.
267
+ */
268
+ function useTwinkles(animated, enabled) {
269
+ const a = usePulse(TWINKLE_MS[0], animated && enabled);
270
+ const b = usePulse(TWINKLE_MS[1], animated && enabled);
271
+ const c = usePulse(TWINKLE_MS[2], animated && enabled);
272
+ const d = usePulse(TWINKLE_MS[3], animated && enabled);
273
+ const range = {
274
+ inputRange: [0, 1],
275
+ outputRange: [1 - TWINKLE, 1]
276
+ };
277
+ return [a.interpolate(range), b.interpolate(range), c.interpolate(range), d.interpolate(range)];
278
+ }
279
+ /**
280
+ * The tunable body. `DeepField` below is this with the shipping defaults; the
281
+ * bench route (`example-dev-build/app/bg-bench.tsx`) drives the knobs so every
282
+ * measured variant is this exact code, not a copy of it.
283
+ */
284
+ export const DeepFieldTunable = /*#__PURE__*/memo(function DeepFieldTunable({
285
+ width,
286
+ height,
287
+ animated,
288
+ bandCount = BAND_COUNT,
289
+ raster = true,
290
+ twinkle = "group",
291
+ halo = "full",
292
+ opaque = false,
293
+ drift = true,
294
+ starCount = COUNT
295
+ }) {
296
+ const bands = buildBands(bandCount, starCount);
297
+ const twinkles = useTwinkles(animated, twinkle !== "off");
298
+ const bandViews = [];
299
+ for (let i = 0; i < bandCount; i++) {
300
+ bandViews.push(/*#__PURE__*/_jsx(DeepBand, {
301
+ bands: bands,
302
+ index: i,
303
+ width: width,
304
+ height: height,
305
+ animated: animated,
306
+ raster: raster,
307
+ halo: halo,
308
+ opaque: opaque,
309
+ drift: drift,
310
+ opacity: twinkle === "fused" ? twinkles[i % TWINKLE_GROUPS] : undefined
311
+ }, i));
312
+ }
313
+ return /*#__PURE__*/_jsxs(View, {
314
+ style: absoluteFill,
315
+ pointerEvents: "none",
316
+ children: [/*#__PURE__*/_jsx(Base, {
317
+ color: BASE_COLOR
318
+ }), /*#__PURE__*/_jsx(RadialGlow, {
319
+ size: width * 1.7,
320
+ color: "#1E3A8A",
321
+ alpha: 0.16,
322
+ rings: 8,
323
+ falloff: 2.1,
324
+ style: {
325
+ position: "absolute",
326
+ left: -width * 0.35,
327
+ top: -width
328
+ }
329
+ }), twinkle === "group" ?
330
+ // Group mode: one full-screen Animated.View per pulse, each wrapping
331
+ // its share of the bands. Costs four extra composited surfaces.
332
+ Array.from({
333
+ length: TWINKLE_GROUPS
334
+ }, (_, g) => /*#__PURE__*/_jsx(Animated.View, {
335
+ style: [absoluteFill, {
336
+ opacity: twinkles[g]
337
+ }],
338
+ pointerEvents: "none",
339
+ children: bandViews.filter((_, i) => i % TWINKLE_GROUPS === g)
340
+ }, g)) : bandViews]
341
+ });
342
+ });
343
+ export const DeepField = /*#__PURE__*/memo(function DeepField(props) {
344
+ return /*#__PURE__*/_jsx(DeepFieldTunable, {
345
+ ...props
346
+ });
347
+ });