@nayan-ui/engine 0.0.0-stage → 1.0.0-beta.4

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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/NayanEngine.podspec +28 -0
  3. package/README.md +308 -2
  4. package/lib/module/assets/AssetBytesCache.js +76 -0
  5. package/lib/module/assets/AssetCache.js +19 -0
  6. package/lib/module/assets/AssetLoader.js +52 -0
  7. package/lib/module/assets/CacheGeneration.js +7 -0
  8. package/lib/module/assets/IndexedDbCache.web.js +149 -0
  9. package/lib/module/assets/ProceduralCache.js +249 -0
  10. package/lib/module/assets/font.js +139 -0
  11. package/lib/module/assets/loft.js +142 -0
  12. package/lib/module/assets/model.js +96 -0
  13. package/lib/module/assets/modelling.js +254 -0
  14. package/lib/module/assets/shape.js +926 -0
  15. package/lib/module/assets/source.js +58 -0
  16. package/lib/module/assets/source.web.js +22 -0
  17. package/lib/module/assets/storage.js +4 -0
  18. package/lib/module/assets/storage.shared.js +38 -0
  19. package/lib/module/assets/storage.web.js +38 -0
  20. package/lib/module/assets/surface.js +47 -0
  21. package/lib/module/assets/texture.js +69 -0
  22. package/lib/module/drawing/DrawingCanvas.js +38 -0
  23. package/lib/module/drawing/DrawingCanvas.web.js +206 -0
  24. package/lib/module/drawing/DrawingDocument.js +256 -0
  25. package/lib/module/drawing/types.js +4 -0
  26. package/lib/module/globals.d.ts +12 -0
  27. package/lib/module/index.js +39 -0
  28. package/lib/module/input/Joystick.js +84 -0
  29. package/lib/module/input/Joystick.web.js +93 -0
  30. package/lib/module/input/keyboard.js +250 -0
  31. package/lib/module/media/audio-worklet.js +34 -0
  32. package/lib/module/media/audio.js +97 -0
  33. package/lib/module/media/haptics.js +82 -0
  34. package/lib/module/media/output.web.js +66 -0
  35. package/lib/module/native/BrowserEngine.js +568 -0
  36. package/lib/module/native/EngineBridge.js +4 -0
  37. package/lib/module/native/NativeNayanEngine.js +7 -0
  38. package/lib/module/native/NativeNayanEngine.web.js +62 -0
  39. package/lib/module/native/prepare.js +7 -0
  40. package/lib/module/native/prepare.web.js +17 -0
  41. package/lib/module/native/spec/NativeNayanEngine.js +17 -0
  42. package/lib/module/package.json +1 -0
  43. package/lib/module/render/GameView.js +317 -0
  44. package/lib/module/render/camera.js +34 -0
  45. package/lib/module/render/host.js +39 -0
  46. package/lib/module/render/host.web.js +104 -0
  47. package/lib/module/render/light.js +24 -0
  48. package/lib/module/render/meshes.js +159 -0
  49. package/lib/module/render/quality.js +119 -0
  50. package/lib/module/render/responder.js +4 -0
  51. package/lib/module/render/responder.web.js +97 -0
  52. package/lib/module/render/touch.js +185 -0
  53. package/lib/module/render/useWorld.js +72 -0
  54. package/lib/module/types.js +30 -0
  55. package/lib/module/world/Scoreboard.js +161 -0
  56. package/lib/module/world/TransformBatch.js +128 -0
  57. package/lib/module/world/World.js +704 -0
  58. package/lib/module/world/color.js +80 -0
  59. package/lib/module/world/desc.js +187 -0
  60. package/lib/module/world/effects.js +463 -0
  61. package/lib/module/world/quat.js +86 -0
  62. package/lib/module/world/types.js +4 -0
  63. package/lib/typescript/package.json +1 -0
  64. package/lib/typescript/src/assets/AssetBytesCache.d.ts +7 -0
  65. package/lib/typescript/src/assets/AssetCache.d.ts +9 -0
  66. package/lib/typescript/src/assets/AssetLoader.d.ts +11 -0
  67. package/lib/typescript/src/assets/CacheGeneration.d.ts +3 -0
  68. package/lib/typescript/src/assets/IndexedDbCache.web.d.ts +20 -0
  69. package/lib/typescript/src/assets/ProceduralCache.d.ts +45 -0
  70. package/lib/typescript/src/assets/font.d.ts +53 -0
  71. package/lib/typescript/src/assets/loft.d.ts +31 -0
  72. package/lib/typescript/src/assets/model.d.ts +58 -0
  73. package/lib/typescript/src/assets/modelling.d.ts +157 -0
  74. package/lib/typescript/src/assets/shape.d.ts +203 -0
  75. package/lib/typescript/src/assets/source.d.ts +10 -0
  76. package/lib/typescript/src/assets/source.web.d.ts +8 -0
  77. package/lib/typescript/src/assets/storage.d.ts +2 -0
  78. package/lib/typescript/src/assets/storage.shared.d.ts +7 -0
  79. package/lib/typescript/src/assets/storage.web.d.ts +7 -0
  80. package/lib/typescript/src/assets/surface.d.ts +17 -0
  81. package/lib/typescript/src/assets/texture.d.ts +30 -0
  82. package/lib/typescript/src/drawing/DrawingCanvas.d.ts +5 -0
  83. package/lib/typescript/src/drawing/DrawingCanvas.web.d.ts +4 -0
  84. package/lib/typescript/src/drawing/DrawingDocument.d.ts +210 -0
  85. package/lib/typescript/src/drawing/types.d.ts +12 -0
  86. package/lib/typescript/src/index.d.ts +45 -0
  87. package/lib/typescript/src/input/Joystick.d.ts +20 -0
  88. package/lib/typescript/src/input/Joystick.web.d.ts +13 -0
  89. package/lib/typescript/src/input/keyboard.d.ts +17 -0
  90. package/lib/typescript/src/media/audio.d.ts +46 -0
  91. package/lib/typescript/src/media/haptics.d.ts +22 -0
  92. package/lib/typescript/src/media/output.web.d.ts +4 -0
  93. package/lib/typescript/src/native/BrowserEngine.d.ts +8 -0
  94. package/lib/typescript/src/native/EngineBridge.d.ts +26 -0
  95. package/lib/typescript/src/native/NativeNayanEngine.d.ts +5 -0
  96. package/lib/typescript/src/native/NativeNayanEngine.web.d.ts +10 -0
  97. package/lib/typescript/src/native/prepare.d.ts +3 -0
  98. package/lib/typescript/src/native/prepare.web.d.ts +2 -0
  99. package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +211 -0
  100. package/lib/typescript/src/render/GameView.d.ts +107 -0
  101. package/lib/typescript/src/render/camera.d.ts +6 -0
  102. package/lib/typescript/src/render/host.d.ts +29 -0
  103. package/lib/typescript/src/render/host.web.d.ts +16 -0
  104. package/lib/typescript/src/render/light.d.ts +12 -0
  105. package/lib/typescript/src/render/meshes.d.ts +45 -0
  106. package/lib/typescript/src/render/quality.d.ts +48 -0
  107. package/lib/typescript/src/render/responder.d.ts +2 -0
  108. package/lib/typescript/src/render/responder.web.d.ts +40 -0
  109. package/lib/typescript/src/render/touch.d.ts +26 -0
  110. package/lib/typescript/src/render/useWorld.d.ts +20 -0
  111. package/lib/typescript/src/types.d.ts +81 -0
  112. package/lib/typescript/src/world/Scoreboard.d.ts +75 -0
  113. package/lib/typescript/src/world/TransformBatch.d.ts +39 -0
  114. package/lib/typescript/src/world/World.d.ts +207 -0
  115. package/lib/typescript/src/world/color.d.ts +18 -0
  116. package/lib/typescript/src/world/desc.d.ts +17 -0
  117. package/lib/typescript/src/world/effects.d.ts +157 -0
  118. package/lib/typescript/src/world/quat.d.ts +31 -0
  119. package/lib/typescript/src/world/types.d.ts +238 -0
  120. package/lib/web/audio-worklet.js +29 -0
  121. package/lib/web/engine_core_bg.wasm +0 -0
  122. package/lib/web/index.js +8240 -0
  123. package/lib/web/types/src/assets/AssetBytesCache.d.ts +6 -0
  124. package/lib/web/types/src/assets/AssetCache.d.ts +8 -0
  125. package/lib/web/types/src/assets/AssetLoader.d.ts +10 -0
  126. package/lib/web/types/src/assets/CacheGeneration.d.ts +2 -0
  127. package/lib/web/types/src/assets/IndexedDbCache.d.ts +19 -0
  128. package/lib/web/types/src/assets/ProceduralCache.d.ts +44 -0
  129. package/lib/web/types/src/assets/font.d.ts +52 -0
  130. package/lib/web/types/src/assets/loft.d.ts +30 -0
  131. package/lib/web/types/src/assets/model.d.ts +57 -0
  132. package/lib/web/types/src/assets/modelling.d.ts +156 -0
  133. package/lib/web/types/src/assets/shape.d.ts +202 -0
  134. package/lib/web/types/src/assets/source.d.ts +7 -0
  135. package/lib/web/types/src/assets/storage.d.ts +6 -0
  136. package/lib/web/types/src/assets/storage.shared.d.ts +6 -0
  137. package/lib/web/types/src/assets/surface.d.ts +16 -0
  138. package/lib/web/types/src/assets/texture.d.ts +29 -0
  139. package/lib/web/types/src/drawing/DrawingCanvas.d.ts +3 -0
  140. package/lib/web/types/src/drawing/DrawingDocument.d.ts +209 -0
  141. package/lib/web/types/src/drawing/types.d.ts +11 -0
  142. package/lib/web/types/src/index.d.ts +44 -0
  143. package/lib/web/types/src/input/Joystick.d.ts +12 -0
  144. package/lib/web/types/src/input/keyboard.d.ts +16 -0
  145. package/lib/web/types/src/media/audio.d.ts +45 -0
  146. package/lib/web/types/src/media/haptics.d.ts +21 -0
  147. package/lib/web/types/src/media/output.d.ts +3 -0
  148. package/lib/web/types/src/native/BrowserEngine.d.ts +7 -0
  149. package/lib/web/types/src/native/EngineBridge.d.ts +25 -0
  150. package/lib/web/types/src/native/NativeNayanEngine.d.ts +9 -0
  151. package/lib/web/types/src/native/prepare.d.ts +1 -0
  152. package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +210 -0
  153. package/lib/web/types/src/render/GameView.d.ts +106 -0
  154. package/lib/web/types/src/render/camera.d.ts +5 -0
  155. package/lib/web/types/src/render/host.d.ts +15 -0
  156. package/lib/web/types/src/render/light.d.ts +11 -0
  157. package/lib/web/types/src/render/meshes.d.ts +44 -0
  158. package/lib/web/types/src/render/quality.d.ts +47 -0
  159. package/lib/web/types/src/render/responder.d.ts +39 -0
  160. package/lib/web/types/src/render/touch.d.ts +25 -0
  161. package/lib/web/types/src/render/useWorld.d.ts +19 -0
  162. package/lib/web/types/src/types.d.ts +80 -0
  163. package/lib/web/types/src/world/Scoreboard.d.ts +74 -0
  164. package/lib/web/types/src/world/TransformBatch.d.ts +38 -0
  165. package/lib/web/types/src/world/World.d.ts +206 -0
  166. package/lib/web/types/src/world/color.d.ts +17 -0
  167. package/lib/web/types/src/world/desc.d.ts +16 -0
  168. package/lib/web/types/src/world/effects.d.ts +156 -0
  169. package/lib/web/types/src/world/quat.d.ts +30 -0
  170. package/lib/web/types/src/world/types.d.ts +237 -0
  171. package/native/android/CMakeLists.txt +34 -0
  172. package/native/android/NayanEngineSpec.h +15 -0
  173. package/native/android/build.gradle +26 -0
  174. package/native/android/codegen/CMakeLists.txt +3 -0
  175. package/native/android/proguard-rules.pro +2 -0
  176. package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +295 -0
  177. package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceViewManager.java +45 -0
  178. package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +24 -0
  179. package/native/core/build/EngineCore.xcframework/Info.plist +43 -0
  180. package/native/core/build/EngineCore.xcframework/ios-arm64/libengine_core.a +0 -0
  181. package/native/core/build/EngineCore.xcframework/ios-arm64-simulator/libengine_core.a +0 -0
  182. package/native/core/build/android/arm64-v8a/libengine_core.a +0 -0
  183. package/native/core/build/android/armeabi-v7a/libengine_core.a +0 -0
  184. package/native/core/build/android/x86/libengine_core.a +0 -0
  185. package/native/core/build/android/x86_64/libengine_core.a +0 -0
  186. package/native/core/include/drawing-licenses.txt +58 -0
  187. package/native/core/include/engine_core.h +331 -0
  188. package/native/cpp/NayanEngineModule.cpp +998 -0
  189. package/native/cpp/NayanEngineModule.h +174 -0
  190. package/native/cpp/generated/NayanEngineSpecJSI.cpp +2 -0
  191. package/native/cpp/generated/NayanEngineSpecJSI.h +1026 -0
  192. package/native/ios/NayanEngineProvider.h +5 -0
  193. package/native/ios/NayanEngineProvider.mm +21 -0
  194. package/native/ios/NayanEngineSurface.mm +252 -0
  195. package/native/scripts/check-package.mjs +39 -0
  196. package/package.json +162 -4
  197. package/react-native.config.js +18 -0
  198. package/src/native/spec/NativeNayanEngine.ts +265 -0
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ import { Image } from 'react-native';
4
+ // Loads asset bytes for the engine: `require("./file.ext")` assets (resolved by the bundler) or URIs.
5
+ import { assetBytes } from "./AssetBytesCache.js";
6
+
7
+ /** A `require("./file.ext")` asset, or a URI (http(s):// or file://). */
8
+
9
+ /** The URI an asset resolves to (a Metro dev-server URL in development, a bundle path in release). */
10
+ export function assetUri(source) {
11
+ return typeof source === 'number' ? Image.resolveAssetSource(source)?.uri : source;
12
+ }
13
+
14
+ /** Copies a bundled asset to a local file (Android release bundles them as res/raw resources). */
15
+ async function localAssetUri(source) {
16
+ let Asset;
17
+ try {
18
+ ({
19
+ Asset
20
+ } = require('expo-asset'));
21
+ } catch {
22
+ throw new Error('loading bundled assets in Android release builds needs expo-asset installed');
23
+ }
24
+ const {
25
+ name,
26
+ type,
27
+ hash,
28
+ uri
29
+ } = Asset.fromModule(source);
30
+ // fromModule marks images as "downloaded" with localUri = the drawable name (fine for <Image>, not
31
+ // for reading bytes); an Asset without dimensions makes expo-asset copy the resource to a file.
32
+ const asset = await new Asset({
33
+ name,
34
+ type,
35
+ hash,
36
+ uri
37
+ }).downloadAsync();
38
+ if (!asset.localUri?.includes(':')) throw new Error(`couldn't copy the bundled asset ${name}`);
39
+ return asset.localUri;
40
+ }
41
+
42
+ /** Fetches an asset's bytes. */
43
+ export async function loadAssetBytes(source) {
44
+ const uri = assetUri(source);
45
+ if (!uri) throw new Error("couldn't resolve the asset (is its extension in Metro's assetExts?)");
46
+ const bytes = await assetBytes(uri, async () => {
47
+ // Android bundled resources must be copied before their bytes can be read.
48
+ const url = typeof source === 'number' && !uri.includes(':') ? await localAssetUri(source) : uri;
49
+ const response = await fetch(url);
50
+ if (!response.ok && !url.startsWith('file:')) throw new Error(`HTTP ${response.status} for ${uri}`);
51
+ return response.arrayBuffer();
52
+ });
53
+ return {
54
+ uri,
55
+ bytes
56
+ };
57
+ }
58
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ import { assetBytes } from "./AssetBytesCache.js";
4
+ /** Browser assets use URLs (including URLs emitted by Vite/webpack imports). */
5
+
6
+ export function assetUri(source) {
7
+ return typeof source === 'string' ? source : undefined;
8
+ }
9
+ export async function loadAssetBytes(source) {
10
+ const uri = assetUri(source);
11
+ if (!uri) throw new Error('Engine: browser assets need a URL; use an asset import or a public URL');
12
+ const bytes = await assetBytes(uri, async () => {
13
+ const response = await fetch(uri);
14
+ if (!response.ok) throw new Error(`HTTP ${response.status} for ${uri}`);
15
+ return response.arrayBuffer();
16
+ });
17
+ return {
18
+ uri,
19
+ bytes
20
+ };
21
+ }
22
+ //# sourceMappingURL=source.web.js.map
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { proceduralStorage, readPersistentAsset, writePersistentAsset, removePersistentAsset, clearPersistentStorage } from "./storage.shared.js";
4
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ // Persistence is implemented by the shared Rust core, not an application filesystem dependency.
4
+ import NativeEngine from '../native/NativeNayanEngine';
5
+ export function proceduralStorage(revision) {
6
+ const native = NativeEngine;
7
+ return {
8
+ // The Rust store checksums every record (SHA-256) and rejects any that don't match.
9
+ verified: true,
10
+ read(key) {
11
+ if (typeof native?.cacheRead !== 'function') return null;
12
+ const data = native.cacheRead(`procedural:${revision}:${key}`);
13
+ return data.byteLength ? new Uint8Array(data) : null;
14
+ },
15
+ write(key, bytes) {
16
+ if (typeof native?.cacheWrite !== 'function') return;
17
+ const data = bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes.buffer : bytes.slice().buffer;
18
+ if (!native.cacheWrite(`procedural:${revision}:${key}`, data)) throw new Error(native.loadError() || 'Engine cache write failed');
19
+ }
20
+ };
21
+ }
22
+ export async function readPersistentAsset(key) {
23
+ if (typeof NativeEngine?.cacheRead !== 'function') return null;
24
+ const bytes = NativeEngine.cacheRead(`source:${key}`);
25
+ return bytes.byteLength ? bytes : null;
26
+ }
27
+ export async function writePersistentAsset(key, bytes) {
28
+ // Keep the async loader contract; writes themselves are serialized by the Rust storage lock.
29
+ if (typeof NativeEngine?.cacheWrite === 'function' && !NativeEngine.cacheWrite(`source:${key}`, bytes)) throw new Error(NativeEngine.loadError() || 'Engine cache write failed');
30
+ }
31
+ export async function removePersistentAsset(key) {
32
+ if (typeof NativeEngine?.cacheRemove === 'function') NativeEngine.cacheRemove(`source:${key}`);
33
+ }
34
+ export async function clearPersistentStorage() {
35
+ if (typeof NativeEngine?.cacheClear !== 'function') throw new Error('Rebuild the app with engine cache support');
36
+ if (!NativeEngine.cacheClear()) throw new Error(NativeEngine.loadError() || 'Engine cache clear failed');
37
+ }
38
+ //# sourceMappingURL=storage.shared.js.map
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ import { clearedAssetStorage, flushAssetStorage, prepareEngine, readSavedAsset } from "../native/NativeNayanEngine.web.js";
4
+ // Browser platform I/O is asynchronous; Rust still owns record validation and cache policy.
5
+
6
+ import * as shared from "./storage.shared.js";
7
+ export function proceduralStorage(revision) {
8
+ const storage = shared.proceduralStorage(revision);
9
+ if (!storage) return;
10
+ return {
11
+ verified: storage.verified,
12
+ read: storage.read,
13
+ write(key, bytes) {
14
+ storage.write(key, bytes);
15
+ return flushAssetStorage();
16
+ }
17
+ };
18
+ }
19
+ export async function readPersistentAsset(key) {
20
+ return readSavedAsset(`source:${key}`);
21
+ }
22
+ export async function writePersistentAsset(key, bytes) {
23
+ const writing = shared.writePersistentAsset(key, bytes);
24
+ const saved = flushAssetStorage();
25
+ await Promise.all([writing, saved]);
26
+ }
27
+ export async function removePersistentAsset(key) {
28
+ const removing = shared.removePersistentAsset(key);
29
+ const saved = flushAssetStorage();
30
+ await Promise.all([removing, saved]);
31
+ }
32
+ export async function clearPersistentStorage() {
33
+ await prepareEngine();
34
+ const clearing = shared.clearPersistentStorage();
35
+ const saved = clearedAssetStorage();
36
+ await Promise.all([clearing, saved]);
37
+ }
38
+ //# sourceMappingURL=storage.web.js.map
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ import { recolor, smoothNormals } from "./shape.js";
4
+ /**
5
+ * Samples an arbitrary surface on u/v in [0,1]. Winding follows dP/du cross dP/dv.
6
+ * Use for terrain, cloth, wings, twisted ribbons and custom mathematical forms. Wrapped edges
7
+ * retain texture seams; coincident pole vertices share normals. Degenerate triangles are omitted.
8
+ */
9
+ export function parametricSurface(sample, options = {}) {
10
+ const nu = options.uSegments ?? 32,
11
+ nv = options.vSegments ?? 16;
12
+ if (![nu, nv].every(n => Number.isInteger(n) && n >= 1 && n <= 1024) || (nu + 1) * (nv + 1) > 1_000_000) throw new Error('parametricSurface: invalid segments or surface exceeds one million vertices');
13
+ const vertices = new Float32Array((nu + 1) * (nv + 1) * 11);
14
+ for (let y = 0; y <= nv; y++) for (let x = 0; x <= nu; x++) {
15
+ const u = x / nu,
16
+ v = y / nv;
17
+ const p = sample(options.wrapU && x === nu ? 0 : u, options.wrapV && y === nv ? 0 : v);
18
+ if (p.some(c => !Number.isFinite(c))) throw new Error('parametricSurface: sample returned a non-finite position');
19
+ vertices.set([p[0], p[1], p[2], 0, 1, 0, 1, 1, 1, u, v], (y * (nu + 1) + x) * 11);
20
+ }
21
+ const indices = [];
22
+ const triangle = (a, b, c) => {
23
+ const v = vertices;
24
+ const oa = a * 11,
25
+ ob = b * 11,
26
+ oc = c * 11;
27
+ const x1 = v[ob] - v[oa],
28
+ y1 = v[ob + 1] - v[oa + 1],
29
+ z1 = v[ob + 2] - v[oa + 2];
30
+ const x2 = v[oc] - v[oa],
31
+ y2 = v[oc + 1] - v[oa + 1],
32
+ z2 = v[oc + 2] - v[oa + 2];
33
+ if (Math.hypot(y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2) > 0) indices.push(a, b, c);
34
+ };
35
+ for (let y = 0; y < nv; y++) for (let x = 0; x < nu; x++) {
36
+ const a = y * (nu + 1) + x,
37
+ b = a + nu + 1;
38
+ triangle(a, a + 1, b);
39
+ triangle(a + 1, b + 1, b);
40
+ }
41
+ const geometry = smoothNormals({
42
+ vertices,
43
+ indices: new Uint32Array(indices)
44
+ });
45
+ return options.color ? recolor(geometry, typeof options.color === 'function' ? options.color : () => options.color) : geometry;
46
+ }
47
+ //# sourceMappingURL=surface.js.map
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ import NativeEngine from '../native/NativeNayanEngine';
4
+ // Textures: PNG / JPEG images, decoded by the Rust core, drawn on built-in shapes or models.
5
+ import { meshInfo } from "../render/meshes.js";
6
+ import { AssetLoader } from "./AssetLoader.js";
7
+ import { registerCoreMesh } from "./model.js";
8
+
9
+ /** A loaded image. Pass it as an entity's `texture`. */
10
+
11
+ const loader = new AssetLoader('loadTexture');
12
+
13
+ /**
14
+ * Initializes the engine automatically. Loads a PNG or JPEG once (up to 4096 x 4096). Use it on any entity: `{ mesh: "cube", texture }`.
15
+ * The entity's `color` tints it; `textureRegion` shows part of it (sprite sheets, card atlases).
16
+ *
17
+ * ```ts
18
+ * const crate = await loadTexture(require("./assets/crate.png"));
19
+ * world.spawn({ mesh: "cube", texture: crate });
20
+ * ```
21
+ */
22
+ export function loadTexture(source) {
23
+ return loader.load(source, (native, bytes) => {
24
+ const finish = id => {
25
+ if (id < 0) throw new Error(native.loadError() || 'not a PNG or JPEG image');
26
+ const [width, height] = native.textureSize(id);
27
+ return {
28
+ id,
29
+ width,
30
+ height
31
+ };
32
+ };
33
+ // Decoded on a background native thread where the app's build supports it.
34
+ return typeof native.textureLoadAsync === 'function' ? native.textureLoadAsync(bytes).then(finish) : finish(native.textureLoad(bytes));
35
+ });
36
+ }
37
+
38
+ /** Pixels of a texture id (aliasing native memory), for the renderer. */
39
+ export function textureImage(id) {
40
+ const [width, height] = NativeEngine.textureSize(id);
41
+ return {
42
+ width,
43
+ height,
44
+ pixels: new Uint8Array(NativeEngine.texturePixels(id))
45
+ };
46
+ }
47
+ const variants = new Map();
48
+
49
+ /**
50
+ * The mesh id that draws `mesh`'s geometry with `texture`: a textured variant made on first use
51
+ * (it shares the geometry, colliders and picking of the original).
52
+ */
53
+ export function texturedMesh(mesh, texture) {
54
+ const key = `${mesh}:${texture.id}`;
55
+ let id = variants.get(key);
56
+ if (id === undefined) {
57
+ const base = meshInfo(mesh);
58
+ if (!base) throw new Error('texture: this mesh has nothing to draw');
59
+ id = NativeEngine.meshAlias(mesh);
60
+ if (id < 0) throw new Error(`texture: ${NativeEngine.loadError()}`);
61
+ registerCoreMesh(id, {
62
+ texture: texture.id,
63
+ shine: base.shine
64
+ }, () => base.geometry);
65
+ variants.set(key, id);
66
+ }
67
+ return id;
68
+ }
69
+ //# sourceMappingURL=texture.js.map
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ import { memo, useCallback } from 'react';
4
+ import { processColor } from 'react-native';
5
+ import { EngineSurface } from '../render/host';
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ /** Native coalesced finger/Pencil/stylus input, with pinch zoom and pan, bypasses the JS thread. */
8
+ export const DrawingCanvas = /*#__PURE__*/memo(function DrawingCanvas({
9
+ document,
10
+ mode = 'draw',
11
+ background = '#ffffff',
12
+ active = true,
13
+ onChange,
14
+ onError,
15
+ style
16
+ }) {
17
+ const color = processColor(background);
18
+ const change = useCallback(event => {
19
+ if (!active || document.isDisposed || event.nativeEvent.documentId !== document.id) return;
20
+ try {
21
+ onChange?.(JSON.parse(event.nativeEvent.state));
22
+ } catch (failure) {
23
+ onError?.(failure instanceof Error ? failure : new Error(String(failure)));
24
+ }
25
+ }, [onChange, onError, active, document]);
26
+ return /*#__PURE__*/_jsx(EngineSurface, {
27
+ onDrawingChange: onChange ? change : undefined,
28
+ surfaceId: document.id,
29
+ drawingId: active ? document.id : -1,
30
+ drawingMode: mode === 'draw' ? 0 : mode === 'move' ? 1 : 2,
31
+ drawingBackground: typeof color === 'number' ? color & 0xffffff : 0xffffff,
32
+ style: {
33
+ flex: 1,
34
+ ...style
35
+ }
36
+ });
37
+ });
38
+ //# sourceMappingURL=DrawingCanvas.js.map
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+
3
+ import { memo, useEffect, useRef, useState } from 'react';
4
+ import { attachCanvas, detachCanvas } from "../native/NativeNayanEngine.web.js";
5
+ import { warmUpEngine } from "../render/meshes.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export const DrawingCanvas = /*#__PURE__*/memo(function DrawingCanvas({
8
+ document: drawing,
9
+ mode = 'draw',
10
+ background = '#ffffff',
11
+ active = true,
12
+ onError,
13
+ onChange,
14
+ style
15
+ }) {
16
+ const ref = useRef(null);
17
+ const [error, setError] = useState('');
18
+ const live = useRef({
19
+ mode,
20
+ background,
21
+ active,
22
+ onError,
23
+ onChange
24
+ });
25
+ live.current = {
26
+ mode,
27
+ background,
28
+ active,
29
+ onError,
30
+ onChange
31
+ };
32
+ useEffect(() => {
33
+ const canvas = ref.current;
34
+ setError('');
35
+ let alive = true,
36
+ ready = false,
37
+ raf = 0,
38
+ drawingPointer = null;
39
+ const pointers = new Map();
40
+ let lastEvent = 0;
41
+ let oldDistance = 0,
42
+ oldCenter = [0, 0];
43
+ // Measure layout once per event: coalesced samples reuse the event's rectangle.
44
+ const coords = (e, r = canvas.getBoundingClientRect()) => ({
45
+ x: e.clientX - r.left,
46
+ y: e.clientY - r.top,
47
+ pen: e.pointerType === 'pen'
48
+ });
49
+ const cancel = () => {
50
+ if (drawingPointer !== null && !drawing.isDisposed) drawing.cancel();
51
+ drawingPointer = null;
52
+ pointers.clear();
53
+ oldDistance = 0;
54
+ };
55
+ const down = e => {
56
+ if (!ready || drawing.isDisposed || !live.current.active || e.button !== 0) return;
57
+ if ([...pointers.values()].some(p => p.pen) && e.pointerType !== 'pen') return;
58
+ e.preventDefault();
59
+ canvas.focus();
60
+ canvas.setPointerCapture(e.pointerId);
61
+ const p = coords(e);
62
+ pointers.set(e.pointerId, p);
63
+ if (pointers.size === 1 && live.current.mode === 'draw') {
64
+ drawingPointer = e.pointerId;
65
+ drawing.input(0, p.x, p.y, p.pen ? e.pressure : 1);
66
+ } else {
67
+ if (drawingPointer !== null && !drawing.isDisposed) drawing.cancel();
68
+ drawingPointer = null;
69
+ oldDistance = 0;
70
+ }
71
+ };
72
+ const move = e => {
73
+ if (!live.current.active || drawing.isDisposed) return;
74
+ const previous = pointers.get(e.pointerId);
75
+ if (!previous) return;
76
+ const rect = canvas.getBoundingClientRect();
77
+ const p = coords(e, rect);
78
+ pointers.set(e.pointerId, p);
79
+ if (e.pointerId === drawingPointer) {
80
+ const coalesced = e.getCoalescedEvents?.();
81
+ for (const sample of coalesced?.length ? coalesced : [e]) {
82
+ const v = coords(sample, rect);
83
+ drawing.input(1, v.x, v.y, v.pen ? sample.pressure : 1);
84
+ }
85
+ } else if (pointers.size > 1) {
86
+ const points = [...pointers.values()];
87
+ const a = points[0],
88
+ b = points[1];
89
+ const distance = Math.hypot(a.x - b.x, a.y - b.y);
90
+ const center = [(a.x + b.x) / 2, (a.y + b.y) / 2];
91
+ if (oldDistance > 0) drawing.transform(center[0] - oldCenter[0], center[1] - oldCenter[1], distance / oldDistance);
92
+ oldDistance = distance;
93
+ oldCenter = center;
94
+ } else drawing.transform(p.x - previous.x, p.y - previous.y);
95
+ };
96
+ const up = e => {
97
+ if (drawingPointer === e.pointerId && !drawing.isDisposed) {
98
+ const p = coords(e);
99
+ drawing.input(e.type === 'pointercancel' ? 3 : 2, p.x, p.y, p.pen ? e.pressure : 1);
100
+ drawingPointer = null;
101
+ }
102
+ pointers.delete(e.pointerId);
103
+ oldDistance = 0;
104
+ };
105
+ const key = e => {
106
+ if (drawing.isDisposed || !live.current.active || !(e.ctrlKey || e.metaKey) || live.current.mode === 'view') return;
107
+ if (e.key.toLowerCase() === 'z') {
108
+ e.preventDefault();
109
+ e.shiftKey ? drawing.redo() : drawing.undo();
110
+ } else if (e.key.toLowerCase() === 'y') {
111
+ e.preventDefault();
112
+ drawing.redo();
113
+ }
114
+ };
115
+ const wheel = e => {
116
+ if (!ready || drawing.isDisposed || !live.current.active) return;
117
+ e.preventDefault();
118
+ e.ctrlKey || e.metaKey ? drawing.transform(0, 0, Math.exp(-e.deltaY * 0.003)) : drawing.transform(-e.deltaX, -e.deltaY);
119
+ };
120
+ const visibility = () => {
121
+ if (document.hidden) cancel();
122
+ };
123
+ const render = () => {
124
+ if (!alive) return;
125
+ if (ready && !drawing.isDisposed && live.current.active && !document.hidden) {
126
+ const bounds = canvas.getBoundingClientRect();
127
+ const ratio = Math.min(window.devicePixelRatio || 1, 3);
128
+ const w = Math.max(1, Math.round(bounds.width * ratio)),
129
+ h = Math.max(1, Math.round(bounds.height * ratio));
130
+ if (canvas.width !== w || canvas.height !== h) {
131
+ canvas.width = w;
132
+ canvas.height = h;
133
+ }
134
+ try {
135
+ drawing.present(bounds.width, bounds.height, live.current.background, ratio);
136
+ if (live.current.onChange && performance.now() - lastEvent >= 100) {
137
+ lastEvent = performance.now();
138
+ const state = drawing.readChange();
139
+ if (state) live.current.onChange(state);
140
+ }
141
+ } catch (failure) {
142
+ ready = false;
143
+ const error = failure instanceof Error ? failure : new Error(String(failure));
144
+ live.current.onError?.(error);
145
+ setError(error.message);
146
+ }
147
+ }
148
+ raf = requestAnimationFrame(render);
149
+ };
150
+ void warmUpEngine().then(() => alive ? attachCanvas(drawing.id, canvas) : undefined).then(() => {
151
+ if (alive && !drawing.isDisposed) {
152
+ drawing.invalidateView();
153
+ ready = true;
154
+ } else detachCanvas(drawing.id);
155
+ }).catch(failure => {
156
+ if (!alive) return;
157
+ const error = failure instanceof Error ? failure : new Error(String(failure));
158
+ live.current.onError?.(error);
159
+ setError(error.message);
160
+ });
161
+ canvas.addEventListener('pointerdown', down);
162
+ canvas.addEventListener('pointermove', move);
163
+ canvas.addEventListener('pointerup', up);
164
+ canvas.addEventListener('pointercancel', up);
165
+ canvas.addEventListener('lostpointercapture', up);
166
+ canvas.addEventListener('keydown', key);
167
+ canvas.addEventListener('wheel', wheel, {
168
+ passive: false
169
+ });
170
+ window.addEventListener('blur', cancel);
171
+ document.addEventListener('visibilitychange', visibility);
172
+ raf = requestAnimationFrame(render);
173
+ return () => {
174
+ alive = false;
175
+ cancelAnimationFrame(raf);
176
+ cancel();
177
+ detachCanvas(drawing.id);
178
+ canvas.removeEventListener('pointerdown', down);
179
+ canvas.removeEventListener('pointermove', move);
180
+ canvas.removeEventListener('pointerup', up);
181
+ canvas.removeEventListener('pointercancel', up);
182
+ canvas.removeEventListener('lostpointercapture', up);
183
+ canvas.removeEventListener('keydown', key);
184
+ canvas.removeEventListener('wheel', wheel);
185
+ window.removeEventListener('blur', cancel);
186
+ document.removeEventListener('visibilitychange', visibility);
187
+ };
188
+ }, [drawing]);
189
+ return /*#__PURE__*/_jsx("canvas", {
190
+ ref: ref,
191
+ tabIndex: 0,
192
+ "aria-label": error ? `Drawing unavailable: ${error}` : 'Drawing canvas',
193
+ title: error || undefined,
194
+ style: {
195
+ display: 'block',
196
+ flex: 1,
197
+ width: '100%',
198
+ height: '100%',
199
+ minHeight: 0,
200
+ touchAction: 'none',
201
+ outline: 'none',
202
+ ...style
203
+ }
204
+ });
205
+ });
206
+ //# sourceMappingURL=DrawingCanvas.web.js.map