lecodes-viewer 0.19.2 → 0.20.2

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 (30) hide show
  1. package/dist-embed/VERSION.json +3 -3
  2. package/dist-embed/assets/{createViewer2d-D12Wy3VF.js → createViewer2d-Dx-COLjO.js} +1 -1
  3. package/dist-embed/assets/createViewerLite-B91Sj6p_.js +852 -0
  4. package/dist-embed/assets/host-DZ6302Ho.js +168 -0
  5. package/dist-embed/assets/{index-UwRci5mq.js → index-D10DoNfS.js} +1 -1
  6. package/dist-embed/assets/{loadCreatorUiNode-UAdhjRTd.js → loadCreatorUiNode-D87bZHrH.js} +1 -1
  7. package/dist-embed/assets/mapViewImpl-B2JcES8l.js +810 -0
  8. package/dist-embed/assets/maplibre-gl-worker-CJfwIrte.js +8 -0
  9. package/dist-embed/assets/{particles-DxYDmI1O.filamat → particles-Cgp1L6RQ.filamat} +0 -0
  10. package/dist-embed/assets/{particles-quad-DwYo9yCK.filamat → particles-quad-CgrEJN4M.filamat} +0 -0
  11. package/dist-embed/embed.js +9 -9
  12. package/package.json +7 -3
  13. package/src/createViewer.ts +2 -0
  14. package/src/host.ts +3 -0
  15. package/src/ui/nativeViewSystem.ts +2 -91
  16. package/src/ui/presentPlayer.ts +2 -156
  17. package/src/utils/imageNode.ts +5 -0
  18. package/src/viewer/createViewer.ts +26 -2
  19. package/src/viewer/particles-quad.filamat +0 -0
  20. package/src/viewer/particles.filamat +0 -0
  21. package/dist-embed/assets/createViewerLite-CinItTpO.js +0 -707
  22. package/dist-embed/assets/host-Vzbyo0SX.js +0 -162
  23. package/src/assets/banner.png +0 -0
  24. package/src/assets/image2.png +0 -0
  25. package/src/assets/landing.mp4 +0 -0
  26. package/src/assets/neutral_ibl256.ktx +0 -0
  27. package/src/assets/output.mp4 +0 -0
  28. package/src/assets/output2.mp4 +0 -0
  29. package/src/assets/texture.png +0 -0
  30. package/src/assets/vue.svg +0 -1
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "lecodes-viewer",
3
- "version": "0.19.2",
3
+ "version": "0.20.2",
4
4
  "main": "src/createViewer.ts",
5
5
  "dependencies": {
6
- "lecodes-renderer": "0.19.2",
6
+ "lecodes-renderer": "0.20.2",
7
7
  "ogl": "^1.0.11",
8
- "lecodes-viewer-lite": "0.19.2"
8
+ "lecodes-viewer-lite": "0.20.2"
9
9
  },
10
10
  "scripts": {
11
11
  "dev": "vite",
@@ -25,6 +25,10 @@
25
25
  "type": "module",
26
26
  "files": [
27
27
  "src",
28
+ "!src/assets/*.mp4",
29
+ "!src/assets/*.png",
30
+ "!src/assets/*.svg",
31
+ "!src/assets/neutral_ibl256.ktx",
28
32
  "dist-embed",
29
33
  "embed.html",
30
34
  "README.md"
@@ -18,6 +18,8 @@ export { getBuffer } from './utils/fetch'
18
18
  export { decodeKtx2Image, isKtx2Bytes } from 'lecodes-viewer-lite/src/gl/decoders'
19
19
  export type { CreatorMethods, EngineMode, Host, HostOptions, Run, RunOptions, UIFactory } from './host'
20
20
  export type { PreviewError, MappedFrame } from './sourcemapError'
21
+ // The render tree the canvas UI hands back (`_creatorUI.renderTree()`) — the embedder's verify gates walk it.
22
+ export type { RenderNode } from 'lecodes-renderer'
21
23
  export { createCanvasUIRenderer } from './ui/mountCanvasUI'
22
24
  export { createBareUI } from './ui/createBareUI'
23
25
  export type { SafeAreaEdge, SafeAreaSpec } from './ui/safeAreaSpec'
package/src/host.ts CHANGED
@@ -13,6 +13,7 @@ import { createCanvasHost } from './canvas/createCanvasHost'
13
13
  import { putBuffer, getBuffer } from './utils/fetch'
14
14
  import { createNavHostBridge } from 'lecodes-viewer-lite/src/gl/core/navBridge'
15
15
  import { createInputHost } from "lecodes-viewer-lite/src/utils/input"
16
+ import { registerWebPlugins } from "lecodes-viewer-lite/src/plugins"
16
17
  import { createUtils } from './utils/createUtils'
17
18
  import { ensureFontsLoaded, loadBootFonts, type BootFont } from './utils/fonts'
18
19
  import type { SafeAreaSpec } from './ui/safeAreaSpec'
@@ -217,6 +218,8 @@ export const createHost = async (root: HTMLElement, options: HostOptions = {}) =
217
218
  }
218
219
 
219
220
  const _creatorUI = options.ui ? await options.ui(root, canvasHost) : undefined
221
+ // The web twins of the first-party NativeView plugins (camera, map) — shared with the lite host.
222
+ registerWebPlugins(_creatorUI)
220
223
  const _creatorUtils = createUtils({ launchUrl: options.launchUrl, onOrientation: options.onOrientation })
221
224
  _creatorUI?._setCreator(_creator)
222
225
  // Before the ResizeObserver's initial fire, so the first applied layout already has the insets.
@@ -1,91 +1,2 @@
1
- // NativeView on the web host (docs/navigation-presentable-plan.md registerView + the
2
- // call/event channel + the "native" layout node). The embedding app registers DOM factories:
3
- //
4
- // host._creatorUI._registerView("map", (params, channel) => {
5
- // const el = document.createElement("div")
6
- // return { el, call: (method, args) => {...}, destroy: () => {...} }
7
- // })
8
- //
9
- // One SDK NativeView instance = one live DOM instance (keyed by its _viewId), reused across
10
- // embed/fullscreen/pager mounts — that reuse IS the promotion semantics. An unregistered
11
- // name renders a labeled placeholder so a bundle stays inspectable on hosts without the plugin.
12
-
13
- export type WebViewChannel = { emit(event: string, data?: any): void }
14
- export type WebViewInstanceHandle = {
15
- el: HTMLElement
16
- call?(method: string, args: any[]): any | Promise<any>
17
- destroy?(): void
18
- }
19
- export type WebViewFactory = (params: any, channel: WebViewChannel) => WebViewInstanceHandle
20
-
21
- // The SDK-side NativeView element/descriptor surface the system needs (see sdk NativeView.ts).
22
- type SdkNativeView = {
23
- viewName: string
24
- params: any
25
- _viewId: number
26
- _emitViewEvent(event: string, dataJson?: string): void
27
- }
28
-
29
- export const createNativeViewSystem = () => {
30
- const factories = new Map<string, WebViewFactory>()
31
- const instances = new Map<number, WebViewInstanceHandle>()
32
-
33
- const registerView = (name: string, factory: WebViewFactory) => { factories.set(name, factory) }
34
- const isViewSupported = (name: string) => factories.has(name)
35
-
36
- const placeholder = (name: string): WebViewInstanceHandle => {
37
- const el = document.createElement("div")
38
- el.style.cssText = "display:flex;align-items:center;justify-content:center;background:#333;color:#999;font:12px sans-serif"
39
- el.textContent = `NativeView("${name}") — no web factory registered`
40
- return { el }
41
- }
42
-
43
- /** Resolve (or lazily create) the live instance for an SDK NativeView. */
44
- const ensureInstance = (view: SdkNativeView): WebViewInstanceHandle => {
45
- let instance = instances.get(view._viewId)
46
- if (!instance) {
47
- const factory = factories.get(view.viewName)
48
- instance = factory
49
- ? factory(view.params, { emit: (event, data) => view._emitViewEvent(event, data === undefined ? undefined : JSON.stringify(data)) })
50
- : placeholder(view.viewName)
51
- instances.set(view._viewId, instance)
52
- }
53
- return instance
54
- }
55
-
56
- /** The `_creatorUI.viewCall` bridge — JSON in/out, promise-friendly. */
57
- const viewCall = (viewId: number, method: string, args: string, onComplete: (result?: string) => void, onError: (err: string) => void) => {
58
- const instance = instances.get(viewId)
59
- if (!instance?.call) {
60
- onError(`NativeView call "${method}": no live instance or no call handler (viewId ${viewId})`)
61
- return
62
- }
63
- try {
64
- Promise.resolve(instance.call(method, JSON.parse(args))).then(
65
- (result) => onComplete(result === undefined ? undefined : JSON.stringify(result)),
66
- (e) => onError(e instanceof Error ? e.message : String(e)),
67
- )
68
- } catch (e) {
69
- onError(e instanceof Error ? e.message : String(e))
70
- }
71
- }
72
-
73
- /** Mount the live instance into a layout cell (the "native" node's DOM element). A view lives
74
- * in ONE place: mounting here steals it from wherever it was (promotion works the same way
75
- * in reverse — openView steals it from the cell, close returns it via re-mount). */
76
- const mountInto = (view: SdkNativeView, cell: HTMLElement) => {
77
- const { el } = ensureInstance(view)
78
- el.style.position = "absolute"
79
- el.style.inset = "0"
80
- cell.appendChild(el)
81
- }
82
-
83
- const destroy = () => {
84
- for (const i of instances.values()) i.destroy?.()
85
- instances.clear()
86
- }
87
-
88
- return { registerView, isViewSupported, ensureInstance, viewCall, mountInto, destroy }
89
- }
90
-
91
- export type NativeViewSystem = ReturnType<typeof createNativeViewSystem>
1
+ // Moved to viewer-lite (the NativeView registry + channel are shared by both web hosts); re-export shim.
2
+ export * from "lecodes-viewer-lite/src/ui/nativeViewSystem"
@@ -1,156 +1,2 @@
1
- // Destination transition player (docs/navigation-presentable-plan.md, phase 2 web reference).
2
- // Named transitions are predefined TransitionSpecs; both shapes play through element.animate(),
3
- // so a custom spec from the SDK needs no extra machinery.
4
- //
5
- // The static rule (mirrors the Android SurfaceView constraint so apps feel the same): a side
6
- // marked `static` (the scene canvas) never animates — only the screen side moves. Screens are
7
- // position:absolute so they always paint above the in-flow canvas, which makes the degradations
8
- // coherent: entering a scene slides the old screen away to reveal it; leaving a scene slides the
9
- // new screen in over it.
10
-
11
- export type SpecTransform = { x?: number | string, y?: number | string, scale?: number, opacity?: number }
12
- export type TransitionSpecLike = {
13
- duration?: number
14
- easing?: [number, number, number, number]
15
- incoming?: { from?: SpecTransform }
16
- outgoing?: { to?: SpecTransform }
17
- dim?: number
18
- onTop?: "incoming" | "outgoing"
19
- }
20
-
21
- const STACK_EASING: [number, number, number, number] = [0.2, 0, 0, 1]
22
-
23
- const NAMED: Record<string, TransitionSpecLike> = {
24
- "none": {},
25
- "fade": { duration: 280, incoming: { from: { opacity: 0 } } },
26
- "slide-from-right": { duration: 400, incoming: { from: { x: "100%" } }, outgoing: { to: { x: "-30%" } } },
27
- "slide-from-left": { duration: 400, incoming: { from: { x: "-100%" } }, outgoing: { to: { x: "30%" } } },
28
- "slide-from-top": { duration: 400, incoming: { from: { y: "-100%" } }, outgoing: { to: { y: "30%" } } },
29
- "slide-from-bottom": { duration: 400, incoming: { from: { y: "100%" } }, outgoing: { to: { y: "-30%" } } },
30
- "zoom": { duration: 400, easing: [0.33, 1.2, 0.62, 1], incoming: { from: { scale: 0.985 } } },
31
- "zoom-in": { duration: 400, easing: [0.33, 1.2, 0.62, 1], incoming: { from: { scale: 1.08, opacity: 0 } }, onTop: "incoming" },
32
- "zoom-out": { duration: 420, outgoing: { to: { scale: 0.92, opacity: 0 } }, onTop: "outgoing" },
33
- "push": { duration: 350, easing: STACK_EASING, incoming: { from: { x: "100%" } }, outgoing: { to: { x: "-25%" } }, dim: 0.3, onTop: "incoming" },
34
- "pop": { duration: 350, easing: STACK_EASING, incoming: { from: { x: "-25%" } }, outgoing: { to: { x: "100%" } }, dim: 0.3, onTop: "outgoing" },
35
- }
36
-
37
- const toTransform = (t: SpecTransform): string => {
38
- const parts: string[] = []
39
- if (t.x !== undefined || t.y !== undefined) {
40
- const px = (v: number | string | undefined) => v === undefined ? "0px" : typeof v === "number" ? v + "px" : v
41
- parts.push(`translate(${px(t.x)}, ${px(t.y)})`)
42
- }
43
- if (t.scale !== undefined) parts.push(`scale(${t.scale})`)
44
- return parts.length > 0 ? parts.join(" ") : "none"
45
- }
46
-
47
- const poseKeyframe = (t: SpecTransform): Keyframe => {
48
- const kf: Keyframe = { transform: toTransform(t) }
49
- if (t.opacity !== undefined) kf.opacity = t.opacity
50
- return kf
51
- }
52
- const IDENTITY: Keyframe = { transform: "none", opacity: 1 }
53
-
54
- // The exit pose for an outgoing side when the incoming one is static (a scene): mirror the
55
- // incoming entry so the reveal keeps the transition's direction (push's 100%-from-right becomes
56
- // a full slide-out to the left); pure opacity entries become a fade-out.
57
- const mirrorExit = (from: SpecTransform): SpecTransform => {
58
- const neg = (v: number | string | undefined) =>
59
- v === undefined ? undefined : typeof v === "number" ? -v : v.startsWith("-") ? v.slice(1) : "-" + v
60
- const out: SpecTransform = {}
61
- if (from.x !== undefined) out.x = neg(from.x)
62
- if (from.y !== undefined) out.y = neg(from.y)
63
- if (from.scale !== undefined) out.scale = 2 - from.scale
64
- if (from.opacity !== undefined || Object.keys(out).length === 0) out.opacity = 0
65
- return out
66
- }
67
-
68
- type Side = { el: HTMLElement, static?: boolean }
69
-
70
- export const createPresentPlayer = (container: HTMLElement) => {
71
- let finishActive: (() => void) | null = null
72
-
73
- /** Play `transition` between the mounted `incoming` and the still-mounted `outgoing`; calls
74
- * `onDone` exactly once (after the animation, or immediately for none/unsupported) — the
75
- * caller physically unmounts the outgoing side there. A new play() snaps the previous
76
- * transition to its end first. */
77
- const play = (opts: {
78
- incoming?: Side
79
- outgoing?: Side
80
- transition: string | TransitionSpecLike | null | undefined
81
- onDone: () => void
82
- }) => {
83
- finishActive?.()
84
-
85
- const spec = typeof opts.transition === "string" ? NAMED[opts.transition] : opts.transition ?? undefined
86
- const inSide = opts.incoming && !opts.incoming.static ? opts.incoming.el : null
87
- const outSide = opts.outgoing && !opts.outgoing.static ? opts.outgoing.el : null
88
-
89
- let inFrom = spec?.incoming?.from
90
- let outTo = spec?.outgoing?.to
91
-
92
- // Static-side degradations (see header). A poseless spec ("none") stays instant — the
93
- // degradations only reshape transitions that actually wanted to move something.
94
- if (opts.incoming?.static && outSide && (spec?.incoming || spec?.outgoing)) {
95
- // The incoming scene can't animate: unless this is an exit-shaped transition (onTop:
96
- // "outgoing" — pop/zoom-out already fully remove the old side), the outgoing screen leaves
97
- // by the mirror of the entry it was supposed to be covered by.
98
- if (spec?.onTop !== "outgoing") outTo = inFrom ? mirrorExit(inFrom) : (outTo ?? { opacity: 0 })
99
- inFrom = undefined
100
- }
101
- if (opts.outgoing?.static && inSide && !inFrom && spec && Object.keys(spec).length > 0) {
102
- inFrom = { opacity: 0 } // something must move; fade the screen in over the scene
103
- }
104
-
105
- const hasWork = (inSide && inFrom) || (outSide && outTo)
106
- if (!spec || !hasWork || typeof (inSide ?? outSide)?.animate !== "function") {
107
- opts.onDone()
108
- return
109
- }
110
-
111
- const duration = spec.duration ?? 300
112
- const easing = spec.easing ? `cubic-bezier(${spec.easing.join(",")})` : "cubic-bezier(0.25, 0.1, 0.25, 1)"
113
- const animations: Animation[] = []
114
-
115
- // z-order for the duration of the transition (screens only — the static canvas stays in
116
- // flow at the bottom). Dim sits between the two.
117
- const onTop = spec.onTop ?? "incoming"
118
- const topEl = onTop === "incoming" ? inSide : outSide
119
- const bottomEl = onTop === "incoming" ? outSide : inSide
120
- if (topEl) topEl.style.zIndex = "3"
121
- if (bottomEl) bottomEl.style.zIndex = "1"
122
-
123
- let dimEl: HTMLElement | null = null
124
- if (spec.dim && spec.dim > 0) {
125
- dimEl = document.createElement("div")
126
- dimEl.style.cssText = "position:absolute;inset:0;background:#000;pointer-events:none;z-index:2"
127
- container.appendChild(dimEl)
128
- // Entering (push): the under layer darkens; exiting (pop): it un-darkens.
129
- const [a, b] = onTop === "incoming" ? [0, spec.dim] : [spec.dim, 0]
130
- animations.push(dimEl.animate([{ opacity: a }, { opacity: b }], { duration, easing }))
131
- }
132
-
133
- if (inSide && inFrom) {
134
- animations.push(inSide.animate([poseKeyframe(inFrom), IDENTITY], { duration, easing }))
135
- }
136
- if (outSide && outTo) {
137
- animations.push(outSide.animate([IDENTITY, poseKeyframe(outTo)], { duration, easing, fill: "forwards" }))
138
- }
139
-
140
- let done = false
141
- const cleanup = () => {
142
- if (done) return
143
- done = true
144
- finishActive = null
145
- for (const a of animations) a.cancel() // drops fill:forwards so a detached-not-freed screen restores clean
146
- if (topEl) topEl.style.zIndex = ""
147
- if (bottomEl) bottomEl.style.zIndex = ""
148
- dimEl?.remove()
149
- opts.onDone()
150
- }
151
- finishActive = cleanup
152
- Promise.all(animations.map(a => a.finished)).then(cleanup, cleanup)
153
- }
154
-
155
- return { play, finish: () => finishActive?.() }
156
- }
1
+ // Moved to viewer-lite (both web hosts play the same destination transitions); re-export shim.
2
+ export * from "lecodes-viewer-lite/src/ui/presentPlayer"
@@ -99,6 +99,11 @@ function configureImageSrc(host: ImageHost, el: HTMLElement, src: ImageSrc, tint
99
99
  ;(el as any)._canvasSurface = surfaceId
100
100
  el.removeAttribute("data-viewbox")
101
101
  el.src = host.canvasHost?.surfaceToDataUrl(surfaceId) ?? ""
102
+ } else if (typeof src === "object" && "scene2d" in src) {
103
+ // UIImage(scene2d): a live 2D scene drawn into the box — desktop only so far (parity
104
+ // ui-scene2d-image); a blank box here rather than a bogus blob url.
105
+ el.removeAttribute("data-viewbox")
106
+ el.removeAttribute("src")
102
107
  } else {
103
108
  el.removeAttribute("data-viewbox")
104
109
  el.src = typeof src === "object" ? getUrl(src._id) : src
@@ -440,6 +440,17 @@ export const createViewer = async (canvas: HTMLCanvasElement, options: ViewerOpt
440
440
  // Screen inputs are logical px; scale to backing px for the native (viewport-space) pick.
441
441
  raycastView: (offsetX: number, offsetY: number) => module._raycastView(offsetX * resFactor, offsetY * resFactor),
442
442
  setCulling: module._setCulling,
443
+ // Draw order / per-instance depth state (Mesh.renderPriority, Material.depthTest / depthWrite) —
444
+ // only once the wasm carries the exports; the SDK feature-detects them.
445
+ setRenderPriority: module._setRenderPriority,
446
+ setMaterialDepthTest: module._setMaterialDepthTest ? (id: number, on: boolean) => module._setMaterialDepthTest(id, on ? 1 : 0) : undefined,
447
+ setMaterialDepthWrite: module._setMaterialDepthWrite ? (id: number, on: boolean) => module._setMaterialDepthWrite(id, on ? 1 : 0) : undefined,
448
+ setMaterialCulling: module._setMaterialCulling,
449
+ setMaterialStencil: module._setMaterialStencil
450
+ ? (id: number, write: boolean, test: number, ref: number, onPass: number, onFail: number, onDepthFail: number, readMask: number, writeMask: number) =>
451
+ module._setMaterialStencil(id, write ? 1 : 0, test, ref, onPass, onFail, onDepthFail, readMask, writeMask)
452
+ : undefined,
453
+ setSceneStencil: module._setSceneStencil ? (sceneId: number, on: boolean) => module._setSceneStencil(sceneId, on ? 1 : 0) : undefined,
443
454
  setGlbCulling: module._setGlbCulling,
444
455
  // Culling default for animated GLBs (Model.load): only once the wasm carries the export — an older
445
456
  // binary leaves the SDK on the always-draw default (see bridges.d.ts).
@@ -615,7 +626,7 @@ export const createViewer = async (canvas: HTMLCanvasElement, options: ViewerOpt
615
626
  createMaterial: (systemId: number) => {
616
627
  return module._createMaterialInstance(compileMaterial(systemId))
617
628
  },
618
- setMesh(entityId: number, materialId: number, vertices: Float32Array, normals: Float32Array, indices: Uint16Array, uv: Float32Array, meshType: number, uv1?: Float32Array) {
629
+ setMesh(entityId: number, materialId: number, vertices: Float32Array, normals: Float32Array, indices: Uint16Array, uv: Float32Array, meshType: number, uv1?: Float32Array, colors?: Uint8Array) {
619
630
  const ptrVertices = module._malloc(vertices.byteLength)
620
631
  const ptrNormals = module._malloc(normals.byteLength)
621
632
  const ptrIndices = module._malloc(indices.byteLength)
@@ -625,6 +636,15 @@ export const createViewer = async (canvas: HTMLCanvasElement, options: ViewerOpt
625
636
  module.HEAPU16.set(indices, ptrIndices/2)
626
637
  module.HEAPF32.set(uv, ptrUv/4)
627
638
 
639
+ // the vertex colours ride the newest export (createMeshC); a wasm without it draws white
640
+ if (colors && module._createMeshC) {
641
+ const ptrUv1 = uv1 ? module._malloc(uv1.byteLength) : 0
642
+ if (uv1 && ptrUv1) module.HEAPF32.set(uv1, ptrUv1 / 4)
643
+ const ptrColors = module._malloc(colors.byteLength)
644
+ module.HEAPU8.set(colors, ptrColors)
645
+ module._createMeshC(entityId, materialId, ptrVertices, ptrNormals, ptrIndices, ptrUv, vertices.length / 3, indices.length, meshType, ptrUv1, ptrColors)
646
+ return
647
+ }
628
648
  // the lightmap UV set rides the newer export; a wasm without it duplicates uv into UV1
629
649
  if (uv1 && module._createMeshEx) {
630
650
  const ptrUv1 = module._malloc(uv1.byteLength)
@@ -832,7 +852,11 @@ export const createViewer = async (canvas: HTMLCanvasElement, options: ViewerOpt
832
852
  return out
833
853
  },
834
854
  getGlbClipSet: (entityId: number) => module._getGlbClipSet(entityId),
835
- sliceClip: (clipSetId: number, clip: number, start: number, end: number) => module._sliceClip(clipSetId, clip, start, end),
855
+ deriveClip: (clipSetId: number, clip: number, mirror: boolean, start: number, end: number) => {
856
+ if (typeof module._deriveClip === "function") return module._deriveClip(clipSetId, clip, mirror ? 1 : 0, start, end)
857
+ if (mirror) { console.warn("creator-gl: this wasm cannot mirror clips — rebuild it"); return 0 } // a wasm from before 2026-09-06
858
+ return module._sliceClip(clipSetId, clip, start < 0 ? 0 : start, end < 0 ? 1e9 : end)
859
+ },
836
860
  destroyClipSet: (clipSetId: number) => module._destroyClipSet(clipSetId),
837
861
  animatorCreate: (entityId: number) => module._animatorCreate(entityId),
838
862
  animatorDestroy: (animatorId: number) => module._animatorDestroy(animatorId),
Binary file
Binary file