<!-- SOLUV · part 440 -->
ualDepth, HalfFloatType, IntType, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NoBlending, NoColorSpace, NoToneMapping, NormalBlending, NotEqualCompare, NotEqualDepth, ObjectSpaceNormalMap, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, Plane, PlaneGeometry, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RawShaderMaterial, RedFormat, RedIntegerFormat, ReinhardToneMapping, RepeatWrapping, ReverseSubtractEquation, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, ShaderChunk, ShaderLib, ShaderMaterial, ShortType, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, SubtractEquation, SubtractiveBlending, TangentSpaceNormalMap, Texture, Uint16BufferAttribute, Uint32BufferAttribute, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebXRController, ZeroFactor, createCanvasElement, error, log, warn, warnOnce };


===== FILE: public/soluv/preview/word-sky.js =====
/*
 * Word Sky — a 3D field of millions of words that stays readable at every zoom ("semantic zoom").
 * Plain ES module, no build step. Depends only on ./vendor/three.module.js (+ three.core.js) and the
 * vendored Roboto Condensed woff2 files. Mount with:
 *   <script type="module" src="/word-sky/word-sky.js"></script><word-sky data="/word-sky/data/"></word-sky>
 * or programmatically: import { mountWordSky } from './word-sky.js'; const sky = await mountWordSky(el, { data: './data/' });
 *
 * Levels (each label is shown only while its glyphs are >= 12 CSS px tall):
 *   L4 book/galaxy title + key words (screen-clamped size)
 *   L3 constellation (= conversation / newspaper page) HEADLINE + key words (screen-clamped size)
 *   L2 two subheads per page (world-sized, shown once >= 12px)
 *   L1 each message's first few words (world-sized)
 *   L0 the full message text (world-sized)
 * Everything not shown as text is a star, a reply line or a page outline. Text = instanced SDF glyph quads,
 * one draw call, hard budget of MAX_GLYPHS per frame. Labels never overlap (screen-space collision grid).
 */
import * as THREE from './vendor/three.module.js';

const MODULE_BASE = new URL('.', import.meta.url);
const MAX_GLYPHS = 6000;
/* ===== THE LAW: Minimum 0.13 (verbatim rule from Solid's saga.js; 0.13 = an avatar's eye) ===== */
if (typeof window !== 'undefined' && window.MINIMUM === undefined) window.MINIMUM = 0.13;
const MINIMUM = (typeof window !== 'undefined' && window.MINIMUM) || 0.13;
function applyMinimum(obj) {
  if (!obj) return obj;
  const box = new THREE.Box3().setFromObject(obj), size = new THREE.Vector3(); box.getSize(size);
  const s = Math.min(size.x, size.y, size.z);
  if (s > 0 && s < MINIMUM) obj.scale.multiplyScalar(MINIMUM / s);
  return obj;
}
// Scene units: the body-text em (glyph height) is exactly MINIMUM world units. All layout data is authored in em units (1 em = 1 layout
// unit) and the whole world group is scaled by WS, so the smallest glyph is eye-sized and everything else is larger.
const WS = MINIMUM;
const MAP_BLOCKS = 2000, SKY_CELL = 50; // map size and grid cell in world blocks; the sky has no ceiling
const MIN_PX = 12;           // readable floor (CSS px of em)
const FADE_LO = 12;          // crossfade window starts AT the floor, so nothing shown at >=50% opacity is under 12px
