@three-flatland/normals 0.1.0-alpha.1 → 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/NormalMapLoader.d.ts +99 -0
- package/dist/NormalMapLoader.d.ts.map +1 -0
- package/dist/NormalMapLoader.js +128 -125
- package/dist/NormalMapLoader.js.map +1 -1
- package/dist/bake.d.ts +57 -0
- package/dist/bake.d.ts.map +1 -0
- package/dist/bake.js +149 -114
- package/dist/bake.js.map +1 -1
- package/dist/bake.node.d.ts +20 -0
- package/dist/bake.node.d.ts.map +1 -0
- package/dist/bake.node.js +37 -30
- package/dist/bake.node.js.map +1 -1
- package/dist/cli.d.ts +4 -3
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +109 -122
- package/dist/cli.js.map +1 -1
- package/dist/descriptor.d.ts +129 -0
- package/dist/descriptor.d.ts.map +1 -0
- package/dist/descriptor.js +45 -52
- package/dist/descriptor.js.map +1 -1
- package/dist/index.d.ts +5 -320
- package/dist/index.js +5 -33
- package/dist/node.d.ts +7 -21
- package/dist/node.js +5 -5
- package/dist/resolveNormalMap.d.ts +51 -0
- package/dist/resolveNormalMap.d.ts.map +1 -0
- package/dist/resolveNormalMap.js +67 -88
- package/dist/resolveNormalMap.js.map +1 -1
- package/package.json +27 -9
- package/dist/index.js.map +0 -1
- package/dist/node.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resolveNormalMap.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"resolveNormalMap.js","names":["ThreeTextureLoader"],"sources":["../src/resolveNormalMap.ts"],"sourcesContent":["import { DataTexture, RGBAFormat, UnsignedByteType, TextureLoader as ThreeTextureLoader, type Texture } from 'three'\nimport { bakedSiblingURL, devtimeWarn, hashDescriptor, probeBakedSibling } from '@three-flatland/bake'\nimport type { NormalSourceDescriptor } from './descriptor.js'\n\nexport interface ResolveNormalMapOptions {\n /**\n * Generate this asset's normal map in the browser on every load\n * instead of loading a pre-baked `.normal.png` sidecar. Fetches the\n * source image, decodes its pixels, and runs `bakeNormalMap` in\n * memory each time — no HEAD probe, no devtime \"no baked sibling\"\n * warning.\n *\n * The returned data is always a valid normal map: this flag chooses\n * *where* the bake happens (browser vs CI), not whether you get one.\n *\n * Use when runtime is the right home for the bake — procedurally\n * varied content, throwaway prototypes, asset bundles where shipping\n * the sidecar isn't worth the bytes. Not a dev-iteration knob: the\n * default path (probe → bake on miss + warn) already handles that.\n *\n * Mirrors `SlugFontLoader.forceRuntime` and every other baked-asset\n * loader in the codebase.\n */\n forceRuntime?: boolean\n /**\n * Force the returned texture's `flipY` to this value. Pass the\n * diffuse texture's `flipY` so the normal map samples 1:1 with the\n * diffuse on the GPU regardless of whether the normal came from the\n * image-loader path (default true) or the in-memory `DataTexture`\n * path (default false).\n */\n flipY?: boolean\n}\n\n/**\n * Resolve the normal map for an asset URL + descriptor.\n *\n * 1. Hash the descriptor.\n * 2. Probe the baked sibling `<source>.normal.png` (unless\n * `forceRuntime`). If present and its stamped hash matches, load\n * and return that texture directly.\n * 3. On miss (or stale hash), fetch the source, decode its pixels,\n * lazy-import + run `bakeNormalMap` in memory, and wrap the result\n * in a `DataTexture`. Runtime bake is the always-on fallback when\n * normals were requested.\n *\n * Browser-only — uses `fetch`, `createImageBitmap`, `OffscreenCanvas`.\n * Safe to call from any Three.js loader runtime.\n */\nexport async function resolveNormalMap(\n sourceURL: string,\n descriptor: NormalSourceDescriptor,\n options: ResolveNormalMapOptions = {}\n): Promise<Texture> {\n const hash = hashDescriptor(descriptor)\n\n if (!options.forceRuntime) {\n const bakedURL = bakedSiblingURL(sourceURL, '.normal.png')\n const probe = await probeBakedSibling(bakedURL, { expectedHash: hash })\n if (probe.ok && probe.hashMatches) {\n const tex = await loadTextureURL(bakedURL)\n if (options.flipY !== undefined) tex.flipY = options.flipY\n tex.needsUpdate = true\n return tex\n }\n if (probe.ok && !probe.hashMatches) {\n devtimeWarn(\n 'normal',\n sourceURL,\n `${bakedURL} exists but its descriptor hash is stale — re-baking in memory. ` +\n `Run \\`npx flatland-bake normal ${sourceURL} --descriptor <descriptor>.json\\` to refresh.`\n )\n } else {\n devtimeWarn(\n 'normal',\n sourceURL,\n `No baked sibling at ${bakedURL} — baking in memory. ` + `Run \\`npx flatland-bake normal\\` for production.`\n )\n }\n }\n\n const tex = await bakeInMemory(sourceURL, descriptor)\n if (options.flipY !== undefined) tex.flipY = options.flipY\n tex.needsUpdate = true\n return tex\n}\n\n// ─── Private ──────────────────────────────────────────────────────────────\n\nasync function loadTextureURL(url: string): Promise<Texture> {\n return new Promise((resolve, reject) => {\n const loader = new ThreeTextureLoader()\n loader.load(\n url,\n (tex) => resolve(tex as Texture),\n undefined,\n (err) => reject(err as Error)\n )\n })\n}\n\nasync function bakeInMemory(sourceURL: string, descriptor: NormalSourceDescriptor): Promise<Texture> {\n const res = await fetch(sourceURL)\n if (!res.ok) {\n throw new Error(`resolveNormalMap: failed to fetch ${sourceURL} (${res.status})`)\n }\n const blob = await res.blob()\n const bitmap = await createImageBitmap(blob)\n const { width, height } = bitmap\n const pixels = imageBitmapToRGBA(bitmap, width, height)\n bitmap.close()\n\n const { bakeNormalMap } = await import('./bake.js')\n const normalPixels = bakeNormalMap(pixels, width, height, descriptor)\n const texture = new DataTexture(normalPixels, width, height, RGBAFormat, UnsignedByteType)\n texture.needsUpdate = true\n return texture\n}\n\nfunction imageBitmapToRGBA(bitmap: ImageBitmap, width: number, height: number): Uint8Array {\n // OffscreenCanvas where available (workers + modern browsers), fall\n // back to a regular 2D canvas in environments that don't ship it.\n if (typeof OffscreenCanvas !== 'undefined') {\n const canvas = new OffscreenCanvas(width, height)\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('resolveNormalMap: OffscreenCanvas 2D context unavailable')\n ctx.drawImage(bitmap, 0, 0)\n const data = ctx.getImageData(0, 0, width, height)\n return new Uint8Array(data.data.buffer, data.data.byteOffset, data.data.byteLength)\n }\n const canvas = document.createElement('canvas')\n canvas.width = width\n canvas.height = height\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('resolveNormalMap: Canvas 2D context unavailable')\n ctx.drawImage(bitmap, 0, 0)\n const data = ctx.getImageData(0, 0, width, height)\n return new Uint8Array(data.data.buffer, data.data.byteOffset, data.data.byteLength)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiDA,eAAsB,iBACpB,WACA,YACA,UAAmC,CAAC,GAClB;CAClB,MAAM,OAAO,eAAe,UAAU;CAEtC,IAAI,CAAC,QAAQ,cAAc;EACzB,MAAM,WAAW,gBAAgB,WAAW,aAAa;EACzD,MAAM,QAAQ,MAAM,kBAAkB,UAAU,EAAE,cAAc,KAAK,CAAC;EACtE,IAAI,MAAM,MAAM,MAAM,aAAa;GACjC,MAAM,MAAM,MAAM,eAAe,QAAQ;GACzC,IAAI,QAAQ,UAAU,KAAA,GAAW,IAAI,QAAQ,QAAQ;GACrD,IAAI,cAAc;GAClB,OAAO;EACT;EACA,IAAI,MAAM,MAAM,CAAC,MAAM,aACrB,YACE,UACA,WACA,GAAG,SAAS,iGACwB,UAAU,8CAChD;OAEA,YACE,UACA,WACA,uBAAuB,SAAS,sEAClC;CAEJ;CAEA,MAAM,MAAM,MAAM,aAAa,WAAW,UAAU;CACpD,IAAI,QAAQ,UAAU,KAAA,GAAW,IAAI,QAAQ,QAAQ;CACrD,IAAI,cAAc;CAClB,OAAO;AACT;AAIA,eAAe,eAAe,KAA+B;CAC3D,OAAO,IAAI,SAAS,SAAS,WAAW;EAEtC,IADmBA,cACd,CAAC,CAAC,KACL,MACC,QAAQ,QAAQ,GAAc,GAC/B,KAAA,IACC,QAAQ,OAAO,GAAY,CAC9B;CACF,CAAC;AACH;AAEA,eAAe,aAAa,WAAmB,YAAsD;CACnG,MAAM,MAAM,MAAM,MAAM,SAAS;CACjC,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,qCAAqC,UAAU,IAAI,IAAI,OAAO,EAAE;CAElF,MAAM,OAAO,MAAM,IAAI,KAAK;CAC5B,MAAM,SAAS,MAAM,kBAAkB,IAAI;CAC3C,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,SAAS,kBAAkB,QAAQ,OAAO,MAAM;CACtD,OAAO,MAAM;CAEb,MAAM,EAAE,kBAAkB,MAAM,OAAO;CAEvC,MAAM,UAAU,IAAI,YADC,cAAc,QAAQ,OAAO,QAAQ,UACf,GAAG,OAAO,QAAQ,YAAY,gBAAgB;CACzF,QAAQ,cAAc;CACtB,OAAO;AACT;AAEA,SAAS,kBAAkB,QAAqB,OAAe,QAA4B;CAGzF,IAAI,OAAO,oBAAoB,aAAa;EAE1C,MAAM,MAAM,IADO,gBAAgB,OAAO,MACzB,CAAC,CAAC,WAAW,IAAI;EAClC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0DAA0D;EACpF,IAAI,UAAU,QAAQ,GAAG,CAAC;EAC1B,MAAM,OAAO,IAAI,aAAa,GAAG,GAAG,OAAO,MAAM;EACjD,OAAO,IAAI,WAAW,KAAK,KAAK,QAAQ,KAAK,KAAK,YAAY,KAAK,KAAK,UAAU;CACpF;CACA,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,QAAQ;CACf,OAAO,SAAS;CAChB,MAAM,MAAM,OAAO,WAAW,IAAI;CAClC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,iDAAiD;CAC3E,IAAI,UAAU,QAAQ,GAAG,CAAC;CAC1B,MAAM,OAAO,IAAI,aAAa,GAAG,GAAG,OAAO,MAAM;CACjD,OAAO,IAAI,WAAW,KAAK,KAAK,QAAQ,KAAK,KAAK,YAAY,KAAK,KAAK,UAAU;AACpF"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@three-flatland/normals",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Offline + runtime normal map generation for sprites and tilesets. Contributes a `normal` subcommand to the flatland-bake CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"source": "./src/index.ts",
|
|
9
8
|
"node": {
|
|
10
9
|
"types": "./dist/node.d.ts",
|
|
11
10
|
"import": "./dist/node.js"
|
|
@@ -20,17 +19,14 @@
|
|
|
20
19
|
}
|
|
21
20
|
},
|
|
22
21
|
"./node": {
|
|
23
|
-
"source": "./src/node.ts",
|
|
24
22
|
"types": "./dist/node.d.ts",
|
|
25
23
|
"import": "./dist/node.js"
|
|
26
24
|
},
|
|
27
25
|
"./cli": {
|
|
28
|
-
"source": "./src/cli.ts",
|
|
29
26
|
"types": "./dist/cli.d.ts",
|
|
30
27
|
"import": "./dist/cli.js"
|
|
31
28
|
},
|
|
32
29
|
"./bake": {
|
|
33
|
-
"source": "./src/bake.ts",
|
|
34
30
|
"types": "./dist/bake.d.ts",
|
|
35
31
|
"import": "./dist/bake.js"
|
|
36
32
|
}
|
|
@@ -41,9 +37,30 @@
|
|
|
41
37
|
"dist"
|
|
42
38
|
],
|
|
43
39
|
"sideEffects": false,
|
|
40
|
+
"nx": {
|
|
41
|
+
"tags": [
|
|
42
|
+
"scope:sibling"
|
|
43
|
+
],
|
|
44
|
+
"targets": {
|
|
45
|
+
"test": {
|
|
46
|
+
"executor": "nx:run-commands",
|
|
47
|
+
"options": {
|
|
48
|
+
"command": "vitest run",
|
|
49
|
+
"cwd": "{projectRoot}"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"lint": {
|
|
53
|
+
"executor": "nx:run-commands",
|
|
54
|
+
"options": {
|
|
55
|
+
"command": "oxlint --type-aware .",
|
|
56
|
+
"cwd": "{projectRoot}"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
44
61
|
"dependencies": {
|
|
45
62
|
"pngjs": "^7.0.0",
|
|
46
|
-
"@three-flatland/bake": "0.1.0-alpha.
|
|
63
|
+
"@three-flatland/bake": "0.1.0-alpha.2"
|
|
47
64
|
},
|
|
48
65
|
"peerDependencies": {
|
|
49
66
|
"three": ">=0.170.0"
|
|
@@ -51,7 +68,8 @@
|
|
|
51
68
|
"devDependencies": {
|
|
52
69
|
"@types/pngjs": "^6.0.5",
|
|
53
70
|
"@types/three": "^0.183.1",
|
|
54
|
-
"three": "^0.183.1"
|
|
71
|
+
"three": "^0.183.1",
|
|
72
|
+
"@three-flatland/schemas": "1.0.0"
|
|
55
73
|
},
|
|
56
74
|
"flatland": {
|
|
57
75
|
"bake": [
|
|
@@ -74,8 +92,8 @@
|
|
|
74
92
|
"directory": "packages/normals"
|
|
75
93
|
},
|
|
76
94
|
"scripts": {
|
|
77
|
-
"build": "
|
|
78
|
-
"dev": "
|
|
95
|
+
"build": "tsdown",
|
|
96
|
+
"dev": "tsdown --watch",
|
|
79
97
|
"typecheck": "tsc --noEmit",
|
|
80
98
|
"clean": "rm -rf dist"
|
|
81
99
|
}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Browser-safe default entry. Ships the pure bake algorithm, the\n// descriptor types, and the runtime `NormalMapLoader`.\n//\n// Node-only helpers (file I/O, CLI) live under `@three-flatland/normals/node`\n// so bundlers targeting the browser don't pull in `node:fs` or pngjs.\n\nexport {\n bakeNormalMap,\n bakeNormalMapFromPixels,\n bakedNormalURL,\n type BakeOptions,\n} from './bake.js'\nexport {\n NormalMapLoader,\n type NormalMapResult,\n} from './NormalMapLoader.js'\nexport {\n resolveNormalMap,\n type ResolveNormalMapOptions,\n} from './resolveNormalMap.js'\nexport {\n directionToAngle,\n resolveRegion,\n DEFAULT_PITCH,\n DEFAULT_STRENGTH,\n DEFAULT_BUMP,\n DEFAULT_ELEVATION,\n type NormalDirection,\n type NormalBump,\n type NormalRegion,\n type NormalSourceDescriptor,\n type ResolvedNormalRegion,\n} from './descriptor.js'\n"],"mappings":"AAMA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;","names":[]}
|
package/dist/node.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/node.ts"],"sourcesContent":["// Node-only entry. Re-exports the browser-safe surface plus file I/O\n// helpers (`bakeNormalMapFile`). The CLI subcommand entry is at\n// `@three-flatland/normals/cli`.\n\nexport * from './index.js'\nexport { bakeNormalMapFile } from './bake.node.js'\n"],"mappings":"AAIA,cAAc;AACd,SAAS,yBAAyB;","names":[]}
|