@zephyr3d/scene 0.9.0 → 0.9.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 (149) hide show
  1. package/dist/animation/animationset.js +135 -133
  2. package/dist/animation/animationset.js.map +1 -1
  3. package/dist/animation/cloth/gpu_cloth_system.js +9 -1
  4. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  5. package/dist/animation/fixed_geometry_cache_track.js +5 -1
  6. package/dist/animation/fixed_geometry_cache_track.js.map +1 -1
  7. package/dist/animation/geometry_cache_utils.js +20 -4
  8. package/dist/animation/geometry_cache_utils.js.map +1 -1
  9. package/dist/animation/ik/ik_angle_constraint.js +2 -6
  10. package/dist/animation/ik/ik_angle_constraint.js.map +1 -1
  11. package/dist/animation/ik/two_bone_ik_solver.js +2 -6
  12. package/dist/animation/ik/two_bone_ik_solver.js.map +1 -1
  13. package/dist/animation/joint_dynamics/collision.js +60 -12
  14. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  15. package/dist/animation/joint_dynamics/constraints.js +20 -4
  16. package/dist/animation/joint_dynamics/constraints.js.map +1 -1
  17. package/dist/animation/joint_dynamics/controller.js +151 -103
  18. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  19. package/dist/animation/joint_dynamics/solver.js +21 -11
  20. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  21. package/dist/animation/joint_dynamics/types.js +15 -3
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/pca_geometry_cache_track.js +5 -1
  24. package/dist/animation/pca_geometry_cache_track.js.map +1 -1
  25. package/dist/animation/skeleton.js +2 -2
  26. package/dist/animation/skeleton.js.map +1 -1
  27. package/dist/animation/skeleton_modifier.js +2 -6
  28. package/dist/animation/skeleton_modifier.js.map +1 -1
  29. package/dist/animation/spring/spring_system.js +87 -114
  30. package/dist/animation/spring/spring_system.js.map +1 -1
  31. package/dist/app/app.js.map +1 -1
  32. package/dist/app/engine.js +1 -1
  33. package/dist/app/engine.js.map +1 -1
  34. package/dist/app/screen.js +4 -4
  35. package/dist/app/screen.js.map +1 -1
  36. package/dist/app/scriptingsystem.js +24 -1
  37. package/dist/app/scriptingsystem.js.map +1 -1
  38. package/dist/app/scriptregistry.js +165 -144
  39. package/dist/app/scriptregistry.js.map +1 -1
  40. package/dist/asset/assetmanager.js +2 -2
  41. package/dist/asset/assetmanager.js.map +1 -1
  42. package/dist/asset/model.js +3 -3
  43. package/dist/asset/model.js.map +1 -1
  44. package/dist/camera/camera.js +185 -185
  45. package/dist/camera/camera.js.map +1 -1
  46. package/dist/camera/orbit.js.map +1 -1
  47. package/dist/index.d.ts +794 -261
  48. package/dist/index.js +2 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/material/material.js +290 -288
  51. package/dist/material/material.js.map +1 -1
  52. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +13 -26
  53. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  54. package/dist/material/pbrmr.js +1 -11
  55. package/dist/material/pbrmr.js.map +1 -1
  56. package/dist/material/sprite.js +6 -6
  57. package/dist/material/sprite.js.map +1 -1
  58. package/dist/material/terrain-cm.js +2 -2
  59. package/dist/material/terrain-cm.js.map +1 -1
  60. package/dist/posteffect/taa.js +31 -39
  61. package/dist/posteffect/taa.js.map +1 -1
  62. package/dist/render/drawable.js +5 -1
  63. package/dist/render/drawable.js.map +1 -1
  64. package/dist/render/rendergraph/device_pool_allocator.js +29 -3
  65. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  66. package/dist/render/rendergraph/executor.js +283 -33
  67. package/dist/render/rendergraph/executor.js.map +1 -1
  68. package/dist/render/rendergraph/forward_plus_builder.js +338 -108
  69. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  70. package/dist/render/rendergraph/history_resource_manager.js +236 -156
  71. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  72. package/dist/render/rendergraph/history_resources.js +10 -0
  73. package/dist/render/rendergraph/history_resources.js.map +1 -0
  74. package/dist/render/rendergraph/rendergraph.js +162 -35
  75. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  76. package/dist/render/rendergraph/types.js +36 -16
  77. package/dist/render/rendergraph/types.js.map +1 -1
  78. package/dist/render/rendertarget.js +5 -1
  79. package/dist/render/rendertarget.js.map +1 -1
  80. package/dist/render/screenrendertarget.js +5 -1
  81. package/dist/render/screenrendertarget.js.map +1 -1
  82. package/dist/render/sky.js +4 -4
  83. package/dist/render/sky.js.map +1 -1
  84. package/dist/scene/basesprite.js +2 -2
  85. package/dist/scene/basesprite.js.map +1 -1
  86. package/dist/scene/graph_node.js +1 -1
  87. package/dist/scene/graph_node.js.map +1 -1
  88. package/dist/scene/mesh.js +4 -20
  89. package/dist/scene/mesh.js.map +1 -1
  90. package/dist/scene/particlesys.js +1 -1
  91. package/dist/scene/particlesys.js.map +1 -1
  92. package/dist/scene/scene_node.js +2 -2
  93. package/dist/scene/scene_node.js.map +1 -1
  94. package/dist/scene/script_attachment.js +15 -3
  95. package/dist/scene/script_attachment.js.map +1 -1
  96. package/dist/scene/terrain-cm/terrain-cm.js +3 -3
  97. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  98. package/dist/shadow/shadowmapper.js.map +1 -1
  99. package/dist/shapes/box.js +1 -1
  100. package/dist/shapes/box.js.map +1 -1
  101. package/dist/shapes/capsule.js +0 -3
  102. package/dist/shapes/capsule.js.map +1 -1
  103. package/dist/shapes/cylinder.js +0 -3
  104. package/dist/shapes/cylinder.js.map +1 -1
  105. package/dist/shapes/plane.js +0 -3
  106. package/dist/shapes/plane.js.map +1 -1
  107. package/dist/shapes/tetrahedron.js +3 -9
  108. package/dist/shapes/tetrahedron.js.map +1 -1
  109. package/dist/shapes/torus.js +4 -7
  110. package/dist/shapes/torus.js.map +1 -1
  111. package/dist/utility/blueprint/material/inputs.js +3 -3
  112. package/dist/utility/blueprint/material/inputs.js.map +1 -1
  113. package/dist/utility/blueprint/material/ir.js +493 -493
  114. package/dist/utility/blueprint/material/ir.js.map +1 -1
  115. package/dist/utility/serialization/manager.js +34 -3
  116. package/dist/utility/serialization/manager.js.map +1 -1
  117. package/dist/utility/serialization/scene/animation.js +45 -0
  118. package/dist/utility/serialization/scene/animation.js.map +1 -1
  119. package/dist/utility/serialization/scene/camera.js +53 -0
  120. package/dist/utility/serialization/scene/camera.js.map +1 -1
  121. package/dist/utility/serialization/scene/common.js +10 -0
  122. package/dist/utility/serialization/scene/common.js.map +1 -1
  123. package/dist/utility/serialization/scene/light.js +30 -0
  124. package/dist/utility/serialization/scene/light.js.map +1 -1
  125. package/dist/utility/serialization/scene/material.js +63 -0
  126. package/dist/utility/serialization/scene/material.js.map +1 -1
  127. package/dist/utility/serialization/scene/mesh.js +11 -0
  128. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  129. package/dist/utility/serialization/scene/misc.js +2 -0
  130. package/dist/utility/serialization/scene/misc.js.map +1 -1
  131. package/dist/utility/serialization/scene/node.js +19 -0
  132. package/dist/utility/serialization/scene/node.js.map +1 -1
  133. package/dist/utility/serialization/scene/particle.js +22 -0
  134. package/dist/utility/serialization/scene/particle.js.map +1 -1
  135. package/dist/utility/serialization/scene/primitive.js +33 -0
  136. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  137. package/dist/utility/serialization/scene/scene.js +39 -0
  138. package/dist/utility/serialization/scene/scene.js.map +1 -1
  139. package/dist/utility/serialization/scene/script.js +2 -0
  140. package/dist/utility/serialization/scene/script.js.map +1 -1
  141. package/dist/utility/serialization/scene/sprite.js +6 -0
  142. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  143. package/dist/utility/serialization/scene/terrain.js +9 -0
  144. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  145. package/dist/utility/serialization/scene/water.js +21 -0
  146. package/dist/utility/serialization/scene/water.js.map +1 -1
  147. package/dist/utility/serialization/types.js +5 -1
  148. package/dist/utility/serialization/types.js.map +1 -1
  149. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"screen.js","sources":["../../src/app/screen.ts"],"sourcesContent":["import type { Immutable, Nullable, Rect } from '@zephyr3d/base';\r\nimport { Vector2 } from '@zephyr3d/base';\r\nimport { getDevice } from './api';\r\n\r\n/**\r\n * Scaling mode used to adapt the design resolution to the viewport.\r\n *\r\n * - 'fit' – Preserve aspect ratio, show whole design area, may add letterboxing (black bars).\r\n * - 'fit-width' – Match viewport width exactly; height follows aspect ratio (may crop or letterbox vertically).\r\n * - 'fit-height' – Match viewport height exactly; width follows aspect ratio (may crop or letterbox horizontall\r\n * - 'cover' – Preserve aspect ratio, fill the entire viewport, design area may be cropped.\r\n * - 'stretch' – Do not preserve aspect ratio, stretch to fill the viewport.\r\n *\r\n * @public\r\n */\r\nexport type ScreenScaleMode = 'fit' | 'fit-width' | 'fit-height' | 'cover' | 'stretch';\r\n\r\n/**\r\n * Screen adapter configuration\r\n *\r\n * @public\r\n */\r\nexport type ScreenConfig = {\r\n /** Logical width in the design resolution coordinate system. */\r\n designWidth: number;\r\n /** Logical height in the design resolution coordinate system. */\r\n designHeight: number;\r\n /** Scaling mode used to adapt the design resolution to the viewport. */\r\n scaleMode: ScreenScaleMode;\r\n};\r\n\r\n/**\r\n * Parameters used to describe a 2D affine transform in the form:\r\n *\r\n * outX = inX * scaleX + offsetX\r\n * outY = inY * scaleY + offsetY\r\n */\r\nexport type PointTransform = {\r\n scaleX: number;\r\n scaleY: number;\r\n offsetX: number;\r\n offsetY: number;\r\n};\r\n\r\n/**\r\n * Resolution transform information derived from a {@link ScreenConfig}\r\n * and a concrete viewport rectangle.\r\n */\r\nexport type ResolutionTransform = {\r\n /**\r\n * X position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportX: number;\r\n /**\r\n * Y position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportY: number;\r\n /**\r\n * Width of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportWidth: number;\r\n /**\r\n * Height of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportHeight: number;\r\n /**\r\n * Visible part of the adjusted viewport, i.e. intersection with original viewport.\r\n **/\r\n croppedViewport: Rect;\r\n /**\r\n * Transform from canvas coordinates to the adjusted viewport's local coordinates.\r\n *\r\n * Typically used to convert mouse / pointer positions into the active rendering region.\r\n */\r\n canvasToViewport: PointTransform;\r\n /**\r\n * Transform from canvas coordinates to logical coordinates in the\r\n * design resolution space.\r\n *\r\n * Typically used for UI editing and interaction, so that logic consistently\r\n * works in designWidth × designHeight space.\r\n */\r\n canvasToLogic: PointTransform;\r\n};\r\n\r\n/**\r\n * Adapts a given physical viewport to a logical design resolution,\r\n * and provides coordinate transforms between canvas and logical spaces.\r\n *\r\n * @public\r\n */\r\nexport class ScreenAdapter {\r\n private _config!: ScreenConfig;\r\n private _transform: Nullable<ResolutionTransform>;\r\n private _viewport: Nullable<Immutable<number[]>>;\r\n private _resolvedViewport: Nullable<Immutable<number[]>>;\r\n private _version: number;\r\n /**\r\n * Creates a new {@link ScreenAdapter}.\r\n *\r\n * @param config - Optional initial screen configuration. If omitted,\r\n * a default of 1280×720 with 'cover' mode is used.\r\n */\r\n constructor(config?: Immutable<ScreenConfig>) {\r\n this._viewport = null;\r\n this._transform = null;\r\n this._resolvedViewport = null;\r\n this._version = 1;\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n }\r\n /**\r\n * Returns the current design resolution configuration.\r\n */\r\n get config(): Immutable<ScreenConfig> {\r\n return this._config;\r\n }\r\n set config(config: Immutable<ScreenConfig>) {\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n this._transform = null;\r\n this._version++;\r\n }\r\n /**\r\n * Returns the viewport of the screen\r\n */\r\n get viewport(): Nullable<Immutable<number[]>> {\r\n return this._viewport;\r\n }\r\n set viewport(vp: Nullable<Immutable<number[]>>) {\r\n if (this._viewport !== vp) {\r\n this._viewport = vp?.slice() ?? null;\r\n this.resolveViewport();\r\n }\r\n }\r\n /**\r\n * Returns the version of the screen adapter\r\n */\r\n get version() {\r\n this.resolveViewport();\r\n return this._version;\r\n }\r\n /**\r\n * Returns the calculated resolution transform\r\n */\r\n get transform(): Immutable<ResolutionTransform> {\r\n this.resolveViewport();\r\n if (!this._transform) {\r\n this._transform = this.calculateResolutionTransform(\r\n this._resolvedViewport![0],\r\n this._resolvedViewport![1],\r\n this._resolvedViewport![2],\r\n this._resolvedViewport![3]\r\n );\r\n }\r\n return this._transform;\r\n }\r\n /**\r\n * Computes the resolution transform for a given viewport in canvas coordinates.\r\n *\r\n * @param viewportX - X position of the provided viewport (CSS pixels).\r\n * @param viewportY - Y position of the provided viewport (CSS pixels).\r\n * @param viewportWidth - Width of the provided viewport (CSS pixels).\r\n * @param viewportHeight - Height of the provided viewport (CSS pixels).\r\n * @returns A {@link ResolutionTransform} describing the adjusted viewport\r\n * and coordinate transforms. If any dimension is non-positive, a\r\n * transform with zero-sized viewport and identity-like transforms is returned.\r\n */\r\n calculateResolutionTransform(\r\n viewportX: number,\r\n viewportY: number,\r\n viewportWidth: number,\r\n viewportHeight: number\r\n ) {\r\n const { designWidth, designHeight, scaleMode } = this._config;\r\n\r\n // Guard against invalid dimensions.\r\n if (viewportWidth <= 0 || viewportHeight <= 0 || designWidth <= 0 || designHeight <= 0) {\r\n return {\r\n viewportX,\r\n viewportY,\r\n viewportWidth: 0,\r\n viewportHeight: 0,\r\n croppedViewport: { x: viewportX, y: viewportY, width: 0, height: 0 },\r\n canvasToViewport: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 },\r\n canvasToLogic: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 }\r\n };\r\n }\r\n\r\n const sx = viewportWidth / designWidth;\r\n const sy = viewportHeight / designHeight;\r\n\r\n let scaleX = 1;\r\n let scaleY = 1;\r\n let finalViewportWidth = viewportWidth;\r\n let finalViewportHeight = viewportHeight;\r\n let finalViewportX = viewportX;\r\n let finalViewportY = viewportY;\r\n\r\n switch (scaleMode) {\r\n case 'fit': {\r\n // Uniform scale, entire design area visible, may add letterboxing.\r\n const s = Math.min(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'cover': {\r\n // Uniform scale, viewport fully covered, design area may be cropped.\r\n const s = Math.max(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'stretch': {\r\n // Non-uniform scale, stretch to fill the viewport.\r\n scaleX = sx;\r\n scaleY = sy;\r\n finalViewportWidth = viewportWidth;\r\n finalViewportHeight = viewportHeight;\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY;\r\n break;\r\n }\r\n case 'fit-width': {\r\n // Match width exactly; height follows aspect ratio.\r\n const s = sx; // width-driven\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s; // == viewportWidth\r\n finalViewportHeight = designHeight * s; // may be > or < viewportHeight\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'fit-height': {\r\n // Match height exactly; width follows aspect ratio.\r\n const s = sy; // height-driven\r\n scaleX = scaleY = s;\r\n finalViewportHeight = designHeight * s; // == viewportHeight\r\n finalViewportWidth = designWidth * s; // may be > or < viewportWidth\r\n finalViewportY = viewportY;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n break;\r\n }\r\n }\r\n\r\n // calculate cropped viewport\r\n const adjLeft = finalViewportX;\r\n const adjTop = finalViewportY;\r\n const adjRight = finalViewportX + finalViewportWidth;\r\n const adjBottom = finalViewportY + finalViewportHeight;\r\n\r\n const rawLeft = viewportX;\r\n const rawTop = viewportY;\r\n const rawRight = viewportX + viewportWidth;\r\n const rawBottom = viewportY + viewportHeight;\r\n\r\n const cropLeft = Math.max(adjLeft, rawLeft);\r\n const cropTop = Math.max(adjTop, rawTop);\r\n const cropRight = Math.min(adjRight, rawRight);\r\n const cropBottom = Math.min(adjBottom, rawBottom);\r\n\r\n let croppedViewport: Rect;\r\n if (cropRight <= cropLeft || cropBottom <= cropTop) {\r\n // No intersection\r\n croppedViewport = {\r\n x: viewportX,\r\n y: viewportY,\r\n width: 0,\r\n height: 0\r\n };\r\n } else {\r\n croppedViewport = {\r\n x: cropLeft,\r\n y: cropTop,\r\n width: cropRight - cropLeft,\r\n height: cropBottom - cropTop\r\n };\r\n }\r\n\r\n // Transform: canvas -> viewport-local\r\n // viewportLocalX = canvasX - finalViewportX\r\n // viewportLocalY = canvasY - finalViewportY\r\n const canvasToViewport: PointTransform = {\r\n scaleX: 1,\r\n scaleY: 1,\r\n offsetX: -finalViewportX,\r\n offsetY: -finalViewportY\r\n };\r\n\r\n // Transform: canvas -> logic (design space)\r\n //\r\n // canvas -> viewport-local:\r\n // vx = canvasX - finalViewportX\r\n // vy = canvasY - finalViewportY\r\n //\r\n // viewport-local -> logic:\r\n // logicX = vx / scaleX\r\n // logicY = vy / scaleY\r\n //\r\n // Combined:\r\n // logicX = (canvasX - finalViewportX) / scaleX\r\n // = (1 / scaleX) * canvasX + (-finalViewportX / scaleX)\r\n // logicY = (canvasY - finalViewportY) / scaleY\r\n // = (1 / scaleY) * canvasY + (-finalViewportY / scaleY)\r\n const canvasToLogic: PointTransform = {\r\n scaleX: 1 / scaleX,\r\n scaleY: 1 / scaleY,\r\n offsetX: -finalViewportX / scaleX,\r\n offsetY: -finalViewportY / scaleY\r\n };\r\n\r\n return {\r\n viewportX: finalViewportX,\r\n viewportY: finalViewportY,\r\n viewportWidth: finalViewportWidth,\r\n viewportHeight: finalViewportHeight,\r\n croppedViewport,\r\n canvasToViewport,\r\n canvasToLogic\r\n };\r\n }\r\n /**\r\n * Converts canvas coordinates into adjusted viewport-local coordinates.\r\n *\r\n * @remarks\r\n * This is mainly intended for picking / hit testing within the active\r\n * rendering region, where (0, 0) corresponds to the top-left of the\r\n * adapted viewport.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param viewportPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in viewport-local coordinates.\r\n */\r\n canvasPosToViewport(canvasPos: Vector2, viewportPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToViewport, canvasPos, viewportPosOut);\r\n }\r\n /**\r\n * Converts canvas coordinates into logical coordinates in the design\r\n * resolution space.\r\n *\r\n * @remarks\r\n * This is mainly intended for UI editing and interaction, so that logic\r\n * works consistently in the designWidth × designHeight coordinate system.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param logicPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in logical (design resolution) coordinates.\r\n */\r\n canvasPosToLogic(canvasPos: Vector2, logicPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToLogic, canvasPos, logicPosOut);\r\n }\r\n /**\r\n * Applies a 2D affine transform to a point.\r\n *\r\n * The transform is applied as:\r\n *\r\n * out.x = in.x * scaleX + offsetX\r\n * out.y = in.y * scaleY + offsetY\r\n *\r\n * @param transform - Transform parameters (scale and offset).\r\n * @param pointIn - Input point.\r\n * @param pointOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The transformed point.\r\n */\r\n transformPoint(transform: PointTransform, pointIn: Vector2, pointOut?: Vector2) {\r\n const out = pointOut ?? new Vector2();\r\n out.x = pointIn.x * transform.scaleX + transform.offsetX;\r\n out.y = pointIn.y * transform.scaleY + transform.offsetY;\r\n return out;\r\n }\r\n /**\r\n * Resolves the current viewport, updating internal state as needed.\r\n */\r\n resolveViewport() {\r\n const device = getDevice();\r\n const vp = this._viewport ?? [\r\n 0,\r\n 0,\r\n device.deviceXToScreen(device.getDrawingBufferWidth()),\r\n device.deviceYToScreen(device.getDrawingBufferHeight())\r\n ];\r\n if (\r\n !this._resolvedViewport ||\r\n this._resolvedViewport[0] !== vp[0] ||\r\n this._resolvedViewport[1] !== vp[1] ||\r\n this._resolvedViewport[2] !== vp[2] ||\r\n this._resolvedViewport[3] !== vp[3]\r\n ) {\r\n this._resolvedViewport = vp.slice();\r\n this._version++;\r\n this._transform = null;\r\n }\r\n }\r\n private getDefaultConfig(): ScreenConfig {\r\n return {\r\n designWidth: 1280,\r\n designHeight: 720,\r\n scaleMode: 'cover'\r\n };\r\n }\r\n}\r\n"],"names":["ScreenAdapter","_config","_transform","_viewport","_resolvedViewport","_version","config","getDefaultConfig","viewport","vp","slice","resolveViewport","version","transform","calculateResolutionTransform","viewportX","viewportY","viewportWidth","viewportHeight","designWidth","designHeight","scaleMode","croppedViewport","x","y","width","height","canvasToViewport","scaleX","scaleY","offsetX","offsetY","canvasToLogic","sx","sy","finalViewportWidth","finalViewportHeight","finalViewportX","finalViewportY","s","Math","min","max","adjLeft","adjTop","adjRight","adjBottom","rawLeft","rawTop","rawRight","rawBottom","cropLeft","cropTop","cropRight","cropBottom","canvasPosToViewport","canvasPos","viewportPosOut","transformPoint","canvasPosToLogic","logicPosOut","pointIn","pointOut","out","Vector2","device","getDevice","deviceXToScreen","getDrawingBufferWidth","deviceYToScreen","getDrawingBufferHeight"],"mappings":";;;AAqFA;;;;;AAKC,IACM,MAAMA,aAAAA,CAAAA;IACHC,OAAuB;IACvBC,UAA0C;IAC1CC,SAAyC;IACzCC,iBAAiD;IACjDC,QAAiB;AACzB;;;;;MAMA,WAAA,CAAYC,MAAgC,CAAE;QAC5C,IAAI,CAACH,SAAS,GAAG,IAAA;QACjB,IAAI,CAACD,UAAU,GAAG,IAAA;QAClB,IAAI,CAACE,iBAAiB,GAAG,IAAA;QACzB,IAAI,CAACC,QAAQ,GAAG,CAAA;QAChB,IAAI,CAACJ,OAAO,GAAG;YAAE,GAAG,IAAI,CAACM,gBAAgB,EAAE;AAAE,YAAA,GAAGD;AAAO,SAAA;AACzD;AACA;;AAEC,MACD,IAAIA,MAAkC,GAAA;QACpC,OAAO,IAAI,CAACL,OAAO;AACrB;IACA,IAAIK,MAAAA,CAAOA,MAA+B,EAAE;QAC1C,IAAI,CAACL,OAAO,GAAG;YAAE,GAAG,IAAI,CAACM,gBAAgB,EAAE;AAAE,YAAA,GAAGD;AAAO,SAAA;QACvD,IAAI,CAACJ,UAAU,GAAG,IAAA;AAClB,QAAA,IAAI,CAACG,QAAQ,EAAA;AACf;AACA;;AAEC,MACD,IAAIG,QAA0C,GAAA;QAC5C,OAAO,IAAI,CAACL,SAAS;AACvB;IACA,IAAIK,QAAAA,CAASC,EAAiC,EAAE;AAC9C,QAAA,IAAI,IAAI,CAACN,SAAS,KAAKM,EAAI,EAAA;AACzB,YAAA,IAAI,CAACN,SAAS,GAAGM,EAAAA,EAAIC,KAAW,EAAA,IAAA,IAAA;AAChC,YAAA,IAAI,CAACC,eAAe,EAAA;AACtB;AACF;AACA;;AAEC,MACD,IAAIC,OAAU,GAAA;AACZ,QAAA,IAAI,CAACD,eAAe,EAAA;QACpB,OAAO,IAAI,CAACN,QAAQ;AACtB;AACA;;AAEC,MACD,IAAIQ,SAA4C,GAAA;AAC9C,QAAA,IAAI,CAACF,eAAe,EAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAACT,UAAU,EAAE;AACpB,YAAA,IAAI,CAACA,UAAU,GAAG,IAAI,CAACY,4BAA4B,CACjD,IAAI,CAACV,iBAAkB,CAAC,CAAA,CAAE,EAC1B,IAAI,CAACA,iBAAkB,CAAC,CAAA,CAAE,EAC1B,IAAI,CAACA,iBAAkB,CAAC,CAAA,CAAE,EAC1B,IAAI,CAACA,iBAAkB,CAAC,CAAE,CAAA,CAAA;AAE9B;QACA,OAAO,IAAI,CAACF,UAAU;AACxB;AACA;;;;;;;;;;MAWAY,4BAAAA,CACEC,SAAiB,EACjBC,SAAiB,EACjBC,aAAqB,EACrBC,cAAsB,EACtB;QACA,MAAM,EAAEC,WAAW,EAAEC,YAAY,EAAEC,SAAS,EAAE,GAAG,IAAI,CAACpB,OAAO;;AAG7D,QAAA,IAAIgB,iBAAiB,CAAKC,IAAAA,cAAAA,IAAkB,KAAKC,WAAe,IAAA,CAAA,IAAKC,gBAAgB,CAAG,EAAA;YACtF,OAAO;AACLL,gBAAAA,SAAAA;AACAC,gBAAAA,SAAAA;gBACAC,aAAe,EAAA,CAAA;gBACfC,cAAgB,EAAA,CAAA;gBAChBI,eAAiB,EAAA;oBAAEC,CAAGR,EAAAA,SAAAA;oBAAWS,CAAGR,EAAAA,SAAAA;oBAAWS,KAAO,EAAA,CAAA;oBAAGC,MAAQ,EAAA;AAAE,iBAAA;gBACnEC,gBAAkB,EAAA;oBAAEC,MAAQ,EAAA,CAAA;oBAAGC,MAAQ,EAAA,CAAA;oBAAGC,OAAS,EAAA,CAAA;oBAAGC,OAAS,EAAA;AAAE,iBAAA;gBACjEC,aAAe,EAAA;oBAAEJ,MAAQ,EAAA,CAAA;oBAAGC,MAAQ,EAAA,CAAA;oBAAGC,OAAS,EAAA,CAAA;oBAAGC,OAAS,EAAA;AAAE;AAChE,aAAA;AACF;AAEA,QAAA,MAAME,KAAKhB,aAAgBE,GAAAA,WAAAA;AAC3B,QAAA,MAAMe,KAAKhB,cAAiBE,GAAAA,YAAAA;AAE5B,QAAA,IAAIQ,MAAS,GAAA,CAAA;AACb,QAAA,IAAIC,MAAS,GAAA,CAAA;AACb,QAAA,IAAIM,kBAAqBlB,GAAAA,aAAAA;AACzB,QAAA,IAAImB,mBAAsBlB,GAAAA,cAAAA;AAC1B,QAAA,IAAImB,cAAiBtB,GAAAA,SAAAA;AACrB,QAAA,IAAIuB,cAAiBtB,GAAAA,SAAAA;QAErB,OAAQK,SAAAA;YACN,KAAK,KAAA;AAAO,gBAAA;;AAEV,oBAAA,MAAMkB,CAAIC,GAAAA,IAAAA,CAAKC,GAAG,CAACR,EAAIC,EAAAA,EAAAA,CAAAA;AACvBN,oBAAAA,MAAAA,GAASC,MAASU,GAAAA,CAAAA;AAClBJ,oBAAAA,kBAAAA,GAAqBhB,WAAcoB,GAAAA,CAAAA;AACnCH,oBAAAA,mBAAAA,GAAsBhB,YAAemB,GAAAA,CAAAA;AACrCF,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,aAAAA,GAAgBkB,kBAAiB,IAAK,GAAA;AACpEG,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,cAAAA,GAAiBkB,mBAAkB,IAAK,GAAA;AACtE,oBAAA;AACF;YACA,KAAK,OAAA;AAAS,gBAAA;;AAEZ,oBAAA,MAAMG,CAAIC,GAAAA,IAAAA,CAAKE,GAAG,CAACT,EAAIC,EAAAA,EAAAA,CAAAA;AACvBN,oBAAAA,MAAAA,GAASC,MAASU,GAAAA,CAAAA;AAClBJ,oBAAAA,kBAAAA,GAAqBhB,WAAcoB,GAAAA,CAAAA;AACnCH,oBAAAA,mBAAAA,GAAsBhB,YAAemB,GAAAA,CAAAA;AACrCF,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,aAAAA,GAAgBkB,kBAAiB,IAAK,GAAA;AACpEG,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,cAAAA,GAAiBkB,mBAAkB,IAAK,GAAA;AACtE,oBAAA;AACF;YACA,KAAK,SAAA;AAAW,gBAAA;;oBAEdR,MAASK,GAAAA,EAAAA;oBACTJ,MAASK,GAAAA,EAAAA;oBACTC,kBAAqBlB,GAAAA,aAAAA;oBACrBmB,mBAAsBlB,GAAAA,cAAAA;oBACtBmB,cAAiBtB,GAAAA,SAAAA;oBACjBuB,cAAiBtB,GAAAA,SAAAA;AACjB,oBAAA;AACF;YACA,KAAK,WAAA;AAAa,gBAAA;;oBAEhB,MAAMuB,CAAAA,GAAIN;AACVL,oBAAAA,MAAAA,GAASC,MAASU,GAAAA,CAAAA;oBAClBJ,kBAAqBhB,GAAAA,WAAAA,GAAcoB;oBACnCH,mBAAsBhB,GAAAA,YAAAA,GAAemB;oBACrCF,cAAiBtB,GAAAA,SAAAA;AACjBuB,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,cAAAA,GAAiBkB,mBAAkB,IAAK,GAAA;AACtE,oBAAA;AACF;YACA,KAAK,YAAA;AAAc,gBAAA;;oBAEjB,MAAMG,CAAAA,GAAIL;AACVN,oBAAAA,MAAAA,GAASC,MAASU,GAAAA,CAAAA;oBAClBH,mBAAsBhB,GAAAA,YAAAA,GAAemB;oBACrCJ,kBAAqBhB,GAAAA,WAAAA,GAAcoB;oBACnCD,cAAiBtB,GAAAA,SAAAA;AACjBqB,oBAAAA,cAAAA,GAAiBtB,SAAY,GAACE,CAAAA,aAAAA,GAAgBkB,kBAAiB,IAAK,GAAA;AACpE,oBAAA;AACF;AACF;;AAGA,QAAA,MAAMQ,OAAUN,GAAAA,cAAAA;AAChB,QAAA,MAAMO,MAASN,GAAAA,cAAAA;AACf,QAAA,MAAMO,WAAWR,cAAiBF,GAAAA,kBAAAA;AAClC,QAAA,MAAMW,YAAYR,cAAiBF,GAAAA,mBAAAA;AAEnC,QAAA,MAAMW,OAAUhC,GAAAA,SAAAA;AAChB,QAAA,MAAMiC,MAAShC,GAAAA,SAAAA;AACf,QAAA,MAAMiC,WAAWlC,SAAYE,GAAAA,aAAAA;AAC7B,QAAA,MAAMiC,YAAYlC,SAAYE,GAAAA,cAAAA;AAE9B,QAAA,MAAMiC,QAAWX,GAAAA,IAAAA,CAAKE,GAAG,CAACC,OAASI,EAAAA,OAAAA,CAAAA;AACnC,QAAA,MAAMK,OAAUZ,GAAAA,IAAAA,CAAKE,GAAG,CAACE,MAAQI,EAAAA,MAAAA,CAAAA;AACjC,QAAA,MAAMK,SAAYb,GAAAA,IAAAA,CAAKC,GAAG,CAACI,QAAUI,EAAAA,QAAAA,CAAAA;AACrC,QAAA,MAAMK,UAAad,GAAAA,IAAAA,CAAKC,GAAG,CAACK,SAAWI,EAAAA,SAAAA,CAAAA;QAEvC,IAAI5B,eAAAA;QACJ,IAAI+B,SAAAA,IAAaF,QAAYG,IAAAA,UAAAA,IAAcF,OAAS,EAAA;;YAElD9B,eAAkB,GAAA;gBAChBC,CAAGR,EAAAA,SAAAA;gBACHS,CAAGR,EAAAA,SAAAA;gBACHS,KAAO,EAAA,CAAA;gBACPC,MAAQ,EAAA;AACV,aAAA;SACK,MAAA;YACLJ,eAAkB,GAAA;gBAChBC,CAAG4B,EAAAA,QAAAA;gBACH3B,CAAG4B,EAAAA,OAAAA;AACH3B,gBAAAA,KAAAA,EAAO4B,SAAYF,GAAAA,QAAAA;AACnBzB,gBAAAA,MAAAA,EAAQ4B,UAAaF,GAAAA;AACvB,aAAA;AACF;;;;AAKA,QAAA,MAAMzB,gBAAmC,GAAA;YACvCC,MAAQ,EAAA,CAAA;YACRC,MAAQ,EAAA,CAAA;AACRC,YAAAA,OAAAA,EAAS,CAACO,cAAAA;AACVN,YAAAA,OAAAA,EAAS,CAACO;AACZ,SAAA;;;;;;;;;;;;;;;;AAiBA,QAAA,MAAMN,aAAgC,GAAA;AACpCJ,YAAAA,MAAAA,EAAQ,CAAIA,GAAAA,MAAAA;AACZC,YAAAA,MAAAA,EAAQ,CAAIA,GAAAA,MAAAA;AACZC,YAAAA,OAAAA,EAAS,CAACO,cAAiBT,GAAAA,MAAAA;AAC3BG,YAAAA,OAAAA,EAAS,CAACO,cAAiBT,GAAAA;AAC7B,SAAA;QAEA,OAAO;YACLd,SAAWsB,EAAAA,cAAAA;YACXrB,SAAWsB,EAAAA,cAAAA;YACXrB,aAAekB,EAAAA,kBAAAA;YACfjB,cAAgBkB,EAAAA,mBAAAA;AAChBd,YAAAA,eAAAA;AACAK,YAAAA,gBAAAA;AACAK,YAAAA;AACF,SAAA;AACF;AACA;;;;;;;;;;;;AAYC,MACDuB,mBAAoBC,CAAAA,SAAkB,EAAEC,cAAwB,EAAE;QAChE,OAAO,IAAI,CAACC,cAAc,CAAC,IAAI,CAAC7C,SAAS,CAACc,gBAAgB,EAAE6B,SAAWC,EAAAA,cAAAA,CAAAA;AACzE;AACA;;;;;;;;;;;;AAYC,MACDE,gBAAiBH,CAAAA,SAAkB,EAAEI,WAAqB,EAAE;QAC1D,OAAO,IAAI,CAACF,cAAc,CAAC,IAAI,CAAC7C,SAAS,CAACmB,aAAa,EAAEwB,SAAWI,EAAAA,WAAAA,CAAAA;AACtE;AACA;;;;;;;;;;;;;AAaC,MACDF,eAAe7C,SAAyB,EAAEgD,OAAgB,EAAEC,QAAkB,EAAE;QAC9E,MAAMC,GAAAA,GAAMD,YAAY,IAAIE,OAAAA,EAAAA;QAC5BD,GAAIxC,CAAAA,CAAC,GAAGsC,OAAQtC,CAAAA,CAAC,GAAGV,SAAUe,CAAAA,MAAM,GAAGf,SAAAA,CAAUiB,OAAO;QACxDiC,GAAIvC,CAAAA,CAAC,GAAGqC,OAAQrC,CAAAA,CAAC,GAAGX,SAAUgB,CAAAA,MAAM,GAAGhB,SAAAA,CAAUkB,OAAO;QACxD,OAAOgC,GAAAA;AACT;AACA;;AAEC,MACDpD,eAAkB,GAAA;AAChB,QAAA,MAAMsD,MAASC,GAAAA,SAAAA,EAAAA;AACf,QAAA,MAAMzD,EAAK,GAAA,IAAI,CAACN,SAAS,IAAI;AAC3B,YAAA,CAAA;AACA,YAAA,CAAA;YACA8D,MAAOE,CAAAA,eAAe,CAACF,MAAAA,CAAOG,qBAAqB,EAAA,CAAA;YACnDH,MAAOI,CAAAA,eAAe,CAACJ,MAAAA,CAAOK,sBAAsB,EAAA;AACrD,SAAA;QACD,IACE,CAAC,IAAI,CAAClE,iBAAiB,IACvB,IAAI,CAACA,iBAAiB,CAAC,CAAA,CAAE,KAAKK,EAAE,CAAC,EAAE,IACnC,IAAI,CAACL,iBAAiB,CAAC,EAAE,KAAKK,EAAE,CAAC,CAAE,CAAA,IACnC,IAAI,CAACL,iBAAiB,CAAC,CAAE,CAAA,KAAKK,EAAE,CAAC,CAAA,CAAE,IACnC,IAAI,CAACL,iBAAiB,CAAC,CAAA,CAAE,KAAKK,EAAE,CAAC,EAAE,EACnC;AACA,YAAA,IAAI,CAACL,iBAAiB,GAAGK,EAAAA,CAAGC,KAAK,EAAA;AACjC,YAAA,IAAI,CAACL,QAAQ,EAAA;YACb,IAAI,CAACH,UAAU,GAAG,IAAA;AACpB;AACF;IACQK,gBAAiC,GAAA;QACvC,OAAO;YACLY,WAAa,EAAA,IAAA;YACbC,YAAc,EAAA,GAAA;YACdC,SAAW,EAAA;AACb,SAAA;AACF;AACF;;;;"}
1
+ {"version":3,"file":"screen.js","sources":["../../src/app/screen.ts"],"sourcesContent":["import type { Immutable, Nullable, Rect } from '@zephyr3d/base';\r\nimport { Vector2 } from '@zephyr3d/base';\r\nimport { getDevice } from './api';\r\n\r\n/**\r\n * Scaling mode used to adapt the design resolution to the viewport.\r\n *\r\n * - 'fit' – Preserve aspect ratio, show whole design area, may add letterboxing (black bars).\r\n * - 'fit-width' – Match viewport width exactly; height follows aspect ratio (may crop or letterbox vertically).\r\n * - 'fit-height' – Match viewport height exactly; width follows aspect ratio (may crop or letterbox horizontall\r\n * - 'cover' – Preserve aspect ratio, fill the entire viewport, design area may be cropped.\r\n * - 'stretch' – Do not preserve aspect ratio, stretch to fill the viewport.\r\n *\r\n * @public\r\n */\r\nexport type ScreenScaleMode = 'fit' | 'fit-width' | 'fit-height' | 'cover' | 'stretch';\r\n\r\n/**\r\n * Screen adapter configuration\r\n *\r\n * @public\r\n */\r\nexport type ScreenConfig = {\r\n /** Logical width in the design resolution coordinate system. */\r\n designWidth: number;\r\n /** Logical height in the design resolution coordinate system. */\r\n designHeight: number;\r\n /** Scaling mode used to adapt the design resolution to the viewport. */\r\n scaleMode: ScreenScaleMode;\r\n};\r\n\r\n/**\r\n * Parameters used to describe a 2D affine transform in the form:\r\n *\r\n * outX = inX * scaleX + offsetX\r\n * outY = inY * scaleY + offsetY\r\n *\r\n * @public\r\n */\r\nexport type PointTransform = {\r\n scaleX: number;\r\n scaleY: number;\r\n offsetX: number;\r\n offsetY: number;\r\n};\r\n\r\n/**\r\n * Resolution transform information derived from a {@link ScreenConfig}\r\n * and a concrete viewport rectangle.\r\n *\r\n * @public\r\n */\r\nexport type ResolutionTransform = {\r\n /**\r\n * X position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportX: number;\r\n /**\r\n * Y position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportY: number;\r\n /**\r\n * Width of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportWidth: number;\r\n /**\r\n * Height of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportHeight: number;\r\n /**\r\n * Visible part of the adjusted viewport, i.e. intersection with original viewport.\r\n **/\r\n croppedViewport: Rect;\r\n /**\r\n * Transform from canvas coordinates to the adjusted viewport's local coordinates.\r\n *\r\n * Typically used to convert mouse / pointer positions into the active rendering region.\r\n */\r\n canvasToViewport: PointTransform;\r\n /**\r\n * Transform from canvas coordinates to logical coordinates in the\r\n * design resolution space.\r\n *\r\n * Typically used for UI editing and interaction, so that logic consistently\r\n * works in designWidth × designHeight space.\r\n */\r\n canvasToLogic: PointTransform;\r\n};\r\n\r\n/**\r\n * Adapts a given physical viewport to a logical design resolution,\r\n * and provides coordinate transforms between canvas and logical spaces.\r\n *\r\n * @public\r\n */\r\nexport class ScreenAdapter {\r\n private _config!: ScreenConfig;\r\n private _transform: Nullable<ResolutionTransform>;\r\n private _viewport: Nullable<Immutable<number[]>>;\r\n private _resolvedViewport: Nullable<Immutable<number[]>>;\r\n private _version: number;\r\n /**\r\n * Creates a new {@link ScreenAdapter}.\r\n *\r\n * @param config - Optional initial screen configuration. If omitted,\r\n * a default of `1280 x 720` with `cover` mode is used.\r\n */\r\n constructor(config?: Immutable<ScreenConfig>) {\r\n this._viewport = null;\r\n this._transform = null;\r\n this._resolvedViewport = null;\r\n this._version = 1;\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n }\r\n /**\r\n * Returns the current design resolution configuration.\r\n */\r\n get config(): Immutable<ScreenConfig> {\r\n return this._config;\r\n }\r\n set config(config: Immutable<ScreenConfig>) {\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n this._transform = null;\r\n this._version++;\r\n }\r\n /**\r\n * Returns the viewport of the screen\r\n */\r\n get viewport(): Nullable<Immutable<number[]>> {\r\n return this._viewport;\r\n }\r\n set viewport(vp: Nullable<Immutable<number[]>>) {\r\n if (this._viewport !== vp) {\r\n this._viewport = vp?.slice() ?? null;\r\n this.resolveViewport();\r\n }\r\n }\r\n /**\r\n * Returns the version of the screen adapter\r\n */\r\n get version() {\r\n this.resolveViewport();\r\n return this._version;\r\n }\r\n /**\r\n * Returns the calculated resolution transform\r\n */\r\n get transform(): Immutable<ResolutionTransform> {\r\n this.resolveViewport();\r\n if (!this._transform) {\r\n this._transform = this.calculateResolutionTransform(\r\n this._resolvedViewport![0],\r\n this._resolvedViewport![1],\r\n this._resolvedViewport![2],\r\n this._resolvedViewport![3]\r\n );\r\n }\r\n return this._transform;\r\n }\r\n /**\r\n * Computes the resolution transform for a given viewport in canvas coordinates.\r\n *\r\n * @param viewportX - X position of the provided viewport (CSS pixels).\r\n * @param viewportY - Y position of the provided viewport (CSS pixels).\r\n * @param viewportWidth - Width of the provided viewport (CSS pixels).\r\n * @param viewportHeight - Height of the provided viewport (CSS pixels).\r\n * @returns A {@link ResolutionTransform} describing the adjusted viewport\r\n * and coordinate transforms. If any dimension is non-positive, a\r\n * transform with zero-sized viewport and identity-like transforms is returned.\r\n */\r\n calculateResolutionTransform(\r\n viewportX: number,\r\n viewportY: number,\r\n viewportWidth: number,\r\n viewportHeight: number\r\n ) {\r\n const { designWidth, designHeight, scaleMode } = this._config;\r\n\r\n // Guard against invalid dimensions.\r\n if (viewportWidth <= 0 || viewportHeight <= 0 || designWidth <= 0 || designHeight <= 0) {\r\n return {\r\n viewportX,\r\n viewportY,\r\n viewportWidth: 0,\r\n viewportHeight: 0,\r\n croppedViewport: { x: viewportX, y: viewportY, width: 0, height: 0 },\r\n canvasToViewport: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 },\r\n canvasToLogic: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 }\r\n };\r\n }\r\n\r\n const sx = viewportWidth / designWidth;\r\n const sy = viewportHeight / designHeight;\r\n\r\n let scaleX = 1;\r\n let scaleY = 1;\r\n let finalViewportWidth = viewportWidth;\r\n let finalViewportHeight = viewportHeight;\r\n let finalViewportX = viewportX;\r\n let finalViewportY = viewportY;\r\n\r\n switch (scaleMode) {\r\n case 'fit': {\r\n // Uniform scale, entire design area visible, may add letterboxing.\r\n const s = Math.min(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'cover': {\r\n // Uniform scale, viewport fully covered, design area may be cropped.\r\n const s = Math.max(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'stretch': {\r\n // Non-uniform scale, stretch to fill the viewport.\r\n scaleX = sx;\r\n scaleY = sy;\r\n finalViewportWidth = viewportWidth;\r\n finalViewportHeight = viewportHeight;\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY;\r\n break;\r\n }\r\n case 'fit-width': {\r\n // Match width exactly; height follows aspect ratio.\r\n const s = sx; // width-driven\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s; // == viewportWidth\r\n finalViewportHeight = designHeight * s; // may be > or < viewportHeight\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'fit-height': {\r\n // Match height exactly; width follows aspect ratio.\r\n const s = sy; // height-driven\r\n scaleX = scaleY = s;\r\n finalViewportHeight = designHeight * s; // == viewportHeight\r\n finalViewportWidth = designWidth * s; // may be > or < viewportWidth\r\n finalViewportY = viewportY;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n break;\r\n }\r\n }\r\n\r\n // calculate cropped viewport\r\n const adjLeft = finalViewportX;\r\n const adjTop = finalViewportY;\r\n const adjRight = finalViewportX + finalViewportWidth;\r\n const adjBottom = finalViewportY + finalViewportHeight;\r\n\r\n const rawLeft = viewportX;\r\n const rawTop = viewportY;\r\n const rawRight = viewportX + viewportWidth;\r\n const rawBottom = viewportY + viewportHeight;\r\n\r\n const cropLeft = Math.max(adjLeft, rawLeft);\r\n const cropTop = Math.max(adjTop, rawTop);\r\n const cropRight = Math.min(adjRight, rawRight);\r\n const cropBottom = Math.min(adjBottom, rawBottom);\r\n\r\n let croppedViewport: Rect;\r\n if (cropRight <= cropLeft || cropBottom <= cropTop) {\r\n // No intersection\r\n croppedViewport = {\r\n x: viewportX,\r\n y: viewportY,\r\n width: 0,\r\n height: 0\r\n };\r\n } else {\r\n croppedViewport = {\r\n x: cropLeft,\r\n y: cropTop,\r\n width: cropRight - cropLeft,\r\n height: cropBottom - cropTop\r\n };\r\n }\r\n\r\n // Transform: canvas -> viewport-local\r\n // viewportLocalX = canvasX - finalViewportX\r\n // viewportLocalY = canvasY - finalViewportY\r\n const canvasToViewport: PointTransform = {\r\n scaleX: 1,\r\n scaleY: 1,\r\n offsetX: -finalViewportX,\r\n offsetY: -finalViewportY\r\n };\r\n\r\n // Transform: canvas -> logic (design space)\r\n //\r\n // canvas -> viewport-local:\r\n // vx = canvasX - finalViewportX\r\n // vy = canvasY - finalViewportY\r\n //\r\n // viewport-local -> logic:\r\n // logicX = vx / scaleX\r\n // logicY = vy / scaleY\r\n //\r\n // Combined:\r\n // logicX = (canvasX - finalViewportX) / scaleX\r\n // = (1 / scaleX) * canvasX + (-finalViewportX / scaleX)\r\n // logicY = (canvasY - finalViewportY) / scaleY\r\n // = (1 / scaleY) * canvasY + (-finalViewportY / scaleY)\r\n const canvasToLogic: PointTransform = {\r\n scaleX: 1 / scaleX,\r\n scaleY: 1 / scaleY,\r\n offsetX: -finalViewportX / scaleX,\r\n offsetY: -finalViewportY / scaleY\r\n };\r\n\r\n return {\r\n viewportX: finalViewportX,\r\n viewportY: finalViewportY,\r\n viewportWidth: finalViewportWidth,\r\n viewportHeight: finalViewportHeight,\r\n croppedViewport,\r\n canvasToViewport,\r\n canvasToLogic\r\n };\r\n }\r\n /**\r\n * Converts canvas coordinates into adjusted viewport-local coordinates.\r\n *\r\n * @remarks\r\n * This is mainly intended for picking / hit testing within the active\r\n * rendering region, where (0, 0) corresponds to the top-left of the\r\n * adapted viewport.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param viewportPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new `Vector2` is allocated.\r\n * @returns The point in viewport-local coordinates.\r\n */\r\n canvasPosToViewport(canvasPos: Vector2, viewportPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToViewport, canvasPos, viewportPosOut);\r\n }\r\n /**\r\n * Converts canvas coordinates into logical coordinates in the design\r\n * resolution space.\r\n *\r\n * @remarks\r\n * This is mainly intended for UI editing and interaction, so that logic\r\n * works consistently in the designWidth × designHeight coordinate system.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param logicPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new `Vector2` is allocated.\r\n * @returns The point in logical (design resolution) coordinates.\r\n */\r\n canvasPosToLogic(canvasPos: Vector2, logicPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToLogic, canvasPos, logicPosOut);\r\n }\r\n /**\r\n * Applies a 2D affine transform to a point.\r\n *\r\n * The transform is applied as:\r\n *\r\n * out.x = in.x * scaleX + offsetX\r\n * out.y = in.y * scaleY + offsetY\r\n *\r\n * @param transform - Transform parameters (scale and offset).\r\n * @param pointIn - Input point.\r\n * @param pointOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new `Vector2` is allocated.\r\n * @returns The transformed point.\r\n */\r\n transformPoint(transform: PointTransform, pointIn: Vector2, pointOut?: Vector2) {\r\n const out = pointOut ?? new Vector2();\r\n out.x = pointIn.x * transform.scaleX + transform.offsetX;\r\n out.y = pointIn.y * transform.scaleY + transform.offsetY;\r\n return out;\r\n }\r\n /**\r\n * Resolves the current viewport, updating internal state as needed.\r\n */\r\n resolveViewport() {\r\n const device = getDevice();\r\n const vp = this._viewport ?? [\r\n 0,\r\n 0,\r\n device.deviceXToScreen(device.getDrawingBufferWidth()),\r\n device.deviceYToScreen(device.getDrawingBufferHeight())\r\n ];\r\n if (\r\n !this._resolvedViewport ||\r\n this._resolvedViewport[0] !== vp[0] ||\r\n this._resolvedViewport[1] !== vp[1] ||\r\n this._resolvedViewport[2] !== vp[2] ||\r\n this._resolvedViewport[3] !== vp[3]\r\n ) {\r\n this._resolvedViewport = vp.slice();\r\n this._version++;\r\n this._transform = null;\r\n }\r\n }\r\n private getDefaultConfig(): ScreenConfig {\r\n return {\r\n designWidth: 1280,\r\n designHeight: 720,\r\n scaleMode: 'cover'\r\n };\r\n }\r\n}\r\n"],"names":["ScreenAdapter","_config","_transform","_viewport","_resolvedViewport","_version","config","getDefaultConfig","viewport","vp","slice","resolveViewport","version","transform","calculateResolutionTransform","viewportX","viewportY","viewportWidth","viewportHeight","designWidth","designHeight","scaleMode","croppedViewport","x","y","width","height","canvasToViewport","scaleX","scaleY","offsetX","offsetY","canvasToLogic","sx","sy","finalViewportWidth","finalViewportHeight","finalViewportX","finalViewportY","s","Math","min","max","adjLeft","adjTop","adjRight","adjBottom","rawLeft","rawTop","rawRight","rawBottom","cropLeft","cropTop","cropRight","cropBottom","canvasPosToViewport","canvasPos","viewportPosOut","transformPoint","canvasPosToLogic","logicPosOut","pointIn","pointOut","out","Vector2","device","getDevice","deviceXToScreen","getDrawingBufferWidth","deviceYToScreen","getDrawingBufferHeight"],"mappings":"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"}
@@ -2,6 +2,25 @@ import { HttpFS } from '@zephyr3d/base';
2
2
  import { ScriptRegistry } from './scriptregistry.js';
3
3
  import { RuntimeScript, applyRuntimeScriptConfig } from './runtimescript.js';
4
4
 
5
+ function resolveCreatedHook(instance) {
6
+ if (instance.onCreated !== RuntimeScript.prototype.onCreated) {
7
+ return {
8
+ legacy: false,
9
+ hook: ()=>instance.onCreated()
10
+ };
11
+ }
12
+ const legacyHook = instance.onCreate;
13
+ if (typeof legacyHook === 'function') {
14
+ return {
15
+ legacy: true,
16
+ hook: ()=>legacyHook.call(instance)
17
+ };
18
+ }
19
+ return {
20
+ legacy: false,
21
+ hook: ()=>instance.onCreated()
22
+ };
23
+ }
5
24
  /**
6
25
  * Script system that resolves, loads, and manages lifecycle of runtime scripts.
7
26
  *
@@ -83,7 +102,11 @@ import { RuntimeScript, applyRuntimeScriptConfig } from './runtimescript.js';
83
102
  if (instance instanceof RuntimeScript) {
84
103
  applyRuntimeScriptConfig(instance, config);
85
104
  if (!this._scriptHosts.has(instance)) {
86
- const P = instance.onCreated();
105
+ const createdHook = resolveCreatedHook(instance);
106
+ if (createdHook.legacy) {
107
+ console.warn(`Script '${id}' uses deprecated onCreate(); rename it to onCreated().`);
108
+ }
109
+ const P = createdHook.hook();
87
110
  if (P instanceof Promise) {
88
111
  await P;
89
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scriptingsystem.js","sources":["../../src/app/scriptingsystem.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, VFS } from '@zephyr3d/base';\r\nimport { HttpFS } from '@zephyr3d/base';\r\nimport { ScriptRegistry } from './scriptregistry';\r\nimport { applyRuntimeScriptConfig, RuntimeScript, type RuntimeScriptConfig } from './runtimescript';\r\n\r\n/**\r\n * A host object that supports disposal.\r\n *\r\n * Hosts are objects to which scripts can be attached. They are expected to\r\n * emit a `'dispose'` event compatible with `IDisposable` so that scripts\r\n * can be automatically detached when the host is destroyed.\r\n *\r\n * @public\r\n */\r\nexport type Host = IDisposable;\r\n\r\n/**\r\n * Options for configuring a `ScriptingSystem`.\r\n *\r\n * @public\r\n */\r\nexport type ScriptingSystemOptions = {\r\n /** Virtual file system used by the script registry. Defaults to `new HttpFS('./')`. */\r\n VFS?: VFS;\r\n /** Root path for scripts within the VFS. Defaults to `/`. */\r\n scriptsRoot?: string;\r\n /**\r\n * Optional string appended to dynamic import URLs (e.g., for cache busting).\r\n * Example: `'?v=' + Date.now()`\r\n */\r\n importComment?: string;\r\n /**\r\n * Optional callback invoked when a module fails to load.\r\n * @param e - The error that occurred.\r\n * @param id - The module ID that failed to load.\r\n */\r\n onLoadError?: (e: unknown, id: string) => void;\r\n};\r\n\r\n/**\r\n * Information about a script attached to a host.\r\n *\r\n * @public\r\n */\r\nexport interface IAttachedScript {\r\n /** The logical module identifier used to resolve the script. */\r\n id: string;\r\n /** The resolved runtime URL used for dynamic import. */\r\n url: string;\r\n /** The instantiated runtime script. */\r\n instance: RuntimeScript<any>;\r\n}\r\n\r\n/**\r\n * Script system that resolves, loads, and manages lifecycle of runtime scripts.\r\n *\r\n * Responsibilities:\r\n * - Resolves module IDs to URLs via {@link ScriptRegistry}\r\n * - Dynamically imports modules and instantiates a `RuntimeScript` (default export)\r\n * - Tracks attachments between hosts and script instances\r\n * - Bridges script lifecycle hooks: `onCreated`, `onAttached`, `onDetached`, `onDestroy`, `onUpdate`\r\n * - Auto-detaches scripts when a host is disposed\r\n *\r\n * Notes:\r\n * - Multiple hosts can reference the same `RuntimeScript` instance; destruction\r\n * occurs when the last host detaches.\r\n * - Errors during load/attach/update are caught and logged; an optional\r\n * `onLoadError` callback can be provided.\r\n *\r\n * @public\r\n */\r\nexport class ScriptingSystem {\r\n private _registry: ScriptRegistry;\r\n private _hostScripts: Map<Nullable<Host>, IAttachedScript[]>;\r\n private _scriptHosts: Map<RuntimeScript<any>, Nullable<Host>[]>;\r\n private _onLoadError?: (e: unknown, id: string) => void;\r\n private _importComment?: string;\r\n\r\n /**\r\n * Constructs a new scripting system.\r\n *\r\n * @param opts - Optional configuration.\r\n */\r\n constructor(opts: ScriptingSystemOptions = {}) {\r\n this._registry = new ScriptRegistry(opts.VFS ?? new HttpFS('./'), opts.scriptsRoot ?? '/');\r\n this._hostScripts = new Map();\r\n this._scriptHosts = new Map();\r\n this._importComment = opts.importComment;\r\n this._onLoadError = opts.onLoadError;\r\n }\r\n\r\n /**\r\n * Accessor for the underlying script registry used for module resolution.\r\n */\r\n get registry() {\r\n return this._registry;\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<\r\n Nullable<{\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n }>\r\n > {\r\n let mod: any = null;\r\n const moduleName = module ? String(module).slice(0, 64) : '';\r\n let url = '';\r\n try {\r\n url = await this._registry.resolveRuntimeUrl(module);\r\n if (!url) {\r\n return null;\r\n }\r\n mod = await import(url + (this._importComment ?? ''));\r\n } catch (e) {\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n }\r\n if (mod && typeof mod.default === 'function') {\r\n return { url, id: module, cls: mod.default as GenericConstructor<RuntimeScript<T>> };\r\n } else {\r\n console.error(`No runtime class exported from '${moduleName}'`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Creates a script from a dynamic loaded class and attachs it to a host and returns the `RuntimeScript` instance.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param classInfo - The dynamic loaded class information\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScriptIndirect<T extends Host>(\r\n host: Nullable<T>,\r\n classInfo: {\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n },\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n try {\r\n const { url, id, cls } = classInfo;\r\n let instance: Nullable<RuntimeScript<T>> = new cls();\r\n if (instance instanceof RuntimeScript) {\r\n applyRuntimeScriptConfig(instance, config);\r\n if (!this._scriptHosts.has(instance)) {\r\n const P = instance.onCreated();\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n }\r\n } else {\r\n instance = null;\r\n }\r\n if (!instance) {\r\n console.warn(`Script '${url}' does not have RuntimeScript class exported as default`);\r\n return null;\r\n }\r\n\r\n let hostList = this._scriptHosts.get(instance);\r\n if (!hostList) {\r\n hostList = [];\r\n this._scriptHosts.set(instance, hostList);\r\n }\r\n if (hostList.includes(host)) {\r\n console.warn(`Script '${url}' already attached`);\r\n return instance;\r\n }\r\n hostList.push(host);\r\n\r\n const P = instance.onAttached(host);\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n\r\n const attached: IAttachedScript = {\r\n id,\r\n url,\r\n instance\r\n };\r\n\r\n let list = this._hostScripts.get(host);\r\n if (!list) {\r\n list = [];\r\n this._hostScripts.set(host, list);\r\n if (host) {\r\n host.on('dispose', () => {\r\n this.detachScript(host);\r\n });\r\n }\r\n }\r\n list.push(attached);\r\n\r\n return attached.instance;\r\n } catch (e) {\r\n const moduleName = classInfo.id ? String(classInfo.id).slice(0, 64) : '';\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n this._onLoadError?.(e, classInfo.id);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Attaches a script to a host and returns the `RuntimeScript` instance.\r\n *\r\n * Process:\r\n * 1. Resolve module ID to a runtime URL via the registry.\r\n * 2. Dynamically import the module.\r\n * 3. Instantiate the default export if it is a constructor.\r\n * 4. If this is the first time the instance is seen, call `onCreated()`.\r\n * 5. Link the instance to the host, and call `onAttached(host)`.\r\n * 6. Subscribe to the host's `'dispose'` event to auto-detach.\r\n *\r\n * If the module cannot be resolved or does not export a default `RuntimeScript`\r\n * subclass, a warning is logged and `null` is returned.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param module - Module identifier used by the registry (logical ID or path).\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n const info = await this.loadRuntimeScriptClass(module);\r\n return info ? await this.attachScriptIndirect(host, info, config) : null;\r\n }\r\n\r\n /**\r\n * Detaches script(s) from a host.\r\n *\r\n * Behavior:\r\n * - If `idOrInstance` is omitted, detaches all scripts from the host.\r\n * - If a module ID is provided, detaches only the matching script.\r\n * - If a `RuntimeScript` instance is provided, detaches that instance.\r\n * - Invokes `onDetached(host)` on each detached instance.\r\n * - If the instance has no remaining hosts, invokes `onDestroy()` and disposes tracking.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host to detach from.\r\n * @param idOrInstance - Optional module ID or script instance to target.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance?: string | RuntimeScript<T>) {\r\n const list = this._hostScripts.get(host);\r\n if (!list || list.length === 0) {\r\n return;\r\n }\r\n for (let i = list.length - 1; i >= 0; i--) {\r\n const it = list[i];\r\n const hit =\r\n !idOrInstance || typeof idOrInstance === 'string'\r\n ? it.id === idOrInstance\r\n : it.instance === idOrInstance;\r\n if (hit) {\r\n list.splice(i, 1);\r\n try {\r\n it.instance.onDetached(host);\r\n } catch (err) {\r\n console.error(`Error occured at onDetach() of module '${it.id}': ${err}`);\r\n }\r\n\r\n const hostList = this._scriptHosts.get(it.instance);\r\n if (hostList) {\r\n const index = hostList.indexOf(host);\r\n if (index >= 0) {\r\n hostList.splice(index, 1);\r\n }\r\n }\r\n if (!hostList || hostList.length === 0) {\r\n try {\r\n it.instance.onDestroy();\r\n } catch (err) {\r\n console.error(`Error occured at onDestroy() of module '${it.id}': ${err}`);\r\n } finally {\r\n this._scriptHosts.delete(it.instance);\r\n }\r\n }\r\n }\r\n }\r\n if (list.length === 0) {\r\n this._hostScripts.delete(host);\r\n }\r\n }\r\n\r\n /**\r\n * Get all script instances attached to a host.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - The host whose scripts to retrieve.\r\n * @returns Script instances attached to the host, or an empty array if none.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown): T[] {\r\n return (this._hostScripts.get(host as Host) as unknown as T[]) || [];\r\n }\r\n\r\n /**\r\n * Ticks all attached script instances.\r\n *\r\n * Calls `onUpdate(deltaTime, elapsedTime)` on every attached script instance\r\n * across all hosts. Exceptions thrown by a script are caught and logged,\r\n * allowing other scripts to continue updating.\r\n *\r\n * @param deltaTime - Time in seconds since last update.\r\n * @param elapsedTime - Total time in seconds since start.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._hostScripts.size === 0) {\r\n return;\r\n }\r\n for (const list of this._hostScripts.values()) {\r\n for (const s of list) {\r\n try {\r\n s.instance.onUpdate(deltaTime, elapsedTime);\r\n } catch (err) {\r\n console.error(`Error occured at onUpdate() of module '${s.id}': ${err}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches all scripts from all hosts.\r\n *\r\n * Iteratively calls {@link ScriptingSystem.detachScript} on each host until no attachments remain.\r\n */\r\n detachAllScripts() {\r\n while (this._hostScripts.size > 0) {\r\n for (const entry of this._hostScripts) {\r\n if (entry[0]) {\r\n this.detachScript(entry[0]);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["ScriptingSystem","_registry","_hostScripts","_scriptHosts","_onLoadError","_importComment","opts","ScriptRegistry","VFS","HttpFS","scriptsRoot","Map","importComment","onLoadError","registry","loadRuntimeScriptClass","module","mod","moduleName","String","slice","url","resolveRuntimeUrl","e","console","error","default","id","cls","attachScriptIndirect","host","classInfo","config","instance","RuntimeScript","applyRuntimeScriptConfig","has","P","onCreated","Promise","warn","hostList","get","set","includes","push","onAttached","attached","list","on","detachScript","attachScript","info","idOrInstance","length","i","it","hit","splice","onDetached","err","index","indexOf","onDestroy","delete","getScriptObjects","update","deltaTime","elapsedTime","size","values","s","onUpdate","detachAllScripts","entry"],"mappings":"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"}
1
+ {"version":3,"file":"scriptingsystem.js","sources":["../../src/app/scriptingsystem.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, VFS } from '@zephyr3d/base';\r\nimport { HttpFS } from '@zephyr3d/base';\r\nimport { ScriptRegistry } from './scriptregistry';\r\nimport { applyRuntimeScriptConfig, RuntimeScript, type RuntimeScriptConfig } from './runtimescript';\r\n\r\nfunction resolveCreatedHook(instance: RuntimeScript<any>) {\r\n if (instance.onCreated !== RuntimeScript.prototype.onCreated) {\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n }\r\n const legacyHook = (instance as RuntimeScript<any> & { onCreate?: () => void | Promise<void> }).onCreate;\r\n if (typeof legacyHook === 'function') {\r\n return {\r\n legacy: true,\r\n hook: () => legacyHook.call(instance)\r\n };\r\n }\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n}\r\n\r\n/**\r\n * A host object that supports disposal.\r\n *\r\n * Hosts are objects to which scripts can be attached. They are expected to\r\n * emit a `'dispose'` event compatible with `IDisposable` so that scripts\r\n * can be automatically detached when the host is destroyed.\r\n *\r\n * @public\r\n */\r\nexport type Host = IDisposable;\r\n\r\n/**\r\n * Options for configuring a `ScriptingSystem`.\r\n *\r\n * @public\r\n */\r\nexport type ScriptingSystemOptions = {\r\n /** Virtual file system used by the script registry. Defaults to `new HttpFS('./')`. */\r\n VFS?: VFS;\r\n /** Root path for scripts within the VFS. Defaults to `/`. */\r\n scriptsRoot?: string;\r\n /**\r\n * Optional string appended to dynamic import URLs (e.g., for cache busting).\r\n * Example: `'?v=' + Date.now()`\r\n */\r\n importComment?: string;\r\n /**\r\n * Optional callback invoked when a module fails to load.\r\n * @param e - The error that occurred.\r\n * @param id - The module ID that failed to load.\r\n */\r\n onLoadError?: (e: unknown, id: string) => void;\r\n};\r\n\r\n/**\r\n * Information about a script attached to a host.\r\n *\r\n * @public\r\n */\r\nexport interface IAttachedScript {\r\n /** The logical module identifier used to resolve the script. */\r\n id: string;\r\n /** The resolved runtime URL used for dynamic import. */\r\n url: string;\r\n /** The instantiated runtime script. */\r\n instance: RuntimeScript<any>;\r\n}\r\n\r\n/**\r\n * Script system that resolves, loads, and manages lifecycle of runtime scripts.\r\n *\r\n * Responsibilities:\r\n * - Resolves module IDs to URLs via {@link ScriptRegistry}\r\n * - Dynamically imports modules and instantiates a `RuntimeScript` (default export)\r\n * - Tracks attachments between hosts and script instances\r\n * - Bridges script lifecycle hooks: `onCreated`, `onAttached`, `onDetached`, `onDestroy`, `onUpdate`\r\n * - Auto-detaches scripts when a host is disposed\r\n *\r\n * Notes:\r\n * - Multiple hosts can reference the same `RuntimeScript` instance; destruction\r\n * occurs when the last host detaches.\r\n * - Errors during load/attach/update are caught and logged; an optional\r\n * `onLoadError` callback can be provided.\r\n *\r\n * @public\r\n */\r\nexport class ScriptingSystem {\r\n private _registry: ScriptRegistry;\r\n private _hostScripts: Map<Nullable<Host>, IAttachedScript[]>;\r\n private _scriptHosts: Map<RuntimeScript<any>, Nullable<Host>[]>;\r\n private _onLoadError?: (e: unknown, id: string) => void;\r\n private _importComment?: string;\r\n\r\n /**\r\n * Constructs a new scripting system.\r\n *\r\n * @param opts - Optional configuration.\r\n */\r\n constructor(opts: ScriptingSystemOptions = {}) {\r\n this._registry = new ScriptRegistry(opts.VFS ?? new HttpFS('./'), opts.scriptsRoot ?? '/');\r\n this._hostScripts = new Map();\r\n this._scriptHosts = new Map();\r\n this._importComment = opts.importComment;\r\n this._onLoadError = opts.onLoadError;\r\n }\r\n\r\n /**\r\n * Accessor for the underlying script registry used for module resolution.\r\n */\r\n get registry() {\r\n return this._registry;\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<\r\n Nullable<{\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n }>\r\n > {\r\n let mod: any = null;\r\n const moduleName = module ? String(module).slice(0, 64) : '';\r\n let url = '';\r\n try {\r\n url = await this._registry.resolveRuntimeUrl(module);\r\n if (!url) {\r\n return null;\r\n }\r\n mod = await import(url + (this._importComment ?? ''));\r\n } catch (e) {\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n }\r\n if (mod && typeof mod.default === 'function') {\r\n return { url, id: module, cls: mod.default as GenericConstructor<RuntimeScript<T>> };\r\n } else {\r\n console.error(`No runtime class exported from '${moduleName}'`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Creates a script from a dynamic loaded class and attachs it to a host and returns the `RuntimeScript` instance.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param classInfo - The dynamic loaded class information\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScriptIndirect<T extends Host>(\r\n host: Nullable<T>,\r\n classInfo: {\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n },\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n try {\r\n const { url, id, cls } = classInfo;\r\n let instance: Nullable<RuntimeScript<T>> = new cls();\r\n if (instance instanceof RuntimeScript) {\r\n applyRuntimeScriptConfig(instance, config);\r\n if (!this._scriptHosts.has(instance)) {\r\n const createdHook = resolveCreatedHook(instance);\r\n if (createdHook.legacy) {\r\n console.warn(`Script '${id}' uses deprecated onCreate(); rename it to onCreated().`);\r\n }\r\n const P = createdHook.hook();\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n }\r\n } else {\r\n instance = null;\r\n }\r\n if (!instance) {\r\n console.warn(`Script '${url}' does not have RuntimeScript class exported as default`);\r\n return null;\r\n }\r\n\r\n let hostList = this._scriptHosts.get(instance);\r\n if (!hostList) {\r\n hostList = [];\r\n this._scriptHosts.set(instance, hostList);\r\n }\r\n if (hostList.includes(host)) {\r\n console.warn(`Script '${url}' already attached`);\r\n return instance;\r\n }\r\n hostList.push(host);\r\n\r\n const P = instance.onAttached(host);\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n\r\n const attached: IAttachedScript = {\r\n id,\r\n url,\r\n instance\r\n };\r\n\r\n let list = this._hostScripts.get(host);\r\n if (!list) {\r\n list = [];\r\n this._hostScripts.set(host, list);\r\n if (host) {\r\n host.on('dispose', () => {\r\n this.detachScript(host);\r\n });\r\n }\r\n }\r\n list.push(attached);\r\n\r\n return attached.instance;\r\n } catch (e) {\r\n const moduleName = classInfo.id ? String(classInfo.id).slice(0, 64) : '';\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n this._onLoadError?.(e, classInfo.id);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Attaches a script to a host and returns the `RuntimeScript` instance.\r\n *\r\n * Process:\r\n * 1. Resolve module ID to a runtime URL via the registry.\r\n * 2. Dynamically import the module.\r\n * 3. Instantiate the default export if it is a constructor.\r\n * 4. If this is the first time the instance is seen, call `onCreated()`.\r\n * 5. Link the instance to the host, and call `onAttached(host)`.\r\n * 6. Subscribe to the host's `'dispose'` event to auto-detach.\r\n *\r\n * If the module cannot be resolved or does not export a default `RuntimeScript`\r\n * subclass, a warning is logged and `null` is returned.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param module - Module identifier used by the registry (logical ID or path).\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n const info = await this.loadRuntimeScriptClass(module);\r\n return info ? await this.attachScriptIndirect(host, info, config) : null;\r\n }\r\n\r\n /**\r\n * Detaches script(s) from a host.\r\n *\r\n * Behavior:\r\n * - If `idOrInstance` is omitted, detaches all scripts from the host.\r\n * - If a module ID is provided, detaches only the matching script.\r\n * - If a `RuntimeScript` instance is provided, detaches that instance.\r\n * - Invokes `onDetached(host)` on each detached instance.\r\n * - If the instance has no remaining hosts, invokes `onDestroy()` and disposes tracking.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host to detach from.\r\n * @param idOrInstance - Optional module ID or script instance to target.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance?: string | RuntimeScript<T>) {\r\n const list = this._hostScripts.get(host);\r\n if (!list || list.length === 0) {\r\n return;\r\n }\r\n for (let i = list.length - 1; i >= 0; i--) {\r\n const it = list[i];\r\n const hit =\r\n !idOrInstance || typeof idOrInstance === 'string'\r\n ? it.id === idOrInstance\r\n : it.instance === idOrInstance;\r\n if (hit) {\r\n list.splice(i, 1);\r\n try {\r\n it.instance.onDetached(host);\r\n } catch (err) {\r\n console.error(`Error occured at onDetach() of module '${it.id}': ${err}`);\r\n }\r\n\r\n const hostList = this._scriptHosts.get(it.instance);\r\n if (hostList) {\r\n const index = hostList.indexOf(host);\r\n if (index >= 0) {\r\n hostList.splice(index, 1);\r\n }\r\n }\r\n if (!hostList || hostList.length === 0) {\r\n try {\r\n it.instance.onDestroy();\r\n } catch (err) {\r\n console.error(`Error occured at onDestroy() of module '${it.id}': ${err}`);\r\n } finally {\r\n this._scriptHosts.delete(it.instance);\r\n }\r\n }\r\n }\r\n }\r\n if (list.length === 0) {\r\n this._hostScripts.delete(host);\r\n }\r\n }\r\n\r\n /**\r\n * Get all script instances attached to a host.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - The host whose scripts to retrieve.\r\n * @returns Script instances attached to the host, or an empty array if none.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown): T[] {\r\n return (this._hostScripts.get(host as Host) as unknown as T[]) || [];\r\n }\r\n\r\n /**\r\n * Ticks all attached script instances.\r\n *\r\n * Calls `onUpdate(deltaTime, elapsedTime)` on every attached script instance\r\n * across all hosts. Exceptions thrown by a script are caught and logged,\r\n * allowing other scripts to continue updating.\r\n *\r\n * @param deltaTime - Time in seconds since last update.\r\n * @param elapsedTime - Total time in seconds since start.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._hostScripts.size === 0) {\r\n return;\r\n }\r\n for (const list of this._hostScripts.values()) {\r\n for (const s of list) {\r\n try {\r\n s.instance.onUpdate(deltaTime, elapsedTime);\r\n } catch (err) {\r\n console.error(`Error occured at onUpdate() of module '${s.id}': ${err}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches all scripts from all hosts.\r\n *\r\n * Iteratively calls {@link ScriptingSystem.detachScript} on each host until no attachments remain.\r\n */\r\n detachAllScripts() {\r\n while (this._hostScripts.size > 0) {\r\n for (const entry of this._hostScripts) {\r\n if (entry[0]) {\r\n this.detachScript(entry[0]);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["resolveCreatedHook","instance","onCreated","RuntimeScript","prototype","legacy","hook","legacyHook","onCreate","call","ScriptingSystem","_registry","_hostScripts","_scriptHosts","_onLoadError","_importComment","opts","ScriptRegistry","VFS","HttpFS","scriptsRoot","Map","importComment","onLoadError","registry","loadRuntimeScriptClass","module","mod","moduleName","String","slice","url","resolveRuntimeUrl","e","console","error","default","id","cls","attachScriptIndirect","host","classInfo","config","applyRuntimeScriptConfig","has","createdHook","warn","P","Promise","hostList","get","set","includes","push","onAttached","attached","list","on","detachScript","attachScript","info","idOrInstance","length","i","it","hit","splice","onDetached","err","index","indexOf","onDestroy","delete","getScriptObjects","update","deltaTime","elapsedTime","size","values","s","onUpdate","detachAllScripts","entry"],"mappings":"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"}