@3driseai/3drise-viewer 0.1.35 → 0.1.38

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.
@@ -0,0 +1,77 @@
1
+ import * as THREE from 'three';
2
+ import type { Object3D } from 'three';
3
+ export interface HarmonicState {
4
+ f1: Float32Array;
5
+ f2: Float32Array;
6
+ p1: Float32Array;
7
+ p2: Float32Array;
8
+ gate: Float32Array;
9
+ }
10
+ /** Fixed per-term frequencies and phases, so the same config always moves the same way. */
11
+ export declare function createHarmonicState(): HarmonicState;
12
+ /**
13
+ * Writes the 24 weights for time T into `out`. Bands above `degree` fade
14
+ * out; the top band leads and lower bands sit at about half strength.
15
+ */
16
+ export declare function updateHarmonicWeights(state: HarmonicState, out: Float32Array, T: number, degree: number, dt: number): void;
17
+ /** The shared uniforms, declared (the shell's own ShaderMaterial; a layered material gets them from the kit). */
18
+ export declare const HSH_FIELD_DECL = "\n uniform float uHshW[24];\n uniform float uHshAmplitude; uniform float uHshBound; uniform float uHshSize;\n uniform vec3 uHshColor; uniform vec3 uHshRim; uniform float uHshFilm; uniform float uHshTint; uniform float uHshTime;\n uniform float uHshMorph; uniform float uHshMode;\n uniform sampler2D uHshSdf; uniform vec2 uHshSdfHalf; uniform float uHshDepth;\n uniform sampler3D uHshSdf3; uniform vec3 uHshSdf3Min; uniform vec3 uHshSdf3Size; uniform mat4 uHshSdf3Inv; uniform mat4 uHshSdf3Mat;\n";
19
+ /**
20
+ * The field, for any shader (after the declarations): the harmonic polynomial, the
21
+ * thin film, and the target distance functions. Include once per stage.
22
+ */
23
+ export declare const HSH_FIELD_FUNCS = "\n\n // Real spherical harmonics for l = 1..4, as polynomials in the unit vector,\n // each scaled so its peak is about 1. The CPU animates the 24 weights.\n float hshSh(vec3 n){\n float x = n.x, y = n.y, z = n.z;\n float x2 = x * x, y2 = y * y, z2 = z * z;\n float s = 0.0;\n s += uHshW[0] * y + uHshW[1] * z + uHshW[2] * x;\n s += uHshW[3] * 2.0 * x * y + uHshW[4] * 2.0 * y * z + uHshW[5] * (1.5 * z2 - 0.5)\n + uHshW[6] * 2.0 * x * z + uHshW[7] * (x2 - y2);\n s += uHshW[8] * y * (3.0 * x2 - y2)\n + uHshW[9] * 5.2 * x * y * z\n + uHshW[10] * 0.8 * y * (5.0 * z2 - 1.0)\n + uHshW[11] * 0.5 * z * (5.0 * z2 - 3.0)\n + uHshW[12] * 0.8 * x * (5.0 * z2 - 1.0)\n + uHshW[13] * 2.6 * z * (x2 - y2)\n + uHshW[14] * x * (x2 - 3.0 * y2);\n s += uHshW[15] * 4.0 * x * y * (x2 - y2)\n + uHshW[16] * 3.0 * y * z * (3.0 * x2 - y2)\n + uHshW[17] * 1.5 * x * y * (7.0 * z2 - 1.0)\n + uHshW[18] * 0.95 * y * z * (7.0 * z2 - 3.0)\n + uHshW[19] * 0.125 * (35.0 * z2 * z2 - 30.0 * z2 + 3.0)\n + uHshW[20] * 0.95 * x * z * (7.0 * z2 - 3.0)\n + uHshW[21] * 0.78 * (x2 - y2) * (7.0 * z2 - 1.0)\n + uHshW[22] * 3.0 * x * z * (x2 - 3.0 * y2)\n + uHshW[23] * (x2 * (x2 - 3.0 * y2) - y2 * (3.0 * x2 - y2));\n return s;\n }\n\n // The resting shell: radius along direction n, in shell-local units.\n float hshRadius(vec3 n, out float field){\n field = hshSh(n);\n return uHshBound * uHshSize * (1.0 + uHshAmplitude * field);\n }\n\n // Thin-film interference, as on a soap bubble: a film of index 1.33 and\n // thickness d delays the inner reflection by 2*n*d*cos(theta_t). Each\n // wavelength interferes on its own, which splits white light into bands.\n vec3 hshFilm(float ndv, float field){\n float cosT = sqrt(max(1.0 - (1.0 - ndv * ndv) / (1.33 * 1.33), 0.0));\n float opd = 2.0 * 1.33 * uHshFilm * (1.0 + 0.35 * field) * cosT;\n vec3 film = 0.5 + 0.5 * cos(6.28318530718 * opd / vec3(650.0, 532.0, 450.0));\n float lum = dot(film, vec3(0.299, 0.587, 0.114));\n return mix(film, lum * uHshColor * 1.7 + film * 0.12, uHshTint);\n }\n\n // \u2500\u2500 the target: signed distance in shell-local units (negative inside) \u2500\u2500\n float hshSdf2(vec2 p){\n vec2 uv = p / (2.0 * uHshSdfHalf) + 0.5;\n vec2 c = clamp(uv, 0.0, 1.0);\n return texture2D(uHshSdf, c).r + length((uv - c) * 2.0 * uHshSdfHalf);\n }\n float hshSdf(vec3 p){\n if (uHshMode > 1.5) {\n // an object's own field, baked in its local space\n vec3 q = (uHshSdf3Inv * vec4(p, 1.0)).xyz;\n vec3 uvw = (q - uHshSdf3Min) / uHshSdf3Size; vec3 c = clamp(uvw, 0.0, 1.0);\n return texture(uHshSdf3, c).r + length((uvw - c) * uHshSdf3Size);\n }\n // text / shape: the 2D field extruded to \u00B1depth\n float d2 = hshSdf2(p.xy); float dz = abs(p.z) - uHshDepth;\n vec2 w = max(vec2(d2, dz), 0.0);\n return min(max(d2, dz), 0.0) + length(w);\n }\n vec3 hshSdfGrad(vec3 p){\n float e = 0.012;\n vec3 g = vec3(hshSdf(p + vec3(e, 0, 0)) - hshSdf(p - vec3(e, 0, 0)),\n hshSdf(p + vec3(0, e, 0)) - hshSdf(p - vec3(0, e, 0)),\n hshSdf(p + vec3(0, 0, e)) - hshSdf(p - vec3(0, 0, e)));\n float l = length(g); return l > 1e-6 ? g / l : vec3(0.0, 0.0, 1.0);\n }\n\n // Signed distance from a shell-local point to the shell's CURRENT surface\n // (the resting shell blended with the target by uHshMorph). 'field' is the\n // harmonic value in that direction, for the film.\n // Where a sphere vertex starts its trace: the resting shell point stretched to the\n // target's extent, so a wide word or a long object gets vertices along its whole length\n // instead of everything converging on the part nearest the centre.\n vec3 hshTraceStart(vec3 p0){\n float R0 = uHshBound * uHshSize;\n if (uHshMode > 1.5) {\n vec3 c = uHshSdf3Min + 0.5 * uHshSdf3Size; // the target's centre, in its own space\n vec3 h = uHshSdf3Size * 0.44; // half extents (the baked box is padded 12%)\n vec3 ct = (uHshSdf3Inv * vec4(0.0, 0.0, 0.0, 1.0)).xyz;\n vec3 qt = (uHshSdf3Inv * vec4(p0, 1.0)).xyz;\n qt = c + (qt - ct) * (h / R0);\n return (uHshSdf3Mat * vec4(qt, 1.0)).xyz;\n }\n return p0 * vec3(uHshSdfHalf / R0, max(uHshDepth, 0.05) / R0);\n }\n\n float hshDist(vec3 p, out float field){\n float r = length(p); vec3 n = r > 1e-5 ? p / r : vec3(0.0, 1.0, 0.0);\n float dS = r - hshRadius(n, field);\n return uHshMode > 0.5 && uHshMorph > 0.0 ? mix(dS, hshSdf(p), uHshMorph) : dS;\n }\n";
24
+ /** Declarations + functions: the whole field for a shader that declares nothing itself. */
25
+ export declare const HSH_FIELD_GLSL: string;
26
+ /** The shell's own material: the sphere displaced by the field, traced onto the target when it has one. */
27
+ export declare const SHELL_VERT = "\n uniform float uBreath;\n varying vec3 vNormal;\n varying vec3 vViewDir;\n varying float vField;\n varying vec3 vLocal;\n \n uniform float uHshW[24];\n uniform float uHshAmplitude; uniform float uHshBound; uniform float uHshSize;\n uniform vec3 uHshColor; uniform vec3 uHshRim; uniform float uHshFilm; uniform float uHshTint; uniform float uHshTime;\n uniform float uHshMorph; uniform float uHshMode;\n uniform sampler2D uHshSdf; uniform vec2 uHshSdfHalf; uniform float uHshDepth;\n uniform sampler3D uHshSdf3; uniform vec3 uHshSdf3Min; uniform vec3 uHshSdf3Size; uniform mat4 uHshSdf3Inv; uniform mat4 uHshSdf3Mat;\n\n\n // Real spherical harmonics for l = 1..4, as polynomials in the unit vector,\n // each scaled so its peak is about 1. The CPU animates the 24 weights.\n float hshSh(vec3 n){\n float x = n.x, y = n.y, z = n.z;\n float x2 = x * x, y2 = y * y, z2 = z * z;\n float s = 0.0;\n s += uHshW[0] * y + uHshW[1] * z + uHshW[2] * x;\n s += uHshW[3] * 2.0 * x * y + uHshW[4] * 2.0 * y * z + uHshW[5] * (1.5 * z2 - 0.5)\n + uHshW[6] * 2.0 * x * z + uHshW[7] * (x2 - y2);\n s += uHshW[8] * y * (3.0 * x2 - y2)\n + uHshW[9] * 5.2 * x * y * z\n + uHshW[10] * 0.8 * y * (5.0 * z2 - 1.0)\n + uHshW[11] * 0.5 * z * (5.0 * z2 - 3.0)\n + uHshW[12] * 0.8 * x * (5.0 * z2 - 1.0)\n + uHshW[13] * 2.6 * z * (x2 - y2)\n + uHshW[14] * x * (x2 - 3.0 * y2);\n s += uHshW[15] * 4.0 * x * y * (x2 - y2)\n + uHshW[16] * 3.0 * y * z * (3.0 * x2 - y2)\n + uHshW[17] * 1.5 * x * y * (7.0 * z2 - 1.0)\n + uHshW[18] * 0.95 * y * z * (7.0 * z2 - 3.0)\n + uHshW[19] * 0.125 * (35.0 * z2 * z2 - 30.0 * z2 + 3.0)\n + uHshW[20] * 0.95 * x * z * (7.0 * z2 - 3.0)\n + uHshW[21] * 0.78 * (x2 - y2) * (7.0 * z2 - 1.0)\n + uHshW[22] * 3.0 * x * z * (x2 - 3.0 * y2)\n + uHshW[23] * (x2 * (x2 - 3.0 * y2) - y2 * (3.0 * x2 - y2));\n return s;\n }\n\n // The resting shell: radius along direction n, in shell-local units.\n float hshRadius(vec3 n, out float field){\n field = hshSh(n);\n return uHshBound * uHshSize * (1.0 + uHshAmplitude * field);\n }\n\n // Thin-film interference, as on a soap bubble: a film of index 1.33 and\n // thickness d delays the inner reflection by 2*n*d*cos(theta_t). Each\n // wavelength interferes on its own, which splits white light into bands.\n vec3 hshFilm(float ndv, float field){\n float cosT = sqrt(max(1.0 - (1.0 - ndv * ndv) / (1.33 * 1.33), 0.0));\n float opd = 2.0 * 1.33 * uHshFilm * (1.0 + 0.35 * field) * cosT;\n vec3 film = 0.5 + 0.5 * cos(6.28318530718 * opd / vec3(650.0, 532.0, 450.0));\n float lum = dot(film, vec3(0.299, 0.587, 0.114));\n return mix(film, lum * uHshColor * 1.7 + film * 0.12, uHshTint);\n }\n\n // \u2500\u2500 the target: signed distance in shell-local units (negative inside) \u2500\u2500\n float hshSdf2(vec2 p){\n vec2 uv = p / (2.0 * uHshSdfHalf) + 0.5;\n vec2 c = clamp(uv, 0.0, 1.0);\n return texture2D(uHshSdf, c).r + length((uv - c) * 2.0 * uHshSdfHalf);\n }\n float hshSdf(vec3 p){\n if (uHshMode > 1.5) {\n // an object's own field, baked in its local space\n vec3 q = (uHshSdf3Inv * vec4(p, 1.0)).xyz;\n vec3 uvw = (q - uHshSdf3Min) / uHshSdf3Size; vec3 c = clamp(uvw, 0.0, 1.0);\n return texture(uHshSdf3, c).r + length((uvw - c) * uHshSdf3Size);\n }\n // text / shape: the 2D field extruded to \u00B1depth\n float d2 = hshSdf2(p.xy); float dz = abs(p.z) - uHshDepth;\n vec2 w = max(vec2(d2, dz), 0.0);\n return min(max(d2, dz), 0.0) + length(w);\n }\n vec3 hshSdfGrad(vec3 p){\n float e = 0.012;\n vec3 g = vec3(hshSdf(p + vec3(e, 0, 0)) - hshSdf(p - vec3(e, 0, 0)),\n hshSdf(p + vec3(0, e, 0)) - hshSdf(p - vec3(0, e, 0)),\n hshSdf(p + vec3(0, 0, e)) - hshSdf(p - vec3(0, 0, e)));\n float l = length(g); return l > 1e-6 ? g / l : vec3(0.0, 0.0, 1.0);\n }\n\n // Signed distance from a shell-local point to the shell's CURRENT surface\n // (the resting shell blended with the target by uHshMorph). 'field' is the\n // harmonic value in that direction, for the film.\n // Where a sphere vertex starts its trace: the resting shell point stretched to the\n // target's extent, so a wide word or a long object gets vertices along its whole length\n // instead of everything converging on the part nearest the centre.\n vec3 hshTraceStart(vec3 p0){\n float R0 = uHshBound * uHshSize;\n if (uHshMode > 1.5) {\n vec3 c = uHshSdf3Min + 0.5 * uHshSdf3Size; // the target's centre, in its own space\n vec3 h = uHshSdf3Size * 0.44; // half extents (the baked box is padded 12%)\n vec3 ct = (uHshSdf3Inv * vec4(0.0, 0.0, 0.0, 1.0)).xyz;\n vec3 qt = (uHshSdf3Inv * vec4(p0, 1.0)).xyz;\n qt = c + (qt - ct) * (h / R0);\n return (uHshSdf3Mat * vec4(qt, 1.0)).xyz;\n }\n return p0 * vec3(uHshSdfHalf / R0, max(uHshDepth, 0.05) / R0);\n }\n\n float hshDist(vec3 p, out float field){\n float r = length(p); vec3 n = r > 1e-5 ? p / r : vec3(0.0, 1.0, 0.0);\n float dS = r - hshRadius(n, field);\n return uHshMode > 0.5 && uHshMorph > 0.0 ? mix(dS, hshSdf(p), uHshMorph) : dS;\n }\n\n\n vec3 shellPoint(vec3 n, out float f){ return n * hshRadius(n, f); }\n\n void main(){\n vec3 n = normalize(position);\n float f, f1, f2;\n vec3 p0 = shellPoint(n, f);\n\n // normal from two nearby points on the displaced surface\n vec3 up = abs(n.y) > 0.99 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 t1 = normalize(cross(n, up));\n vec3 t2 = cross(n, t1);\n vec3 p1 = shellPoint(normalize(n + t1 * 0.01), f1);\n vec3 p2 = shellPoint(normalize(n + t2 * 0.01), f2);\n vec3 nrm = normalize(cross(p1 - p0, p2 - p0));\n if (dot(nrm, n) < 0.0) nrm = -nrm;\n\n vec3 p = p0; vec3 N = nrm;\n if (uHshMode > 0.5 && uHshMorph > 0.0) {\n // trace the vertex onto the target surface along the field's gradient\n vec3 q = hshTraceStart(p0);\n for (int i = 0; i < 12; i++) { float d = hshSdf(q); q -= d * hshSdfGrad(q) * 0.85; }\n vec3 g = hshSdfGrad(q);\n // the harmonics keep breathing on the target, along its normal\n q += g * uHshBound * uHshAmplitude * uBreath * f;\n p = mix(p0, q, uHshMorph);\n N = normalize(mix(nrm, g, uHshMorph));\n }\n\n vLocal = p;\n vField = f;\n vec4 mv = modelViewMatrix * vec4(p, 1.0);\n vNormal = normalize(normalMatrix * N);\n vViewDir = normalize(-mv.xyz);\n gl_Position = projectionMatrix * mv;\n }\n";
28
+ export declare const SHELL_FRAG = "\n uniform float uOpacity;\n uniform float uIntensity;\n uniform float uNodalLines;\n uniform float uWeb;\n varying vec3 vNormal;\n varying vec3 vViewDir;\n varying float vField;\n varying vec3 vLocal;\n \n uniform float uHshW[24];\n uniform float uHshAmplitude; uniform float uHshBound; uniform float uHshSize;\n uniform vec3 uHshColor; uniform vec3 uHshRim; uniform float uHshFilm; uniform float uHshTint; uniform float uHshTime;\n uniform float uHshMorph; uniform float uHshMode;\n uniform sampler2D uHshSdf; uniform vec2 uHshSdfHalf; uniform float uHshDepth;\n uniform sampler3D uHshSdf3; uniform vec3 uHshSdf3Min; uniform vec3 uHshSdf3Size; uniform mat4 uHshSdf3Inv; uniform mat4 uHshSdf3Mat;\n\n\n // Real spherical harmonics for l = 1..4, as polynomials in the unit vector,\n // each scaled so its peak is about 1. The CPU animates the 24 weights.\n float hshSh(vec3 n){\n float x = n.x, y = n.y, z = n.z;\n float x2 = x * x, y2 = y * y, z2 = z * z;\n float s = 0.0;\n s += uHshW[0] * y + uHshW[1] * z + uHshW[2] * x;\n s += uHshW[3] * 2.0 * x * y + uHshW[4] * 2.0 * y * z + uHshW[5] * (1.5 * z2 - 0.5)\n + uHshW[6] * 2.0 * x * z + uHshW[7] * (x2 - y2);\n s += uHshW[8] * y * (3.0 * x2 - y2)\n + uHshW[9] * 5.2 * x * y * z\n + uHshW[10] * 0.8 * y * (5.0 * z2 - 1.0)\n + uHshW[11] * 0.5 * z * (5.0 * z2 - 3.0)\n + uHshW[12] * 0.8 * x * (5.0 * z2 - 1.0)\n + uHshW[13] * 2.6 * z * (x2 - y2)\n + uHshW[14] * x * (x2 - 3.0 * y2);\n s += uHshW[15] * 4.0 * x * y * (x2 - y2)\n + uHshW[16] * 3.0 * y * z * (3.0 * x2 - y2)\n + uHshW[17] * 1.5 * x * y * (7.0 * z2 - 1.0)\n + uHshW[18] * 0.95 * y * z * (7.0 * z2 - 3.0)\n + uHshW[19] * 0.125 * (35.0 * z2 * z2 - 30.0 * z2 + 3.0)\n + uHshW[20] * 0.95 * x * z * (7.0 * z2 - 3.0)\n + uHshW[21] * 0.78 * (x2 - y2) * (7.0 * z2 - 1.0)\n + uHshW[22] * 3.0 * x * z * (x2 - 3.0 * y2)\n + uHshW[23] * (x2 * (x2 - 3.0 * y2) - y2 * (3.0 * x2 - y2));\n return s;\n }\n\n // The resting shell: radius along direction n, in shell-local units.\n float hshRadius(vec3 n, out float field){\n field = hshSh(n);\n return uHshBound * uHshSize * (1.0 + uHshAmplitude * field);\n }\n\n // Thin-film interference, as on a soap bubble: a film of index 1.33 and\n // thickness d delays the inner reflection by 2*n*d*cos(theta_t). Each\n // wavelength interferes on its own, which splits white light into bands.\n vec3 hshFilm(float ndv, float field){\n float cosT = sqrt(max(1.0 - (1.0 - ndv * ndv) / (1.33 * 1.33), 0.0));\n float opd = 2.0 * 1.33 * uHshFilm * (1.0 + 0.35 * field) * cosT;\n vec3 film = 0.5 + 0.5 * cos(6.28318530718 * opd / vec3(650.0, 532.0, 450.0));\n float lum = dot(film, vec3(0.299, 0.587, 0.114));\n return mix(film, lum * uHshColor * 1.7 + film * 0.12, uHshTint);\n }\n\n // \u2500\u2500 the target: signed distance in shell-local units (negative inside) \u2500\u2500\n float hshSdf2(vec2 p){\n vec2 uv = p / (2.0 * uHshSdfHalf) + 0.5;\n vec2 c = clamp(uv, 0.0, 1.0);\n return texture2D(uHshSdf, c).r + length((uv - c) * 2.0 * uHshSdfHalf);\n }\n float hshSdf(vec3 p){\n if (uHshMode > 1.5) {\n // an object's own field, baked in its local space\n vec3 q = (uHshSdf3Inv * vec4(p, 1.0)).xyz;\n vec3 uvw = (q - uHshSdf3Min) / uHshSdf3Size; vec3 c = clamp(uvw, 0.0, 1.0);\n return texture(uHshSdf3, c).r + length((uvw - c) * uHshSdf3Size);\n }\n // text / shape: the 2D field extruded to \u00B1depth\n float d2 = hshSdf2(p.xy); float dz = abs(p.z) - uHshDepth;\n vec2 w = max(vec2(d2, dz), 0.0);\n return min(max(d2, dz), 0.0) + length(w);\n }\n vec3 hshSdfGrad(vec3 p){\n float e = 0.012;\n vec3 g = vec3(hshSdf(p + vec3(e, 0, 0)) - hshSdf(p - vec3(e, 0, 0)),\n hshSdf(p + vec3(0, e, 0)) - hshSdf(p - vec3(0, e, 0)),\n hshSdf(p + vec3(0, 0, e)) - hshSdf(p - vec3(0, 0, e)));\n float l = length(g); return l > 1e-6 ? g / l : vec3(0.0, 0.0, 1.0);\n }\n\n // Signed distance from a shell-local point to the shell's CURRENT surface\n // (the resting shell blended with the target by uHshMorph). 'field' is the\n // harmonic value in that direction, for the film.\n // Where a sphere vertex starts its trace: the resting shell point stretched to the\n // target's extent, so a wide word or a long object gets vertices along its whole length\n // instead of everything converging on the part nearest the centre.\n vec3 hshTraceStart(vec3 p0){\n float R0 = uHshBound * uHshSize;\n if (uHshMode > 1.5) {\n vec3 c = uHshSdf3Min + 0.5 * uHshSdf3Size; // the target's centre, in its own space\n vec3 h = uHshSdf3Size * 0.44; // half extents (the baked box is padded 12%)\n vec3 ct = (uHshSdf3Inv * vec4(0.0, 0.0, 0.0, 1.0)).xyz;\n vec3 qt = (uHshSdf3Inv * vec4(p0, 1.0)).xyz;\n qt = c + (qt - ct) * (h / R0);\n return (uHshSdf3Mat * vec4(qt, 1.0)).xyz;\n }\n return p0 * vec3(uHshSdfHalf / R0, max(uHshDepth, 0.05) / R0);\n }\n\n float hshDist(vec3 p, out float field){\n float r = length(p); vec3 n = r > 1e-5 ? p / r : vec3(0.0, 1.0, 0.0);\n float dS = r - hshRadius(n, field);\n return uHshMode > 0.5 && uHshMorph > 0.0 ? mix(dS, hshSdf(p), uHshMorph) : dS;\n }\n\n\n void main(){\n vec3 N = normalize(vNormal);\n vec3 V = normalize(vViewDir);\n float ndv = abs(dot(N, V));\n\n // the film is thicker where the harmonic pushes the shell out, so the colour bands follow the shape\n vec3 film = hshFilm(ndv, vField);\n\n float fres = pow(1.0 - ndv, 3.0);\n vec3 col = uHshColor * 0.25 + film * (0.2 + 0.8 * fres);\n col = mix(col, uHshRim, fres * 0.45);\n\n // nodal lines: where the harmonic field crosses zero\n float nd = abs(vField) / max(fwidth(vField), 1e-4);\n float nodal = (1.0 - smoothstep(0.5, 1.5, nd)) * uNodalLines;\n col += uHshRim * nodal * 1.5;\n\n float a = (0.06 + 0.9 * fres + nodal * 0.8) * uOpacity;\n // webbing between letters: pixels that are not on the target fade out as the morph completes\n if (uHshMode > 0.5 && uHshMorph > 0.0) { float d = abs(hshSdf(vLocal)); a *= 1.0 - uHshMorph * smoothstep(uWeb, uWeb * 3.0, d); }\n if (a < 0.003) discard;\n gl_FragColor = vec4(col * uIntensity, a);\n }\n";
29
+ export type HshUniforms = Record<string, THREE.IUniform>;
30
+ /** Fresh uniform objects for one shell (the shell writes them every frame; effects read them). */
31
+ export declare function createShellUniforms(): HshUniforms;
32
+ /** The keys an effect copies from a shell into its own uniforms (everything but the time, which it keeps). */
33
+ export declare const HSH_SHARED_KEYS: readonly ["uHshW", "uHshAmplitude", "uHshBound", "uHshSize", "uHshColor", "uHshRim", "uHshFilm", "uHshTint", "uHshMorph", "uHshMode", "uHshSdf", "uHshSdfHalf", "uHshDepth", "uHshSdf3", "uHshSdf3Min", "uHshSdf3Size", "uHshSdf3Inv", "uHshSdf3Mat"];
34
+ /** Copy a shell's current values into another uniform set (objects are shared by reference, scalars by value). */
35
+ export declare function copyShellUniforms(from: HshUniforms, to: HshUniforms): void;
36
+ export interface ShellField {
37
+ /** The shell's root group (its world matrix is the field's frame). */
38
+ root: Object3D;
39
+ uniforms: HshUniforms;
40
+ /** World → shell-local, refreshed by the shell every frame. */
41
+ inv: THREE.Matrix4;
42
+ /** The object the shell is wrapping right now (mode object), so it can be left out of the inside look. */
43
+ target: Object3D | null;
44
+ }
45
+ export declare function registerShellField(f: ShellField): void;
46
+ export declare function unregisterShellField(f: ShellField): void;
47
+ export declare const shellFields: () => ReadonlySet<ShellField>;
48
+ /** The shell whose centre is nearest a world point (what `inShell` reacts to), or null when the scene has none. */
49
+ export declare function nearestShellField(worldPos: THREE.Vector3): ShellField | null;
50
+ export declare const SHELL_SHAPES: readonly ["star", "heart", "ring", "hexagon", "triangle", "cross", "disc", "square", "diamond", "pentagon", "octagon", "sparkle", "hexstar", "crescent", "drop", "bolt", "arrow", "cloud", "flower", "gear", "shield", "leaf", "capsule", "infinity", "chevron", "hourglass", "clover", "spade", "sun", "halfmoon"];
51
+ export type ShellShape = (typeof SHELL_SHAPES)[number];
52
+ /** CSS font families the `font` option maps to (the page's own fonts, with system fallbacks). */
53
+ export declare const SHELL_FONTS: Record<string, string>;
54
+ export interface Sdf2 {
55
+ tex: THREE.DataTexture;
56
+ half: number;
57
+ }
58
+ /**
59
+ * The 2D field of a word or a shape, sized to the shell: `half` is the half-width it
60
+ * spans in shell-local units (the shell's resting radius, a little more).
61
+ * Text waits for the page font once (document.fonts), then draws.
62
+ */
63
+ export declare function bakeShapeSdf(kind: 'text' | ShellShape, text: string, font: string, half: number): Promise<Sdf2 | null>;
64
+ export interface Sdf3 {
65
+ tex: THREE.Data3DTexture;
66
+ min: THREE.Vector3;
67
+ size: THREE.Vector3;
68
+ }
69
+ /**
70
+ * The object's signed distance field in its root-local space: all its meshes merged
71
+ * (position only, see mergedPositions), sampled on a 48³ grid with the BVH's
72
+ * closest-point query, sign from the hit face. Baked in slices so the page stays
73
+ * responsive; cached on the root until its geometry changes. ~100–300 ms for a
74
+ * typical model on a desktop CPU — do it at load (pre-bake), never on trigger.
75
+ */
76
+ export declare function bakeObjectSdf(root: Object3D): Promise<Sdf3 | null>;
77
+ //# sourceMappingURL=harmonicShellField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harmonicShellField.d.ts","sourceRoot":"","sources":["../../../src/components/effects/harmonicShellField.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAgBtC,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,YAAY,CAAC;IACvE,IAAI,EAAE,YAAY,CAAC;CACtB;AAED,2FAA2F;AAC3F,wBAAgB,mBAAmB,IAAI,aAAa,CAUnD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAe1H;AAID,iHAAiH;AACjH,eAAO,MAAM,cAAc,0fAO1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,miJAiG3B,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,cAAc,QAAmC,CAAC;AAE/D,2GAA2G;AAC3G,eAAO,MAAM,UAAU,y9MA2CtB,CAAC;AAEF,eAAO,MAAM,UAAU,quMAkCtB,CAAC;AAKF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;AAczD,kGAAkG;AAClG,wBAAgB,mBAAmB,IAAI,WAAW,CAUjD;AAED,8GAA8G;AAC9G,eAAO,MAAM,eAAe,uPAGlB,CAAC;AAEX,kHAAkH;AAClH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,QAMnE;AAID,MAAM,WAAW,UAAU;IACvB,sEAAsE;IACtE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,+DAA+D;IAC/D,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC;IACnB,0GAA0G;IAC1G,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3B;AAID,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,UAAU,QAAoB;AACpE,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,UAAU,QAAuB;AACzE,eAAO,MAAM,WAAW,QAAO,WAAW,CAAC,UAAU,CAAW,CAAC;AAGjE,mHAAmH;AACnH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,GAAG,UAAU,GAAG,IAAI,CAQ5E;AAID,eAAO,MAAM,YAAY,qTAKf,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,iGAAiG;AACjG,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9C,CAAC;AAsBF,MAAM,WAAW,IAAI;IAAG,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AA2G9D;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAK5H;AAID,MAAM,WAAW,IAAI;IAAG,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC;IAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC;IAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAA;CAAE;AA8C3F;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CA4CxE"}