@zkmake/three-textures 0.1.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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +2 -0
- package/dist/lab-CN1v1x-y.d.ts +177 -0
- package/dist/lab-CozZhJaq.js +864 -0
- package/dist/lab-CozZhJaq.js.map +1 -0
- package/dist/mount-Bk5wVa_1.d.ts +25 -0
- package/dist/mount-D6SH40yP.js +507 -0
- package/dist/mount-D6SH40yP.js.map +1 -0
- package/dist/react.d.ts +14 -0
- package/dist/react.js +51 -0
- package/dist/react.js.map +1 -0
- package/dist/ui.d.ts +28 -0
- package/dist/ui.js +2 -0
- package/package.json +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lab-CozZhJaq.js","names":[],"sources":["../src/core/discover.ts","../src/core/kinds.ts","../src/core/names.ts","../src/core/readback.ts","../src/core/store.ts","../src/core/swap.ts","../src/core/lab.ts"],"sourcesContent":["/**\n * Find every texture a scene draws with: each material's texture slots (any property holding a\n * texture, not only three's named maps), its uniforms, and the scene's background and\n * environment. Textures are grouped by their `TextureSource`, the image data they upload: clones share\n * it, so a swap has to reach all of them.\n */\nimport type { Material, Object3D, Texture } from \"three\";\n\n/** A texture's `Source`: the image data it uploads, shared by its clones. */\nexport type TextureSource = Texture[\"source\"];\n\n/** Somewhere a texture is bound: `owner[key]`. A uniform's owner is the uniform, `{ value }`. */\nexport type TextureRef = {\n owner: Record<string, unknown>;\n key: string;\n /** The material to recompile after rebinding, when the owner is one of its slots or uniforms. */\n material: Material | null;\n};\n\nexport type Found = {\n source: TextureSource;\n textures: Set<Texture>;\n refs: TextureRef[];\n /** `material.slot` names, for a fallback label and the \"used by\" count. */\n slots: Set<string>;\n materials: Set<Material>;\n};\n\nconst isTexture = (value: unknown): value is Texture =>\n value !== null && typeof value === \"object\" && (value as Texture).isTexture === true;\n\nconst add = (found: Map<TextureSource, Found>, texture: Texture, ref: TextureRef, slot: string) => {\n let entry = found.get(texture.source);\n\n if (!entry) {\n entry = {\n source: texture.source,\n textures: new Set(),\n refs: [],\n slots: new Set(),\n materials: new Set(),\n };\n found.set(texture.source, entry);\n }\n\n entry.textures.add(texture);\n entry.refs.push(ref);\n entry.slots.add(slot);\n\n if (ref.material) {\n entry.materials.add(ref.material);\n }\n};\n\nconst scanMaterial = (found: Map<TextureSource, Found>, material: Material) => {\n const record = material as unknown as Record<string, unknown>;\n const label = material.name || material.type;\n\n for (const key of Object.keys(record)) {\n const value = record[key];\n\n if (isTexture(value)) {\n add(found, value, { owner: record, key, material }, `${label}.${key}`);\n }\n }\n\n const uniforms = (material as { uniforms?: Record<string, { value?: unknown } | undefined> })\n .uniforms;\n\n for (const [name, uniform] of Object.entries(uniforms ?? {})) {\n if (uniform && isTexture(uniform.value)) {\n add(found, uniform.value, { owner: uniform, key: \"value\", material }, `${label}.${name}`);\n }\n }\n};\n\n/** Every texture under `root`, grouped by source. Materials shared by many meshes are read once. */\nexport const findTextures = (root: Object3D): Map<TextureSource, Found> => {\n const found = new Map<TextureSource, Found>();\n const seen = new Set<Material>();\n const scene = root as unknown as Record<string, unknown>;\n\n for (const key of [\"background\", \"environment\"]) {\n const value = scene[key];\n\n if (isTexture(value)) {\n add(found, value, { owner: scene, key, material: null }, `scene.${key}`);\n }\n }\n\n root.traverse((object) => {\n const held = (object as { material?: Material | Material[] }).material;\n\n for (const material of Array.isArray(held) ? held : held ? [held] : []) {\n if (!seen.has(material)) {\n seen.add(material);\n scanMaterial(found, material);\n }\n }\n });\n\n return found;\n};\n","/**\n * What a texture is, for swapping: an image three uploads as-is (swapped in place), GPU-ready\n * data (compressed or raw, swapped by rebinding), or something the panel can only list.\n */\nimport type { Texture } from \"three\";\n\nexport type TextureKind = \"image\" | \"compressed\" | \"data\" | \"unsupported\";\n\ntype Flags = {\n isCompressedTexture?: boolean;\n isCompressedArrayTexture?: boolean;\n isCompressedCubeTexture?: boolean;\n isDataTexture?: boolean;\n isData3DTexture?: boolean;\n isDataArrayTexture?: boolean;\n isCubeTexture?: boolean;\n isVideoTexture?: boolean;\n isDepthTexture?: boolean;\n isFramebufferTexture?: boolean;\n isRenderTargetTexture?: boolean;\n isArrayTexture?: boolean;\n};\n\n/** An element three uploads with `texImage2D` as it is: what an image swap can replace. */\nexport const isImageLike = (data: unknown): boolean => {\n if (data === null || typeof data !== \"object\") {\n return false;\n }\n\n const hasSize = \"width\" in data && \"height\" in data;\n const isElement =\n (typeof HTMLImageElement !== \"undefined\" && data instanceof HTMLImageElement) ||\n (typeof HTMLCanvasElement !== \"undefined\" && data instanceof HTMLCanvasElement) ||\n (typeof ImageBitmap !== \"undefined\" && data instanceof ImageBitmap) ||\n (typeof OffscreenCanvas !== \"undefined\" && data instanceof OffscreenCanvas);\n\n // Raw data (`{ data, width, height }`) has a typed array; an element or bitmap doesn't.\n return isElement || (hasSize && !(\"data\" in data) && !(\"mipmaps\" in data));\n};\n\nexport const kindOf = (texture: Texture): TextureKind => {\n const flags = texture as unknown as Flags;\n\n if (\n flags.isCompressedArrayTexture ||\n flags.isCompressedCubeTexture ||\n flags.isData3DTexture ||\n flags.isDataArrayTexture ||\n flags.isCubeTexture ||\n flags.isVideoTexture ||\n flags.isDepthTexture ||\n flags.isFramebufferTexture ||\n flags.isRenderTargetTexture ||\n flags.isArrayTexture\n ) {\n return \"unsupported\";\n }\n\n if (flags.isCompressedTexture) {\n return \"compressed\";\n }\n\n if (flags.isDataTexture) {\n return \"data\";\n }\n\n return isImageLike(texture.source.data) ? \"image\" : \"unsupported\";\n};\n\n/** Pixel size of the base level. */\nexport const sizeOf = (texture: Texture): { width: number; height: number } => {\n const image = texture.source.data as { width?: number; height?: number } | null;\n const base = (texture as unknown as { mipmaps?: { width: number; height: number }[] })\n .mipmaps?.[0];\n\n return {\n width: base?.width ?? image?.width ?? 0,\n height: base?.height ?? image?.height ?? 0,\n };\n};\n\n/** GPU compressed format families, by three's (GL-valued) format constants. */\nconst FAMILIES: [number, number, string][] = [\n [33776, 33779, \"BC1–3\"],\n [35840, 35843, \"PVRTC\"],\n [35916, 35919, \"BC1–3\"],\n [36196, 36196, \"ETC1\"],\n [36283, 36286, \"BC4–5\"],\n [36492, 36495, \"BC6–7\"],\n [37488, 37497, \"ETC2\"],\n [37808, 37853, \"ASTC\"],\n];\n\n/** A short format label: `ASTC`, `ETC2`, `RGBA` data, or the image's own. */\nexport const formatOf = (texture: Texture): string => {\n const kind = kindOf(texture);\n\n if (kind === \"compressed\") {\n const format = texture.format as number;\n const family = FAMILIES.find(([low, high]) => format >= low && format <= high);\n\n return family ? family[2] : \"compressed\";\n }\n\n if (kind === \"data\") {\n return \"data\";\n }\n\n const data = texture.source.data as { src?: string; currentSrc?: string } | null;\n const src = data?.currentSrc || data?.src || \"\";\n const extension = /\\.([a-z0-9]+)(?:[?#]|$)/i.exec(src)?.[1]?.toLowerCase();\n\n return extension ?? (data && \"getContext\" in data ? \"canvas\" : \"image\");\n};\n","import type { Texture } from \"three\";\n\n/** Vite's default asset name is `[name]-[hash][ext]` with an 8-character base64url hash. */\nconst VITE_HASH = /-[A-Za-z0-9_-]{8}(\\.[^.]+)$/;\n\n/** The file name at the end of a URL, query and hash dropped, bundler hash stripped. */\nexport const fileNameOf = (url: string): string | null => {\n if (url.startsWith(\"data:\") || url.startsWith(\"blob:\")) {\n return null;\n }\n\n const last = decodeURIComponent(url.split(/[?#]/)[0]!.split(\"/\").pop() ?? \"\");\n\n return last ? last.replace(VITE_HASH, \"$1\") : null;\n};\n\n/** The URL an image texture was loaded from, when it has one. */\nexport const sourceUrlOf = (texture: Texture): string | null => {\n const data = texture.source.data as { currentSrc?: string; src?: string } | null;\n const url = data?.currentSrc || data?.src;\n\n return typeof url === \"string\" && url.length > 0 ? url : null;\n};\n\n/** A label without its extension, for a row: `bunny-baked.webp` reads as `bunny-baked`. */\nexport const stem = (file: string) => file.replace(/\\.[^.]+$/, \"\");\n","/**\n * Read a texture back from the GPU as pixels: the one way to see (and save) a compressed, data or\n * generated texture, which has no file behind it. WebGL only.\n *\n * The texture is drawn onto a quad in a render target the size asked for, sampled raw (no uv\n * transform), and read back. Two corrections make the PNG a file an artist can edit and upload\n * back unchanged:\n * - Rows: three uploads an image with `flipY` bottom row first, so its readback is flipped back;\n * a `flipY: false` texture (compressed, data, glTF) is written in the order it was uploaded.\n * - Colour: an sRGB texture samples as linear, so it's encoded back to sRGB bytes.\n */\nimport {\n GLSL3,\n Mesh,\n NoColorSpace,\n OrthographicCamera,\n PlaneGeometry,\n RawShaderMaterial,\n RGBAFormat,\n SRGBColorSpace,\n type Texture,\n UnsignedByteType,\n type WebGLRenderer,\n WebGLRenderTarget,\n} from \"three\";\n\nconst VERTEX = /* glsl */ `\nin vec3 position;\nin vec2 uv;\nout vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position.xy, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT = /* glsl */ `\nprecision highp float;\nuniform sampler2D map;\nuniform bool encodeSRGB;\nin vec2 vUv;\nout vec4 color;\n\nvec3 toSRGB(vec3 linear) {\n return mix(linear * 12.92, 1.055 * pow(linear, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, linear));\n}\n\nvoid main() {\n vec4 texel = texture(map, vUv);\n\n color = encodeSRGB ? vec4(toSRGB(texel.rgb), texel.a) : texel;\n}\n`;\n\n/** WebGL ignores `flipY` for an `ImageBitmap`: it always uploads top row first. */\nexport const uploadsFlipped = (texture: Texture) =>\n texture.flipY &&\n !(typeof ImageBitmap !== \"undefined\" && texture.source.data instanceof ImageBitmap);\n\nlet quad: Mesh<PlaneGeometry, RawShaderMaterial> | null = null;\nconst camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\nconst quadFor = (texture: Texture) => {\n quad ??= new Mesh(\n new PlaneGeometry(2, 2),\n new RawShaderMaterial({\n glslVersion: GLSL3,\n vertexShader: VERTEX,\n fragmentShader: FRAGMENT,\n uniforms: { map: { value: null }, encodeSRGB: { value: false } },\n depthTest: false,\n depthWrite: false,\n }),\n );\n quad.frustumCulled = false;\n quad.material.uniforms.map!.value = texture;\n quad.material.uniforms.encodeSRGB!.value = texture.colorSpace === SRGBColorSpace;\n\n return quad;\n};\n\n/** Pixels of `texture` at `width × height`, top row first, as they'd be saved to a file. */\nexport const readTexture = (\n renderer: WebGLRenderer,\n texture: Texture,\n width: number,\n height: number,\n): ImageData => {\n const target = new WebGLRenderTarget(width, height, {\n type: UnsignedByteType,\n format: RGBAFormat,\n colorSpace: NoColorSpace,\n depthBuffer: false,\n });\n const previous = renderer.getRenderTarget();\n const xr = renderer.xr.enabled;\n const autoClear = renderer.autoClear;\n const pixels = new Uint8Array(width * height * 4);\n\n try {\n renderer.xr.enabled = false;\n renderer.autoClear = true;\n renderer.setRenderTarget(target);\n renderer.render(quadFor(texture), camera);\n renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);\n } finally {\n renderer.setRenderTarget(previous);\n renderer.xr.enabled = xr;\n renderer.autoClear = autoClear;\n target.dispose();\n quad!.material.uniforms.map!.value = null;\n }\n\n // The render target's row 0 is the texture's first uploaded row. A `flipY` texture uploaded its\n // image bottom row first, so turning it back over gives the image; otherwise keep the order.\n const out = new ImageData(width, height);\n const row = width * 4;\n const flipped = uploadsFlipped(texture);\n\n for (let y = 0; y < height; y += 1) {\n const from = flipped ? height - 1 - y : y;\n\n out.data.set(pixels.subarray(from * row, from * row + row), y * row);\n }\n\n return out;\n};\n\n/** `readTexture` as a PNG. */\nexport const readTextureBlob = async (\n renderer: WebGLRenderer,\n texture: Texture,\n width: number,\n height: number,\n): Promise<Blob> => {\n const canvas = document.createElement(\"canvas\");\n\n canvas.width = width;\n canvas.height = height;\n canvas.getContext(\"2d\")!.putImageData(readTexture(renderer, texture, width, height), 0, 0);\n\n return new Promise((resolve, reject) =>\n canvas.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(\"toBlob failed\"))),\n \"image/png\",\n ),\n );\n};\n\n/** Whether this renderer can read textures back (WebGL, not WebGPU). */\nexport const canReadBack = (renderer: unknown): renderer is WebGLRenderer =>\n renderer !== null &&\n typeof renderer === \"object\" &&\n typeof (renderer as WebGLRenderer).readRenderTargetPixels === \"function\" &&\n (renderer as { isWebGLRenderer?: boolean }).isWebGLRenderer === true;\n","/**\n * Where swaps survive a reload. IndexedDB by default: painted textures are megabytes each, past\n * what `localStorage` holds, and a live-linked file's handle can be kept too (handles clone into\n * IndexedDB; they can't be stringified).\n */\n\nexport type StoredSwap = {\n blob: Blob;\n fileName: string | null;\n showingOriginal: boolean;\n /** A live-linked file, to resume after a reload (the browser asks for permission again). */\n handle?: FileSystemFileHandleLike | undefined;\n};\n\n/** The slice of the File System Access API's file handle the live link uses. */\nexport type FileSystemFileHandleLike = {\n name: string;\n getFile(): Promise<File>;\n queryPermission?(options: { mode: \"read\" }): Promise<PermissionState>;\n requestPermission?(options: { mode: \"read\" }): Promise<PermissionState>;\n};\n\nexport type SwapStore = {\n get(id: string): Promise<StoredSwap | undefined>;\n set(id: string, swap: StoredSwap): Promise<void>;\n delete(id: string): Promise<void>;\n clear(): Promise<void>;\n};\n\n/** A store that lives as long as the page: tests, or `storageKey: null`. */\nexport const memoryStore = (): SwapStore => {\n const swaps = new Map<string, StoredSwap>();\n\n return {\n get: async (id) => swaps.get(id),\n set: async (id, swap) => {\n swaps.set(id, swap);\n },\n delete: async (id) => {\n swaps.delete(id);\n },\n clear: async () => {\n swaps.clear();\n },\n };\n};\n\nconst DATABASE = \"zkmake-three-textures\";\n/** Sorts after every character a key can hold: the top of a key-prefix range. */\nconst LAST_CHAR = String.fromCharCode(0xffff);\nconst STORE = \"swaps\";\n\nconst request = <T>(req: IDBRequest<T>) =>\n new Promise<T>((resolve, reject) => {\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n\n/** Swaps in IndexedDB, keyed `<storageKey>/<texture name>`. Falls back to memory without it. */\nexport const indexedDbStore = (storageKey: string): SwapStore => {\n if (typeof indexedDB === \"undefined\") {\n return memoryStore();\n }\n\n let opened: Promise<IDBDatabase> | null = null;\n const database = () => {\n opened ??= new Promise((resolve, reject) => {\n const open = indexedDB.open(DATABASE, 1);\n\n open.onupgradeneeded = () => open.result.createObjectStore(STORE);\n open.onsuccess = () => resolve(open.result);\n open.onerror = () => reject(open.error);\n });\n\n return opened;\n };\n const key = (id: string) => `${storageKey}/${id}`;\n const store = async (mode: IDBTransactionMode) =>\n (await database()).transaction(STORE, mode).objectStore(STORE);\n\n return {\n get: async (id) =>\n (await request((await store(\"readonly\")).get(key(id)))) as StoredSwap | undefined,\n set: async (id, swap) => {\n await request((await store(\"readwrite\")).put(swap, key(id)));\n },\n delete: async (id) => {\n await request((await store(\"readwrite\")).delete(key(id)));\n },\n clear: async () => {\n const range = IDBKeyRange.bound(`${storageKey}/`, `${storageKey}/${LAST_CHAR}`);\n\n await request((await store(\"readwrite\")).delete(range));\n },\n };\n};\n","/**\n * Put an image in place of a texture's pixels, and take it out again.\n *\n * - **In place**, for an image texture: the shared `Source` gets the new image and every texture\n * on it re-uploads. Anything holding the texture — materials, the app's own references — sees\n * the swap, and the texture keeps all its settings.\n * - **Rebind**, for compressed and data textures: their data is GPU-ready blocks or raw bytes, so\n * an image can't go in their place. Each gets an image twin with its settings (wrap, filters,\n * colour space, uv channel and transform) and the twin is bound wherever the original was: the\n * material slots and uniforms `findTextures` saw. `flipY` is off, the way compressed and data\n * textures lay their rows, so a readback of the original uploads back the same way up.\n */\nimport { type Material, Texture } from \"three\";\n\nimport type { Found, TextureRef, TextureSource } from \"./discover.ts\";\nimport type { TextureKind } from \"./kinds.ts\";\n\nexport type SwapImage = HTMLImageElement | ImageBitmap;\n\n/** One slot the swap rebound: which original it held and the twin that replaced it. */\ntype Binding = TextureRef & { original: Texture; twin: Texture };\n\nexport type Applied =\n | {\n mode: \"in-place\";\n image: SwapImage;\n showingOriginal: boolean;\n /** The source's data before the first swap. */\n original: unknown;\n textures: Set<Texture>;\n }\n | {\n mode: \"rebind\";\n image: SwapImage;\n showingOriginal: boolean;\n /** The twins' shared source, holding the swapped image. */\n source: TextureSource;\n twins: Map<Texture, Texture>;\n bindings: Binding[];\n };\n\nexport const canSwap = (kind: TextureKind) => kind !== \"unsupported\";\n\nconst bump = (textures: Iterable<Texture>) => {\n for (const texture of textures) {\n texture.needsUpdate = true;\n }\n};\n\nconst recompile = (materials: Iterable<Material | null>) => {\n for (const material of materials) {\n if (material) {\n material.needsUpdate = true;\n }\n }\n};\n\nconst twinOf = (original: Texture, source: TextureSource) => {\n const twin = new Texture();\n\n twin.source = source;\n twin.name = original.name;\n twin.mapping = original.mapping;\n twin.channel = original.channel;\n twin.wrapS = original.wrapS;\n twin.wrapT = original.wrapT;\n twin.magFilter = original.magFilter;\n twin.minFilter = original.minFilter;\n twin.anisotropy = original.anisotropy;\n twin.colorSpace = original.colorSpace;\n twin.offset.copy(original.offset);\n twin.repeat.copy(original.repeat);\n twin.center.copy(original.center);\n twin.rotation = original.rotation;\n twin.matrixAutoUpdate = original.matrixAutoUpdate;\n twin.matrix.copy(original.matrix);\n twin.userData = { ...original.userData };\n twin.flipY = false;\n twin.premultiplyAlpha = false;\n twin.generateMipmaps = true;\n twin.needsUpdate = true;\n\n return twin;\n};\n\n/** Bind twins into every ref that still holds an original. Returns the new bindings. */\nconst bindRefs = (refs: readonly TextureRef[], twins: Map<Texture, Texture>): Binding[] => {\n const made: Binding[] = [];\n\n for (const ref of refs) {\n const original = ref.owner[ref.key] as Texture;\n const twin = twins.get(original);\n\n if (twin) {\n ref.owner[ref.key] = twin;\n made.push({ ...ref, original, twin });\n }\n }\n\n recompile(made.map((binding) => binding.material));\n\n return made;\n};\n\n/** Show `image` on the texture: a first swap, or a new image over an earlier one. */\nexport const applyImage = (\n found: Found,\n kind: TextureKind,\n image: SwapImage,\n existing: Applied | null,\n): Applied => {\n if (kind === \"image\") {\n const original = existing?.mode === \"in-place\" ? existing.original : found.source.data;\n\n found.source.data = image;\n bump(found.textures);\n\n return {\n mode: \"in-place\",\n image,\n showingOriginal: false,\n original,\n textures: new Set(found.textures),\n };\n }\n\n if (existing?.mode === \"rebind\") {\n existing.source.data = image;\n bump(existing.twins.values());\n\n const applied = { ...existing, image, showingOriginal: false };\n\n if (existing.showingOriginal) {\n showOriginal(applied, false);\n }\n\n return applied;\n }\n\n // The texture's own source class: `Source` before r186, `TextureSource` from it.\n const SourceClass = found.source.constructor as new (data: unknown) => TextureSource;\n const source = new SourceClass(image);\n const twins = new Map([...found.textures].map((texture) => [texture, twinOf(texture, source)]));\n\n return {\n mode: \"rebind\",\n image,\n showingOriginal: false,\n source,\n twins,\n bindings: bindRefs(found.refs, twins),\n };\n};\n\n/**\n * A rebind swap reaches slots found after it: a mesh mounted later with the original texture.\n * Call after re-finding the scene's textures. In-place swaps need nothing: they changed the data.\n */\nexport const bindNewRefs = (found: Found, applied: Applied) => {\n if (applied.mode !== \"rebind\" || applied.showingOriginal) {\n return;\n }\n\n for (const texture of found.textures) {\n if (!applied.twins.has(texture)) {\n applied.twins.set(texture, twinOf(texture, applied.source));\n }\n }\n\n applied.bindings.push(...bindRefs(found.refs, applied.twins));\n};\n\n/** Flip between the original and the swap (A/B), keeping both. */\nexport const showOriginal = (applied: Applied, original: boolean) => {\n applied.showingOriginal = original;\n\n if (applied.mode === \"in-place\") {\n const first = [...applied.textures][0];\n\n if (first) {\n first.source.data = original ? applied.original : applied.image;\n }\n\n bump(applied.textures);\n\n return;\n }\n\n for (const binding of applied.bindings) {\n const from = original ? binding.twin : binding.original;\n\n if (binding.owner[binding.key] === from) {\n binding.owner[binding.key] = original ? binding.original : binding.twin;\n }\n }\n\n recompile(applied.bindings.map((binding) => binding.material));\n};\n\n/** Undo the swap: the original data or bindings back, twins freed. */\nexport const revertImage = (applied: Applied) => {\n showOriginal(applied, true);\n\n if (applied.mode === \"rebind\") {\n for (const twin of applied.twins.values()) {\n twin.dispose();\n }\n }\n\n if (typeof ImageBitmap !== \"undefined\" && applied.image instanceof ImageBitmap) {\n applied.image.close();\n }\n};\n\n/** The textures drawing now: twins while a rebind swap shows, the originals otherwise. */\nexport const boundTextures = (found: Found, applied: Applied | null): Texture[] =>\n applied?.mode === \"rebind\" && !applied.showingOriginal\n ? [...applied.twins.values()]\n : [...found.textures];\n","/**\n * `TextureLab`: the textures a scene draws with, and swaps on them. No UI; the panel drives it.\n *\n * Each entry is one image's worth of pixels (one `Source`): every texture sharing it swaps\n * together. Entries are named by the `textures` option, else the texture's name, else its file,\n * else the material slot it fills; the name is also the key a swap is saved under, so a swap comes\n * back on reload for as long as the name holds.\n */\nimport type { Object3D, Texture } from \"three\";\n\nimport { findTextures, type Found, type TextureSource } from \"./discover.ts\";\nimport { formatOf, kindOf, sizeOf, type TextureKind } from \"./kinds.ts\";\nimport { fileNameOf, sourceUrlOf, stem } from \"./names.ts\";\nimport { canReadBack, readTexture, readTextureBlob } from \"./readback.ts\";\nimport {\n type FileSystemFileHandleLike,\n indexedDbStore,\n memoryStore,\n type SwapStore,\n} from \"./store.ts\";\nimport {\n type Applied,\n applyImage,\n bindNewRefs,\n boundTextures,\n canSwap,\n revertImage,\n showOriginal,\n type SwapImage,\n} from \"./swap.ts\";\n\nexport type TextureInfo = {\n name: string;\n texture: Texture;\n /** The file it was loaded from, for downloads and thumbnails. */\n src?: string;\n};\n\nexport type SwapEvent = {\n id: string;\n /** Every texture sharing the swapped pixels (the originals). */\n textures: Texture[];\n /** The textures drawing now: the originals after an in-place swap or a revert, else twins. */\n bound: Texture[];\n state: EntryState;\n};\n\nexport type TextureLabOptions = {\n /** Where to look for textures. */\n scene: Object3D;\n /** A `WebGLRenderer`, for reading back textures with no file (compressed, data, generated). */\n renderer?: unknown;\n /** Textures to list whether or not the scene shows them yet, with names and source files. */\n textures?: readonly TextureInfo[];\n /** IndexedDB key prefix for saved swaps. `null` keeps swaps for this page only. Default `three-textures`. */\n storageKey?: string | null;\n /** Replaces the store (tests). */\n store?: SwapStore;\n /** After any swap, toggle or revert: redraw derived textures (atlases) from `bound`. */\n onSwap?: (event: SwapEvent) => void;\n /** Ask for a frame, for render-on-demand loops (R3F `frameloop=\"demand\"`). */\n invalidate?: () => void;\n};\n\nexport type EntryState = \"original\" | \"swapped\" | \"showing-original\";\nexport type LinkState = \"off\" | \"live\" | \"paused\";\n\nexport type TextureEntry = {\n id: string;\n kind: TextureKind;\n /** `ASTC`, `ETC2`, `webp`, `canvas`, `data`… */\n format: string;\n width: number;\n height: number;\n colorSpace: string;\n /** The file it came from, when known. */\n src: string | null;\n /** How many materials use it. */\n materials: number;\n state: EntryState;\n link: LinkState;\n /** Name of the file swapped in. */\n swapName: string | null;\n /** Why it can't be swapped, when it can't. */\n unsupported: string | null;\n /** Counts every change to what it shows: a cache key for thumbnails. */\n revision: number;\n /** One of the original textures. */\n texture: Texture;\n};\n\ntype Item = {\n id: string;\n found: Found;\n kind: TextureKind;\n src: string | null;\n applied: Applied | null;\n blob: Blob | null;\n swapName: string | null;\n url: string | null;\n handle: FileSystemFileHandleLike | null;\n link: LinkState;\n lastModified: number;\n revision: number;\n};\n\ntype PickerWindow = Window & {\n showOpenFilePicker?: (options: object) => Promise<FileSystemFileHandleLike[]>;\n};\n\nconst LINK_POLL_MS = 600;\n\n/** Decode to the same kind of object the texture held: WebGL ignores `flipY` for bitmaps. */\nconst decode = async (\n blob: Blob,\n like: unknown,\n): Promise<{ image: SwapImage; url: string | null }> => {\n if (typeof ImageBitmap !== \"undefined\" && like instanceof ImageBitmap) {\n return {\n image: await createImageBitmap(blob, {\n premultiplyAlpha: \"none\",\n colorSpaceConversion: \"none\",\n }),\n url: null,\n };\n }\n\n const url = URL.createObjectURL(blob);\n const image = new Image();\n\n image.src = url;\n await image.decode();\n\n return { image, url };\n};\n\nconst drawToDataUrl = (\n draw: (context: CanvasRenderingContext2D) => void,\n width: number,\n height: number,\n) => {\n const canvas = document.createElement(\"canvas\");\n\n canvas.width = width;\n canvas.height = height;\n draw(canvas.getContext(\"2d\")!);\n\n return canvas.toDataURL(\"image/png\");\n};\n\nconst fit = (width: number, height: number, max: number) => {\n const scale = Math.min(1, max / Math.max(width, height, 1));\n\n return {\n width: Math.max(1, Math.round(width * scale)),\n height: Math.max(1, Math.round(height * scale)),\n };\n};\n\nexport class TextureLab {\n private readonly options: TextureLabOptions;\n private readonly store: SwapStore;\n private readonly records = new Map<TextureSource, Item>();\n private readonly byId = new Map<string, Item>();\n /** Sources of rebind twins, so a refresh doesn't list them as textures of their own. */\n private readonly twinSources = new Set<TextureSource>();\n private readonly listeners = new Set<() => void>();\n private readonly restoring = new Set<string>();\n private poll: ReturnType<typeof setInterval> | null = null;\n private disposed = false;\n\n constructor(options: TextureLabOptions) {\n this.options = options;\n this.store =\n options.store ??\n (options.storageKey === null\n ? memoryStore()\n : indexedDbStore(options.storageKey ?? \"three-textures\"));\n this.refresh();\n }\n\n /** Whether this browser can live-link a file (the File System Access API: Chrome, Edge). */\n static get canLink() {\n return (\n typeof window !== \"undefined\" &&\n typeof (window as PickerWindow).showOpenFilePicker === \"function\"\n );\n }\n\n /** Whether downloads and thumbnails can read textures back from the GPU. */\n get canReadBack() {\n return canReadBack(this.options.renderer);\n }\n\n subscribe(listener: () => void) {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Every texture, by name. */\n entries(): TextureEntry[] {\n return [...this.byId.values()]\n .map((record) => this.entryOf(record))\n .sort((a, b) => a.id.localeCompare(b.id));\n }\n\n entry(id: string): TextureEntry | null {\n const record = this.byId.get(id);\n\n return record ? this.entryOf(record) : null;\n }\n\n /**\n * Look at the scene again: textures that appeared get entries (and their saved swap back), a\n * rebind swap reaches slots mounted since. Entries whose textures left the scene stay while\n * swapped or registered, so their state isn't lost.\n */\n refresh() {\n if (this.disposed) {\n return;\n }\n\n const found = findTextures(this.options.scene);\n let changed = false;\n\n for (const info of this.options.textures ?? []) {\n if (!found.has(info.texture.source)) {\n found.set(info.texture.source, {\n source: info.texture.source,\n textures: new Set([info.texture]),\n refs: [],\n slots: new Set(),\n materials: new Set(),\n });\n }\n }\n\n const seen = new Set<TextureSource>();\n\n for (const [source, item] of found) {\n if (this.twinSources.has(source)) {\n continue;\n }\n\n seen.add(source);\n\n const record = this.records.get(source);\n\n if (record) {\n const before = record.found.materials.size;\n\n record.found = item;\n\n if (record.applied) {\n bindNewRefs(item, record.applied);\n }\n\n changed ||= before !== item.materials.size;\n continue;\n }\n\n this.add(item);\n changed = true;\n }\n\n for (const [source, record] of this.records) {\n if (!seen.has(source) && !record.applied && !this.isRegistered(source)) {\n this.records.delete(source);\n this.byId.delete(record.id);\n changed = true;\n }\n }\n\n if (changed) {\n this.notify();\n }\n }\n\n /** Swap `blob` (an image file) in for the texture `id`. */\n async swap(\n id: string,\n blob: Blob,\n {\n fileName = (blob as File).name ?? null,\n persist = true,\n }: { fileName?: string | null; persist?: boolean } = {},\n ) {\n const record = this.require(id);\n\n if (!canSwap(record.kind)) {\n throw new Error(`three-textures: \"${id}\" can't be swapped (${record.kind})`);\n }\n\n const { image, url } = await decode(blob, record.found.source.data);\n const previousUrl = record.url;\n\n record.applied = applyImage(record.found, record.kind, image, record.applied);\n\n if (record.applied.mode === \"rebind\") {\n this.twinSources.add(record.applied.source);\n }\n\n record.blob = blob;\n record.swapName = fileName || null;\n record.url = url;\n\n if (previousUrl && previousUrl !== url) {\n URL.revokeObjectURL(previousUrl);\n }\n\n if (persist) {\n await this.save(record);\n }\n\n this.changed(record);\n }\n\n /** A/B: show the original (`true`) or the swap (`false`). */\n async showOriginal(id: string, original: boolean) {\n const record = this.require(id);\n\n if (!record.applied || record.applied.showingOriginal === original) {\n return;\n }\n\n showOriginal(record.applied, original);\n await this.save(record);\n this.changed(record);\n }\n\n /** Back to the original, forgetting the swap. */\n async revert(id: string) {\n const record = this.require(id);\n\n this.stopLink(record);\n record.handle = null;\n await this.store.delete(id);\n\n if (!record.applied) {\n this.notify();\n\n return;\n }\n\n revertImage(record.applied);\n\n if (record.applied.mode === \"rebind\") {\n this.twinSources.delete(record.applied.source);\n }\n\n record.applied = null;\n record.blob = null;\n record.swapName = null;\n\n if (record.url) {\n URL.revokeObjectURL(record.url);\n record.url = null;\n }\n\n this.changed(record);\n }\n\n /** Every entry back to its original, and every saved swap cleared. */\n async revertAll() {\n for (const record of this.byId.values()) {\n if (record.applied || record.handle) {\n await this.revert(record.id);\n }\n }\n\n await this.store.clear();\n }\n\n /**\n * The pixels showing now as a file: the swapped file, else the original file when its URL is\n * known and fetchable, else a GPU readback as PNG.\n */\n async toBlob(id: string): Promise<{ blob: Blob; fileName: string }> {\n const record = this.require(id);\n const fallbackName = `${id}.png`;\n\n if (record.applied && !record.applied.showingOriginal && record.blob) {\n return { blob: record.blob, fileName: record.swapName ?? fallbackName };\n }\n\n if (record.src) {\n try {\n const response = await fetch(record.src);\n\n if (response.ok) {\n return { blob: await response.blob(), fileName: fileNameOf(record.src) ?? fallbackName };\n }\n } catch {\n // Cross-origin or gone: read it back instead.\n }\n }\n\n const renderer = this.options.renderer;\n\n if (!canReadBack(renderer)) {\n throw new Error(\n `three-textures: \"${id}\" has no file to download and the renderer can't read it back`,\n );\n }\n\n const texture = [...record.found.textures][0]!;\n const { width, height } = sizeOf(texture);\n\n return {\n blob: await readTextureBlob(renderer, texture, width, height),\n fileName: fallbackName,\n };\n }\n\n /** Save the pixels showing now to the downloads folder. */\n async download(id: string) {\n const { blob, fileName } = await this.toBlob(id);\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n\n link.href = url;\n link.download = fileName;\n document.body.append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n }\n\n /** A small picture of what's showing now, as a data URL; `null` when there's no way to draw it. */\n thumbnail(id: string, max = 96): string | null {\n const record = this.require(id);\n const bound = boundTextures(record.found, record.applied)[0];\n\n if (!bound) {\n return null;\n }\n\n const data = bound.source.data as CanvasImageSource & { width: number; height: number };\n\n if (kindOf(bound) === \"image\" || (record.applied && !record.applied.showingOriginal)) {\n const { width, height } = fit(data.width, data.height, max);\n\n try {\n return drawToDataUrl(\n (context) => context.drawImage(data, 0, 0, width, height),\n width,\n height,\n );\n } catch {\n return null;\n }\n }\n\n const renderer = this.options.renderer;\n\n if (!canReadBack(renderer)) {\n return null;\n }\n\n const { width, height } = fit(sizeOf(bound).width, sizeOf(bound).height, max);\n\n return drawToDataUrl(\n (context) => context.putImageData(readTexture(renderer, bound, width, height), 0, 0),\n width,\n height,\n );\n }\n\n /**\n * Live-link a file: pick it once, and every save re-applies it. Call from a click (the browser\n * shows a file picker, or asks to resume permission for a link restored after a reload).\n */\n async link(id: string) {\n const record = this.require(id);\n let handle = record.handle;\n\n if (handle) {\n const permission = (await handle.requestPermission?.({ mode: \"read\" })) ?? \"granted\";\n\n if (permission !== \"granted\") {\n return;\n }\n } else {\n const picker = (window as PickerWindow).showOpenFilePicker;\n\n if (!picker) {\n throw new Error(\n \"three-textures: live links need the File System Access API (Chrome, Edge)\",\n );\n }\n\n [handle] = (await picker({\n types: [\n {\n description: \"Images\",\n accept: { \"image/*\": [\".png\", \".jpg\", \".jpeg\", \".webp\", \".avif\"] },\n },\n ],\n })) as [FileSystemFileHandleLike];\n }\n\n const file = await handle.getFile();\n\n record.handle = handle;\n record.link = \"live\";\n record.lastModified = file.lastModified;\n await this.swap(id, file, { fileName: handle.name });\n this.startPolling();\n }\n\n /** Stop following the file; the last version stays swapped in. */\n async unlink(id: string) {\n const record = this.require(id);\n\n this.stopLink(record);\n record.handle = null;\n await this.save(record);\n this.notify();\n }\n\n dispose() {\n this.disposed = true;\n\n if (this.poll) {\n clearInterval(this.poll);\n }\n\n this.listeners.clear();\n }\n\n private add(item: Found) {\n const id = this.uniqueName(this.nameOf(item));\n const texture = [...item.textures][0]!;\n const registered = (this.options.textures ?? []).find(\n (info) => info.texture.source === item.source,\n );\n const record: Item = {\n id,\n found: item,\n kind: kindOf(texture),\n src: registered?.src ?? sourceUrlOf(texture),\n applied: null,\n blob: null,\n swapName: null,\n url: null,\n handle: null,\n link: \"off\",\n lastModified: 0,\n revision: 0,\n };\n\n this.records.set(item.source, record);\n this.byId.set(id, record);\n void this.restore(record);\n }\n\n private nameOf(item: Found) {\n const registered = (this.options.textures ?? []).find(\n (info) => info.texture.source === item.source,\n );\n\n if (registered) {\n return registered.name;\n }\n\n for (const texture of item.textures) {\n if (texture.name) {\n return texture.name;\n }\n }\n\n const url = sourceUrlOf([...item.textures][0]!);\n const file = url ? fileNameOf(url) : null;\n\n return file ? stem(file) : ([...item.slots][0] ?? \"texture\");\n }\n\n private uniqueName(name: string) {\n let unique = name;\n\n for (let n = 2; this.byId.has(unique); n += 1) {\n unique = `${name} ${n}`;\n }\n\n return unique;\n }\n\n private isRegistered(source: TextureSource) {\n return (this.options.textures ?? []).some((info) => info.texture.source === source);\n }\n\n private async restore(record: Item) {\n if (this.restoring.has(record.id)) {\n return;\n }\n\n this.restoring.add(record.id);\n\n try {\n const saved = await this.store.get(record.id);\n\n if (!saved || this.disposed || record.applied || !canSwap(record.kind)) {\n return;\n }\n\n await this.swap(record.id, saved.blob, { fileName: saved.fileName, persist: false });\n\n if (saved.showingOriginal) {\n await this.showOriginal(record.id, true);\n }\n\n if (saved.handle) {\n record.handle = saved.handle;\n record.link = \"paused\";\n this.notify();\n }\n } catch (error) {\n // oxlint-disable-next-line no-console -- a dev tool's one channel for a failed restore\n console.warn(`three-textures: couldn't restore the swap for \"${record.id}\"`, error);\n } finally {\n this.restoring.delete(record.id);\n }\n }\n\n private async save(record: Item) {\n if (!record.blob || !record.applied) {\n return;\n }\n\n const swap = {\n blob: record.blob,\n fileName: record.swapName,\n showingOriginal: record.applied.showingOriginal,\n handle: record.handle ?? undefined,\n };\n\n try {\n await this.store.set(record.id, swap);\n } catch (error) {\n try {\n // A file handle that won't clone (some browsers, test doubles): keep the swap without it.\n await this.store.set(record.id, { ...swap, handle: undefined });\n } catch {\n // oxlint-disable-next-line no-console -- a dev tool's one channel for a failed save\n console.warn(`three-textures: couldn't save the swap for \"${record.id}\"`, error);\n }\n }\n }\n\n private startPolling() {\n this.poll ??= setInterval(() => void this.checkLinks(), LINK_POLL_MS);\n }\n\n private async checkLinks() {\n let live = 0;\n\n for (const record of this.byId.values()) {\n if (record.link !== \"live\" || !record.handle) {\n continue;\n }\n\n live += 1;\n\n try {\n const file = await record.handle.getFile();\n\n if (file.lastModified !== record.lastModified) {\n record.lastModified = file.lastModified;\n await this.swap(record.id, file, { fileName: record.handle.name });\n }\n } catch {\n // Mid-save, moved, or permission gone: pause rather than spin.\n record.link = \"paused\";\n this.notify();\n }\n }\n\n if (live === 0 && this.poll) {\n clearInterval(this.poll);\n this.poll = null;\n }\n }\n\n private stopLink(record: Item) {\n record.link = \"off\";\n }\n\n private require(id: string) {\n const record = this.byId.get(id);\n\n if (!record) {\n throw new Error(`three-textures: no texture \"${id}\"`);\n }\n\n return record;\n }\n\n private entryOf(record: Item): TextureEntry {\n const texture = [...record.found.textures][0]!;\n const { width, height } = sizeOf(texture);\n\n return {\n id: record.id,\n kind: record.kind,\n format: formatOf(texture),\n width,\n height,\n colorSpace: texture.colorSpace,\n src: record.src,\n materials: record.found.materials.size,\n state: !record.applied\n ? \"original\"\n : record.applied.showingOriginal\n ? \"showing-original\"\n : \"swapped\",\n link: record.link,\n swapName: record.swapName,\n unsupported: canSwap(record.kind)\n ? null\n : \"cube, 3D, array, video and render-target textures can't be swapped\",\n revision: record.revision,\n texture,\n };\n }\n\n private changed(record: Item) {\n record.revision += 1;\n this.options.onSwap?.({\n id: record.id,\n textures: [...record.found.textures],\n bound: boundTextures(record.found, record.applied),\n state: this.entryOf(record).state,\n });\n this.options.invalidate?.();\n this.notify();\n }\n\n private notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { o as TextureLab, s as TextureLabOptions } from "./lab-CN1v1x-y.js";
|
|
2
|
+
import { DefaultPlacement, ThemeMode } from "@zkmake/three-meter/ui";
|
|
3
|
+
//#region src/ui/mount.d.ts
|
|
4
|
+
type MountTexturePanelOptions = TextureLabOptions & {
|
|
5
|
+
/** Where it docks on a first visit. Default the right edge, top. */
|
|
6
|
+
defaultPlacement?: DefaultPlacement;
|
|
7
|
+
/** `dark`, `light` or `system` (default). */
|
|
8
|
+
theme?: ThemeMode;
|
|
9
|
+
/** Start compact: the brand row and the count. The choice is remembered. */
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
/** Where to mount. Default `document.body`. */
|
|
12
|
+
container?: HTMLElement;
|
|
13
|
+
};
|
|
14
|
+
type TexturePanelHandle = {
|
|
15
|
+
lab: TextureLab;
|
|
16
|
+
element: HTMLElement;
|
|
17
|
+
setCompact(compact: boolean): void;
|
|
18
|
+
/** `dark`, `light` or `system`: the panel follows it. */
|
|
19
|
+
setTheme(mode: ThemeMode): void;
|
|
20
|
+
dispose(): void;
|
|
21
|
+
};
|
|
22
|
+
declare const mountTexturePanel: (options: MountTexturePanelOptions) => TexturePanelHandle;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { TexturePanelHandle as n, mountTexturePanel as r, MountTexturePanelOptions as t };
|
|
25
|
+
//# sourceMappingURL=mount-Bk5wVa_1.d.ts.map
|