xbintsc 0.5.32 → 0.5.36

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 (173) hide show
  1. package/README.md +10 -7
  2. package/README.zh-CN.md +10 -8
  3. package/dist/scripts/check-version.d.ts +27 -0
  4. package/dist/scripts/check-version.js +71 -0
  5. package/dist/scripts/check-version.js.map +1 -0
  6. package/dist/scripts/package-platform.d.ts +58 -0
  7. package/dist/scripts/package-platform.js +142 -0
  8. package/dist/scripts/package-platform.js.map +1 -0
  9. package/dist/scripts/verify-platform-package.d.ts +34 -0
  10. package/dist/scripts/verify-platform-package.js +161 -0
  11. package/dist/scripts/verify-platform-package.js.map +1 -0
  12. package/dist/src/cli/help.d.ts +1 -1
  13. package/dist/src/cli/main.js +3 -1
  14. package/dist/src/cli/main.js.map +1 -1
  15. package/dist/src/driver/runtime-lib.d.ts +29 -4
  16. package/dist/src/driver/runtime-lib.js +68 -10
  17. package/dist/src/driver/runtime-lib.js.map +1 -1
  18. package/dist/src/driver/version.d.ts +1 -1
  19. package/dist/src/driver/version.js +1 -1
  20. package/dist/src/extensions/gui/index.js +6 -5
  21. package/dist/src/extensions/gui/index.js.map +1 -1
  22. package/dist/src/extensions/media/index.js +4 -3
  23. package/dist/src/extensions/media/index.js.map +1 -1
  24. package/dist/src/parser/context.d.ts +41 -0
  25. package/dist/src/parser/context.js +89 -4
  26. package/dist/src/parser/context.js.map +1 -1
  27. package/dist/src/parser/literals.js +6 -12
  28. package/dist/src/parser/literals.js.map +1 -1
  29. package/dist/tests/driver/platform-package.test.d.ts +1 -0
  30. package/dist/tests/driver/platform-package.test.js +49 -0
  31. package/dist/tests/driver/platform-package.test.js.map +1 -0
  32. package/dist/tests/driver/runtime-lib.test.js +51 -4
  33. package/dist/tests/driver/runtime-lib.test.js.map +1 -1
  34. package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
  35. package/dist/tests/e2e/gui-audio.test.js +287 -0
  36. package/dist/tests/e2e/gui-audio.test.js.map +1 -0
  37. package/dist/tests/e2e/gui-helpers.d.ts +7 -0
  38. package/dist/tests/e2e/gui-helpers.js +1 -0
  39. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  40. package/dist/tests/e2e/gui-media.test.js +78 -0
  41. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  42. package/dist/tests/e2e/gui-style.test.js +55 -0
  43. package/dist/tests/e2e/gui-style.test.js.map +1 -1
  44. package/dist/tests/e2e/gui-webgl.test.js +258 -0
  45. package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
  46. package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
  47. package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
  48. package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
  49. package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
  50. package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
  51. package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
  52. package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
  53. package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
  54. package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
  55. package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
  56. package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
  57. package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
  58. package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
  59. package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
  60. package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
  61. package/dist/tests/e2e/gui-webgl2.test.js +45 -1
  62. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -1
  63. package/dist/tests/extensions/gui-index.test.js +1 -0
  64. package/dist/tests/extensions/gui-index.test.js.map +1 -1
  65. package/dist/tests/extensions/media.test.js +1 -0
  66. package/dist/tests/extensions/media.test.js.map +1 -1
  67. package/dist/tests/parser/expressions.test.js +30 -0
  68. package/dist/tests/parser/expressions.test.js.map +1 -1
  69. package/dist/tests/platform-tarball.test.d.ts +1 -0
  70. package/dist/tests/platform-tarball.test.js +111 -0
  71. package/dist/tests/platform-tarball.test.js.map +1 -0
  72. package/dist/tests/version.test.js +6 -0
  73. package/dist/tests/version.test.js.map +1 -1
  74. package/doc/ai/contributing.md +11 -0
  75. package/doc/ai/extensions.md +7 -4
  76. package/doc/ai/troubleshooting.md +7 -5
  77. package/doc/ai/zh-CN/contributing.md +9 -0
  78. package/doc/ai/zh-CN/extensions.md +4 -2
  79. package/doc/ai/zh-CN/troubleshooting.md +5 -3
  80. package/doc/gui/api.md +61 -13
  81. package/doc/gui/build.md +11 -4
  82. package/doc/gui/dom.md +6 -3
  83. package/doc/gui/media.md +4 -0
  84. package/doc/gui/webgl.md +105 -46
  85. package/doc/gui.md +7 -3
  86. package/doc/npm-package.md +55 -27
  87. package/doc/requirements.md +6 -2
  88. package/doc/zh-CN/gui/api.md +51 -10
  89. package/doc/zh-CN/gui/build.md +7 -2
  90. package/doc/zh-CN/gui/dom.md +3 -1
  91. package/doc/zh-CN/gui/media.md +3 -0
  92. package/doc/zh-CN/gui/webgl.md +22 -16
  93. package/doc/zh-CN/gui.md +3 -2
  94. package/doc/zh-CN/npm-package.md +44 -23
  95. package/doc/zh-CN/requirements.md +4 -1
  96. package/package.json +17 -1
  97. package/runtime/ext_gui/audio.cpp +365 -153
  98. package/runtime/ext_gui/audio_buffer.cpp +166 -0
  99. package/runtime/ext_gui/audio_buffer.h +37 -0
  100. package/runtime/ext_gui/audio_decode.cpp +219 -0
  101. package/runtime/ext_gui/audio_decode.h +39 -0
  102. package/runtime/ext_gui/audio_device.cpp +87 -0
  103. package/runtime/ext_gui/audio_effects.cpp +163 -0
  104. package/runtime/ext_gui/audio_effects.h +25 -0
  105. package/runtime/ext_gui/audio_internal.h +30 -0
  106. package/runtime/ext_gui/audio_mixer.cpp +494 -0
  107. package/runtime/ext_gui/audio_mixer.h +238 -0
  108. package/runtime/ext_gui/audio_param.cpp +104 -0
  109. package/runtime/ext_gui/audio_param_object.cpp +155 -0
  110. package/runtime/ext_gui/browser.cpp +11 -1
  111. package/runtime/ext_gui/css_selector.cpp +21 -3
  112. package/runtime/ext_gui/dom_api_internal.h +16 -0
  113. package/runtime/ext_gui/dom_api_webgl.cpp +7 -0
  114. package/runtime/ext_gui/dom_api_webgl2.cpp +151 -36
  115. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +3 -3
  116. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +6 -2
  117. package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
  118. package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
  119. package/runtime/ext_gui/dom_api_webgl_shader.cpp +4 -4
  120. package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
  121. package/runtime/ext_gui/dom_api_webgl_state.cpp +169 -23
  122. package/runtime/ext_gui/dom_api_webgl_texture.cpp +276 -236
  123. package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
  124. package/runtime/ext_gui/gui.cpp +44 -9
  125. package/runtime/ext_gui/gui_engine.h +9 -4
  126. package/runtime/ext_gui/image_bitmap.cpp +28 -0
  127. package/runtime/ext_gui/image_bitmap.h +26 -0
  128. package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
  129. package/runtime/ext_gui/media.cpp +32 -0
  130. package/runtime/ext_gui/media.h +13 -0
  131. package/runtime/ext_gui/media_api.h +23 -0
  132. package/runtime/ext_gui/webgl.h +152 -18
  133. package/runtime/ext_gui/webgl_blit.cpp +95 -0
  134. package/runtime/ext_gui/webgl_buffer.cpp +178 -263
  135. package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
  136. package/runtime/ext_gui/webgl_clear.cpp +142 -0
  137. package/runtime/ext_gui/webgl_compressed.cpp +180 -0
  138. package/runtime/ext_gui/webgl_context.cpp +241 -156
  139. package/runtime/ext_gui/webgl_draw.cpp +68 -3
  140. package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
  141. package/runtime/ext_gui/webgl_glsl.h +40 -0
  142. package/runtime/ext_gui/webgl_glsl_compile.cpp +6 -0
  143. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +18 -0
  144. package/runtime/ext_gui/webgl_glsl_scan.cpp +20 -11
  145. package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
  146. package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
  147. package/runtime/ext_gui/webgl_pipeline.cpp +71 -19
  148. package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
  149. package/runtime/ext_gui/webgl_program_internal.h +6 -0
  150. package/runtime/ext_gui/webgl_shader.cpp +13 -1
  151. package/runtime/ext_gui/webgl_state.cpp +228 -0
  152. package/runtime/ext_gui/webgl_texture.cpp +144 -17
  153. package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
  154. package/runtime/ext_gui/webgl_uniform_block.h +31 -0
  155. package/runtime/ext_gui/webgl_webgl2.cpp +58 -5
  156. package/runtime/ext_media/decode_audio.cpp +308 -0
  157. package/runtime/ext_media/media_bridge.c +2 -0
  158. package/runtime/rt.h +17 -0
  159. package/runtime/xt_array_buffer.c +30 -0
  160. package/runtime/xt_typed_array/elements.inc +13 -0
  161. package/scripts/build-media.ts +14 -6
  162. package/scripts/build-runtime.ts +21 -16
  163. package/scripts/check-version.ts +39 -9
  164. package/scripts/package-platform.ts +183 -0
  165. package/scripts/set-platform-version.ts +62 -0
  166. package/scripts/verify-platform-package.ts +182 -0
  167. package/src/cli/main.ts +5 -1
  168. package/src/driver/runtime-lib.ts +73 -9
  169. package/src/driver/version.ts +1 -1
  170. package/src/extensions/gui/index.ts +6 -5
  171. package/src/extensions/media/index.ts +4 -3
  172. package/src/parser/context.ts +99 -4
  173. package/src/parser/literals.ts +6 -12
@@ -55,7 +55,7 @@ SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式
55
55
 
56
56
  两个阶段的非采样器 uniform 会合并成同一个块,并在每个阶段各声明一次(顶点 set 1、片元 set 3),与 SDL_GPU 的 Vulkan 描述符布局一致。在 Metal 上同一批声明会变成 `[[buffer(0)]]` 与 `[[texture(N)]]`/`[[sampler(N)]]`,正是 SDL_GPU Metal 后端绑定的槽位。`uniformMatrix4fv` 按列主序写入反射出的偏移;对采样器调用 `uniform1i` 时记录纹理单元。每次绘制都用动态 uniform 缓冲接口推送该块。
57
57
 
58
- 翻译器的限制:结构体 uniform、用户 uniform 块、预处理后仍无法确定长度的 uniform 数组、采样器数组与立方体贴图都会被拒绝(着色器/链接日志会说明)。`#ifdef` 内的代码没问题;非采样器 uniform 声明会被移到外层顶层位置,保证块是无条件的。
58
+ 翻译器的限制:结构体 uniform、用户 uniform 块、预处理后仍无法确定长度的 uniform 数组、采样器数组与采样器类型不匹配的声明会被拒绝(着色器/链接日志会说明)。`#ifdef` 内的代码没问题;非采样器 uniform 声明会被移到外层顶层位置,保证块是无条件的。
59
59
 
60
60
  ### GLSL ES 3.00(WebGL 2)
61
61
 
@@ -63,15 +63,15 @@ SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式
63
63
 
64
64
  ## 支持的 API
65
65
 
66
- - **上下文**:`getContext("webgl")`、`canvas`、`drawingBufferWidth/Height`、`getParameter`、`getError`、`getSupportedExtensions`、`getExtension`、`getContextAttributes`、`isContextLost`、`getShaderPrecisionFormat`,以及模板入口(接受状态;深度目标没有模板附件)。
66
+ - **上下文**:`getContext("webgl")`、`canvas`、`drawingBufferWidth/Height`、`getParameter`、`getError`、`getSupportedExtensions`、`getExtension`、`getContextAttributes`、`isContextLost`、`getShaderPrecisionFormat`,以及 8 位模板缓冲(`getContextAttributes().stencil` 为 `true`,`STENCIL_BITS` 为 8)。`WEBGL_lose_context` 的 `loseContext`/`restoreContext` 会真正丢弃并重建上下文(对象全部失效),并派发 `webglcontextlost` / `webglcontextrestored` 事件。
67
67
  - **着色器与程序**:`createShader`、`shaderSource`、`compileShader`、`getShaderParameter`、`getShaderInfoLog`、`getShaderSource`、`deleteShader`、`createProgram`、`attachShader`、`detachShader`、`linkProgram`、`getProgramParameter`、`getProgramInfoLog`、`getAttachedShaders`、`validateProgram`、`deleteProgram`、`useProgram`、`getActiveUniform`/`getActiveAttrib`、`getUniformLocation`、`getAttribLocation`、`bindAttribLocation`。
68
68
  - **Uniform**:`uniform1f`…`uniform4f`、`uniform1i`…`uniform4i`、`uniform1fv`…`uniform4fv`、`uniform1iv`…`uniform4iv`、`uniformMatrix2fv`/`3fv`/`4fv`、`getUniform`。
69
- - **缓冲与顶点属性**:`createBuffer`、`bindBuffer`、`bufferData`、`bufferSubData`、`deleteBuffer`、`getBufferParameter`、`enableVertexAttribArray`、`disableVertexAttribArray`、`vertexAttribPointer`、`vertexAttrib1f`…`4f` / `1fv`…`4fv`、`getVertexAttrib`。
69
+ - **缓冲与顶点属性**:`createBuffer`、`bindBuffer`、`bufferData`、`bufferSubData`、`deleteBuffer`、`getBufferParameter`、`enableVertexAttribArray`、`disableVertexAttribArray`、`vertexAttribPointer`、`vertexAttrib1f`…`4f` / `1fv`…`4fv`、`getVertexAttrib`。`bufferData` 的 `usage` 提示(`STREAM_DRAW`/`STATIC_DRAW`/`DYNAMIC_DRAW`)会被记录,`getBufferParameter(…, BUFFER_USAGE)` 可读回。
70
70
  - **绘制**:`drawArrays`、`drawElements`(UNSIGNED_BYTE、UNSIGNED_SHORT、UNSIGNED_INT;`TRIANGLE_FAN` 与 `LINE_LOOP` 会展开为列表)。`POINTS`、`LINES`、`LINE_STRIP`、`TRIANGLES`、`TRIANGLE_STRIP` 映射到对应的 SDL 图元。
71
- - **纹理**:`createTexture`、`bindTexture`、`activeTexture`、`texParameteri`/`texParameterf`、`getTexParameter`、`texImage2D`(原始像素、`<img>`、`<canvas>`、`ImageData`)、`texSubImage2D`、`generateMipmap`、`deleteTexture`。支持 `UNPACK_FLIP_Y_WEBGL` 与 `UNPACK_PREMULTIPLY_ALPHA_WEBGL`。全部转换为 RGBA8;接受 `RGBA`、`RGB`、`LUMINANCE`、`ALPHA`、`LUMINANCE_ALPHA` 配 `UNSIGNED_BYTE`。
72
- - **Framebuffer**:`createFramebuffer`、`bindFramebuffer`、`framebufferTexture2D`(颜色附件)、`checkFramebufferStatus`、`createRenderbuffer`、`bindRenderbuffer`、`renderbufferStorage`(深度)、`framebufferRenderbuffer`、`delete*`。足以实现渲染到纹理、阴影贴图与后处理。
73
- - **状态**:`enable`/`disable`/`isEnabled`(`BLEND`、`DEPTH_TEST`、`CULL_FACE`、`SCISSOR_TEST`;模板状态接受但不生效)、`clearColor`/`clearDepth`/`clearStencil`、`clear`、`blendFunc`/`blendFuncSeparate`、`blendEquation`/`blendEquationSeparate`、`depthFunc`、`depthMask`、`colorMask`、`cullFace`、`frontFace`、`viewport`、`scissor`、`pixelStorei`、`finish`。
74
- - **读回**:`readPixels`(RGBA/UNSIGNED_BYTE),可从默认帧缓冲或绑定的 framebuffer 读取。它会阻塞到 GPU 完成;用于测试和截图,不要每帧调用。
71
+ - **纹理**:`createTexture`、`bindTexture`、`activeTexture`、`texParameteri`/`texParameterf`、`getTexParameter`、`texImage2D`(原始像素、`<img>`、`<canvas>`、`ImageData`)、`texSubImage2D`、`generateMipmap`、`deleteTexture`。支持 `UNPACK_FLIP_Y_WEBGL` 与 `UNPACK_PREMULTIPLY_ALPHA_WEBGL`。默认转换为 RGBA8;`RGBA`/`RGB`/`LUMINANCE`/`ALPHA`/`LUMINANCE_ALPHA` 配 `UNSIGNED_BYTE` 可用。浮点纹理(`RGBA32F`、`RGBA16F`、`RGB32F`、`RGB16F`、`RG32F`/`RG16F`、`R32F`/`R16F`,`FLOAT` 或 `HALF_FLOAT` 数据,以及 WebGL 1 的 `OES_texture_float`/`OES_texture_half_float`)映射到 SDL 的 RGBA32F/RGBA16F;深度纹理(`DEPTH_COMPONENT16/24/32F`、`DEPTH_STENCIL`、`DEPTH24_STENCIL8`)映射到 `D32_FLOAT`/`D32_FLOAT_S8_UINT`,可作为采样源或深度附件。压缩纹理通过 `compressedTexImage2D`/`compressedTexSubImage2D` 上传,支持 `WEBGL_compressed_texture_s3tc`(BC1/BC2/BC3)、`WEBGL_compressed_texture_s3tc_srgb` 与 `WEBGL_compressed_texture_astc`;扩展只在设备确实支持对应格式时公布。`texImage2D` 还接受 `<video>` 的最新解码帧与 `createImageBitmap` 产生的 `ImageBitmap`。立方体贴图(`bindTexture(TEXTURE_CUBE_MAP)` + 六个 `texImage2D` 面)与 3D/数组纹理(`texImage3D`/`texStorage3D`)可用对应采样器(`samplerCube`、`sampler3D`、`sampler2DArray`)采样;`texSubImage3D` 可更新 3D/数组纹理的子区域,`framebufferTextureLayer` 可把数组/立方体贴图的指定层作为颜色附件渲染。
72
+ - **Framebuffer**:`createFramebuffer`、`bindFramebuffer`(`FRAMEBUFFER`/`READ_FRAMEBUFFER`/`DRAW_FRAMEBUFFER`)、`framebufferTexture2D`(`COLOR_ATTACHMENT0`、`DEPTH_ATTACHMENT`、`DEPTH_STENCIL_ATTACHMENT`)、`checkFramebufferStatus`、`createRenderbuffer`、`bindRenderbuffer`、`renderbufferStorage`(深度/深度模板)、`framebufferRenderbuffer`、`delete*`,以及 `blitFramebuffer`(颜色附件;深度/模板位被接受但不复制)。足以实现渲染到纹理、阴影贴图与后处理。
73
+ - **状态**:`enable`/`disable`/`isEnabled`(`BLEND`、`DEPTH_TEST`、`CULL_FACE`、`SCISSOR_TEST`、`STENCIL_TEST`)、`clearColor`/`clearDepth`/`clearStencil`、`clear`(开启 `SCISSOR_TEST` 时颜色、深度与模板都只清除 scissor 矩形)、`blendColor`、`blendFunc`/`blendFuncSeparate`、`blendEquation`/`blendEquationSeparate`、`depthFunc`、`depthMask`、`colorMask`、`stencilFunc`/`stencilFuncSeparate`、`stencilOp`/`stencilOpSeparate`、`stencilMask`/`stencilMaskSeparate`、`cullFace`、`frontFace`、`viewport`、`scissor`、`pixelStorei`、`finish`。模板测试真正参与光栅化,`clear(STENCIL_BUFFER_BIT)` 会清空模板附件;SDL_GPU 只有一份前后脸共用的 reference 与 compare/write mask,若前后脸设置不同,使用前脸值。
74
+ - **读回**:`readPixels`(RGBA/UNSIGNED_BYTE),可从默认帧缓冲或绑定的 RGBA8 framebuffer 读取;浮点/深度附件先采样到 RGBA8 目标再读回。它会阻塞到 GPU 完成;用于测试和截图,不要每帧调用。
75
75
 
76
76
  WebGL 2 额外提供:
77
77
 
@@ -80,18 +80,18 @@ WebGL 2 额外提供:
80
80
  - **整数属性与 uniform**:`vertexAttribIPointer`、`vertexAttribI4*` 系列、`uniform1ui`…`uniform4ui`。
81
81
  - **采样器对象**:`createSampler`、`bindSampler`、`deleteSampler`、`samplerParameteri/f`、`getSamplerParameter`;绑定的采样器会覆盖该单元上纹理自身的过滤/环绕状态。
82
82
  - **不可变纹理与缓冲拷贝**:`texStorage2D`(后端始终分配完整 mip 链)、`copyBufferSubData`、`getBufferSubData`。
83
+ - **绘图缓冲**:`drawingBufferStorage(width, height)` 固定绘图缓冲尺寸;此后 `canvas.width` / `canvas.height` 不再重建它。
83
84
  - **清除**:`clearBufferfv`、`clearBufferiv`、`clearBufferuiv`、`clearBufferfi`。
85
+ - **多渲染目标**:`drawBuffers` 最多 4 个颜色附件,`readBuffer` 选择 `readPixels` 的附件;`framebufferTexture2D` 可挂 `COLOR_ATTACHMENT0`…`3`,片元着色器的多个 `out` 按顺序写入。
84
86
  - **查询与栅栏**:对象与入口都存在(`createQuery`/`beginQuery`/`endQuery`/`getQueryParameter`、`fenceSync`/`clientWaitSync`/`waitSync`/`getSyncParameter`),行为是优雅降级:栅栏报告 `ALREADY_SIGNALED`,查询结果为 0。
85
- - **Uniform 块**:`getUniformBlockIndex` 返回 `INVALID_INDEX`,让库回退到独立 uniform;块相关入口为空操作。
86
- - **Transform feedback、3D 纹理与压缩格式**:入口存在但为空操作,避免特性探测类库抛错。
87
+ - **Uniform 块**:`getUniformBlockIndex`、`getActiveUniformBlockParameter`、`getActiveUniformBlockName`、`uniformBlockBinding`、`bindBufferBase`/`bindBufferRange`、`getIndexedParameter`。块成员按 std140 合并进引擎的单一 uniform 块,绘制时从绑定缓冲复制;支持标量/向量/矩阵与定长数组,不支持嵌套结构体、采样器成员和省略实例名的块。
88
+ - **Transform feedback**:入口存在但为空操作,避免特性探测类库抛错。
87
89
 
88
- 纹理创建时带完整 mip 链;在 `generateMipmap` 之前采样被钳制到第 0 层。矩阵顶点属性会占用相应数量的连续 location,每个 location 读取一列。未启用的属性由最近一次 `vertexAttrib*f` 的值通过一个小常量缓冲提供。
90
+ 纹理创建时带完整 mip 链;在 `generateMipmap` 之前采样被钳制到第 0 层。矩阵顶点属性会占用相应数量的连续 location,每个 location 读取一列。未启用的属性由最近一次 `vertexAttrib*f` 的值通过一个小常量缓冲提供。顶点着色器可以像片元着色器一样采样纹理:`MAX_VERTEX_TEXTURE_IMAGE_UNITS` 报告 16,顶点采样器走 set 0,并在每次绘制时通过 `SDL_BindGPUVertexSamplers` 绑定。深度值按后端的 `[0, 1]` 裁剪空间存储,不做 GL 的 `[-1, 1] → [0, 1]` 重映射:`gl_Position.z = 0.5` 写入的深度是 `0.5`(真实 WebGL 为 `0.75`)。
89
91
 
90
92
  ## 未实现
91
93
 
92
- 着色器源码里的 uniform buffer 对象、transform feedback(入口为空操作)、立方体贴图、3D/数组纹理、浮点/半浮点纹理、深度纹理、压缩纹理、多渲染目标(只写第一个片元输出)、`blitFramebuffer`、MSAA/采样缓冲、模板操作(状态接受,但不写模板缓冲)、常量混合颜色、`drawingBufferStorage`、上下文丢失、`bufferData` 的非 static/dynamic `usage`(提示被忽略)、`texImage2D` 对 `HTMLVideoElement`/`ImageBitmap` 的支持,以及带 scissor 的 `clear`(clear 会清空整个附件)。使用内建块、用户 uniform 块或超出支持范围的 `gl_FragDepth` 的着色器会以编译/链接日志报错。
93
-
94
- 引擎报告的顶点纹理单元数量为 0,因此行为良好的 WebGL 1 程序不会在顶点着色器里采样纹理。
94
+ transform feedback(入口为空操作)与 MSAA/采样缓冲(SDL_GPU 的 Metal 多采样 resolve 在 scissor 与实例化绘制下返回未定义像素,因此上下文保持单采样)。`blitFramebuffer` 只复制颜色附件,深度/模板位被接受但不复制。使用内建块或 `gl_FragDepth` 的着色器会以编译/链接日志报错。
95
95
 
96
96
  ## 平台
97
97
 
@@ -101,8 +101,14 @@ WebGL 2 额外提供:
101
101
 
102
102
  ## 测试
103
103
 
104
- - `tests/e2e/gui-webgl.test.ts` 编译 GLSL、绘制带纹理和深度测试的四边形、检查面剔除,并读回像素。
105
- - `tests/e2e/gui-webgl2.test.ts` 覆盖 WebGL 2 的新增能力:`#version 300 es` 着色器、VAO 往返、带 divisor 的实例化绘制、`texStorage2D`、`clearBufferfv`、缓冲拷贝、采样器对象与结构体 uniform 字段。
104
+ - `tests/e2e/gui-webgl.test.ts` 编译 GLSL、绘制带纹理和深度测试的四边形、检查面剔除,并读回像素;它还覆盖混合常量色、动态缓冲 usage、顶点着色器纹理采样、`gl_FragDepth` 诊断、上下文丢失/恢复与立方体贴图。
105
+ - `tests/e2e/gui-webgl2.test.ts` 覆盖 WebGL 2 的着色器/状态新增能力:`#version 300 es` 着色器、VAO 往返、带 divisor 的实例化绘制、`texStorage2D`、`clearBufferfv`、缓冲拷贝、采样器对象、结构体 uniform 字段与 `drawingBufferStorage`。
106
+ - `tests/e2e/gui-webgl2-formats.test.ts` 覆盖模板、浮点/深度纹理、压缩纹理与 `ImageBitmap`。
107
+ - `tests/e2e/gui-webgl2-blit.test.ts` 覆盖带 scissor 的颜色/深度清除、framebuffer blit,以及局部 blit 之外必须保留的像素(在 Metal 上,若目标 load-op 丢弃这些像素,该测试就会失败)。
108
+ - `tests/e2e/gui-webgl2-3d.test.ts` 覆盖 2D 数组纹理与 3D 纹理的多层采样、`texSubImage3D` 子区域更新与 `framebufferTextureLayer` 渲染到数组层。
109
+ - `tests/e2e/gui-webgl2-mrt.test.ts` 覆盖两个片元输出分别写入两个颜色附件。
110
+ - `tests/e2e/gui-webgl2-ubo.test.ts` 覆盖 uniform 块的绑定、std140 成员与运行时更新。
111
+ - `tests/e2e/gui-media.test.ts` 还会把 `<video>` 的最新解码帧上传为纹理并读回像素。
106
112
  - `examples/gui/webgl-cube` 是一个旋转、受光、带纹理的立方体;它在浏览器中原样运行,并由 `tests/e2e/gui-example-webgl.test.ts` 覆盖。
107
113
  - `examples/gui/webgl2-cubes` 用一次绘制调用画出 64 个实例化立方体,使用 `#version 300 es` 与 VAO;由 `tests/e2e/gui-example-webgl2.test.ts` 覆盖。
108
114
 
@@ -112,4 +118,4 @@ WebGL 2 额外提供:
112
118
 
113
119
  `.js` 资源加载器现在只修补 three.js 的着色器循环展开;`WebGLRenderer` 在本引擎真正的 WebGL 2 后端上原样运行,**不再打包 Canvas2D 回退**。已用 three.js r160 通过 SDL_GPU 验证:`MeshBasicMaterial`、`MeshStandardMaterial`、`MeshPhongMaterial`、`CanvasTexture`、线性雾、环境光/平行光/点光/聚光/半球光、`Sprite`、`Line`、`Points` 与 `InstancedMesh`。
114
120
 
115
- 本引擎子集之外的能力仍无法模拟:阴影贴图(深度纹理)、立方体贴图/环境贴图、HDR/浮点渲染目标、多渲染目标、transform feedback 与压缩纹理。需要这些能力的场景无法正确渲染;此前 Canvas2D 回退能显示的内容现在全部走 GPU。
121
+ 本引擎子集之外的能力仍无法模拟:transform feedback 与 MSAA;立方体贴图/环境贴图、深度纹理、HDR/浮点渲染目标与压缩纹理已经可用。需要这些能力的场景无法正确渲染;此前 Canvas2D 回退能显示的内容现在全部走 GPU。
package/doc/zh-CN/gui.md CHANGED
@@ -5,7 +5,7 @@
5
5
  状态:**M19** —— 功能(M1–M15)已全部完成:HTML 解析、CSS 选择器匹配、层叠(cascade)、计算样式与布局(块级、行内、Flexbox 与 CSS 定位)均已就位,引擎还会**绘制**:它构建一个由矩形、图像与排版后的文本 run 组成的显示列表,并通过 SDL_GPU 渲染。输入事件会经过命中测试并投递给原生 TS 处理器,`:hover`/`:focus` 会被动态匹配,`<img>` 依据其固有尺寸确定大小并从纹理绘制——位图(PNG/JPEG/…)与 SVG 文件皆可,后者按绘制尺寸光栅化,因此矢量图保持清晰——CSS transition 会为绘制属性做动画。**M16** 让内联 `<svg>` 子树获得同样的处理:子树被序列化回 SVG 文档,并按绘制设备尺寸光栅化,因此图标不再需要单独的文件。**M8** 增加了交互式 DOM:具有稳定标识的元素句柄、变更操作(`appendChild`、`textContent`、`classList`、`style` 等)以及支持捕获/冒泡的元素级事件。**M9** 会提前编译 `<script>` 主体(内联与 `<script src>`)——参见 `gui-scripts.md`。**M10** 增加 `requestAnimationFrame` 以及若干 DOM 辅助方法。**M11** 增加 `position: relative`/`absolute`/`fixed` 及其偏移,`examples/gui/pelican-bike`(一个可玩的 2D 游戏)就构建在它之上。**M12** 明确了 DOM 节点生命周期(哪些变更释放、哪些保留),并让引擎内存有界:参见[节点生命周期](./gui/dom.md)与[内存与 GC](./gui/runtime.md)。**M13** 真正播放
6
6
  `<video>`/`<audio>`——可选的 `media` 扩展用 vendored 的最小 FFmpeg 在主线程解码,
7
7
  视频帧走图像纹理路径、音频进入 SDL 流,DOM 媒体 API 暴露
8
- `play`/`pause`/`currentTime`/… 与媒体事件。只启用 `gui` 不会链接 FFmpeg。**M14** 增加了 `<canvas>`,配一个自研的 2D 软件光栅器(抗锯齿
8
+ `play`/`pause`/`currentTime`/… 与媒体事件。只启用 `gui` 不会链接 FFmpeg。浏览器全局还带有真正可用的 `AudioContext`:`runtime/ext_gui/audio_mixer.cpp` 中的 48 kHz 混音器,以及 `decodeAudioData`(WAV 由引擎内解码,压缩格式经 `media`)——见 [GUI API](./gui/api.md#web-audio)。**M14** 增加了 `<canvas>`,配一个自研的 2D 软件光栅器(抗锯齿
9
9
  填充、路径、文本与 `drawImage`),并经图像纹理路径上传——参见
10
10
  [Canvas](./gui/canvas.md)。**M15** 增加了 CSS `transform` /
11
11
  `transform-origin`:每个布局盒一个合成好的 `Matrix2D`,由显示列表一路带到
@@ -142,7 +142,8 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
142
142
  只记录日志而不标注运行。
143
143
  - `package` job 在组装发布之前构建 `gui.a`/`gui.lib` 与 `media.a`/`media.lib`,
144
144
  因此两者都会随现有 runtime 归档一起发布(`package-release` 复制整个
145
- `runtime/`)。Windows x64 已包含;Windows arm64 仍跳过。
145
+ `runtime/`),也会打进可选的 `@xbintsc/<os>-<arch>` npm 包。Windows x64
146
+ 已包含;Windows arm64 仍跳过。
146
147
  - `vendor/`(GUI 归档的 SDL3/FreeType/HarfBuzz,以及 `media` 的 FFmpeg,
147
148
  缓慢的部分)按 OS/arch 缓存,以 `scripts/build-gui.ts` /
148
149
  `scripts/build-media.ts` 为键。Windows x64 有独立的源码 + FFmpeg 安装前缀
@@ -34,8 +34,8 @@ npx xbintsc build src/main.ts --out build
34
34
  4. 运行产物(`./build/<name>`,Windows 上是 `.exe`),并报告其路径。
35
35
  5. 如果构建报不支持的语法,阅读安装包里的子集指南
36
36
  `node_modules/xbintsc/doc/ai/language-support.md`;不要假设 Node 能跑的
37
- TypeScript 就一定能编译。首次构建还会编译 C 运行时,请预留比增量构建更多的
38
- 时间。
37
+ TypeScript 就一定能编译。装有可选平台包时,首次构建直接链接预编译运行时;
38
+ 没有平台包时才会从源码编译 C 运行时,那次构建会明显更慢。
39
39
 
40
40
  不要在 `node_modules/xbintsc` 里运行 `npm install`,也不要用 `tsc`/`esbuild`
41
41
  代替 xbintsc:原生产物必须由 `npx xbintsc` 生成。`xbintsc` 不读取
@@ -52,15 +52,18 @@ npx xbintsc build src/main.ts --out build
52
52
  它通过 Node.js 运行编译器。产出的二进制仍然是独立的:不嵌入 Node、V8 或
53
53
  TypeScript 编译器。
54
54
 
55
+ 安装它时还会安装宿主平台对应的可选包 `@xbintsc/<os>-<arch>`(例如
56
+ `@xbintsc/linux-x64`)。该包在 `runtime/lib/<os>-<arch>/` 下携带预编译运行时归档:
57
+ `core`、`ext_node`,以及发布时为该平台构建的 `gui` 与 `media`。驱动会就地链接这些
58
+ 归档,因此首次构建不再编译 C 运行时,也不需要用户再去发布页下载。
59
+
55
60
  这个包**不包含**:
56
61
 
57
- - C 编译器——构建机器需要 clang 16+;
58
- - 预编译的运行时归档(`runtime/lib/<os>-<arch>/core.a`)。驱动会在首次使用时
59
- 从随包发布的源码编译 C 运行时并缓存目标文件,所以第一次构建会更慢
60
- (见[首次构建与缓存](#首次构建与缓存));
61
- - GUI/media 的原生归档(`gui.a`/`gui.lib`、`media.a`/`media.lib`)。如果你需要
62
- `--ext gui` 或 `--ext media`,请使用 Linux/macOS/Windows x64 的发布压缩包,
63
- 或从源码检出中构建这些归档。
62
+ - C 编译器——构建机器需要 clang 16+。
63
+
64
+ 如果 npm 跳过了这个可选包(`--omit=optional`、不安装可选依赖的包管理器,或发布
65
+ 未覆盖的宿主平台),驱动会回退到从随包源码编译 C 运行时并缓存目标文件;这样仍能
66
+ 工作,但首次构建更慢,`--ext gui` / `--ext media` 也需要归档存在。
64
67
 
65
68
  ## 环境要求
66
69
 
@@ -175,7 +178,7 @@ npm run build:native
175
178
  ./build/main # Windows 上是 .\build\main.exe
176
179
  ```
177
180
 
178
- 预期输出(首次构建还会编译 C 运行时):
181
+ 预期输出:
179
182
 
180
183
  ```text
181
184
  xbintsc: wrote /absolute/path/my-app/build/main
@@ -187,14 +190,32 @@ Hello from xbintsc
187
190
 
188
191
  ## 首次构建与缓存
189
192
 
190
- 运行时目标文件按源码/头文件内容哈希缓存。默认缓存目录是**执行命令时所在目录**下
191
- 的 `.xbintsc/`(不一定是配置文件所在目录);可以用 `xbintsc_CACHE_DIR` 改到别处。
193
+ 装有平台包时,首次构建直接链接预编译的
194
+ `runtime/lib/<os>-<arch>/core.a`(Windows 上是 `.lib`),完全不编译 C,耗时与
195
+ 增量构建接近。
196
+
197
+ 如果可选包缺失——`npm install --omit=optional`、包管理器不安装可选依赖,或发布
198
+ 未覆盖当前宿主平台——驱动才会从随包源码编译 C 运行时。运行时目标文件按源码/
199
+ 头文件内容哈希缓存。默认缓存目录是**执行命令时所在目录**下的 `.xbintsc/`
200
+ (不一定是配置文件所在目录);可以用 `xbintsc_CACHE_DIR` 改到别处。这种回退构建
201
+ 会明显比后续构建慢。
202
+
203
+ 如果确实想忽略平台包归档、改从主包自带的源码编译 C 运行时(例如修改了
204
+ `runtime/`,或预编译归档与当前环境不匹配),可以设置:
205
+
206
+ ```bash
207
+ xbintsc_PREFER_PREBUILT=0 npx xbintsc build src/main.ts --out build
208
+ ```
209
+
210
+ 目标文件仍会缓存到 `.xbintsc/`;要完整重编,请把 `xbintsc_CACHE_DIR` 指向空目录
211
+ (或删除 `.xbintsc/`)。只加 `--force` 不会绕过预编译归档。归档文件本身由源码
212
+ 检出中的 `npm run runtime` 生成;普通用户编译时不需要重新生成它们。
192
213
 
193
- npm 包只带运行时的 C 源码,不带预编译的 `core.a`,所以第一次构建会逐个编译
194
- 运行时的翻译单元。这次构建会明显比后续构建慢。`--time` 可以看到时间花在哪里:
214
+ `--time` 可以看到时间花在哪里:
195
215
 
196
216
  ```bash
197
217
  npx xbintsc build src/main.ts --out build --time
218
+ # 未装平台包时的回退构建:
198
219
  # xbintsc: timing (frontend 4ms, codegen 7ms, clang 1089ms, runtime 37770ms, link 1966ms)
199
220
  ```
200
221
 
@@ -208,8 +229,8 @@ npx xbintsc build src/main.ts --out build
208
229
  实际使用中的建议:
209
230
 
210
231
  - 把 `.xbintsc/` 加进 `.gitignore`;
211
- - 在 CI 里保留 `.xbintsc/`(或把 `xbintsc_CACHE_DIR` 指向持久目录),避免每次
212
- 都重新编译运行时;
232
+ - 在 CI 里保留 `.xbintsc/`(或把 `xbintsc_CACHE_DIR` 指向持久目录),避免回退
233
+ 构建每次都重新编译运行时;
213
234
  - 删除 `.xbintsc/` 是安全的——下一次构建会重新生成;
214
235
  - `--force` 只忽略构建新鲜度记录,已缓存且内容哈希相同的运行时目标文件仍会复用。
215
236
  如果要强制完整重编 C 运行时,请删除 `.xbintsc/`。
@@ -350,15 +371,15 @@ jobs:
350
371
  | | npm 包(`xbintsc`) | 预编译发布压缩包 |
351
372
  | --- | --- | --- |
352
373
  | 需要 Node.js | 是,22+ | 否 |
353
- | 首次构建 | 从源码编译 C 运行时 | 直接链接预编译运行时 |
354
- | GUI / media 扩展 | 不包含 | Linux/macOS 与 Windows x64 压缩包包含 |
374
+ | 首次构建 | 链接可选平台包里的预编译运行时 | 直接链接预编译运行时 |
375
+ | GUI / media 扩展 | Linux/macOS 与 Windows x64(发布为这些平台构建)包含 | Linux/macOS 与 Windows x64 压缩包包含 |
355
376
  | 安装方式 | `npm install` + lockfile / provenance | 下载、校验 `.sha256`、解压 |
356
377
  | 编程 API | 有 | 无(仅 CLI) |
357
378
  | 交叉编译 | 否——只构建宿主平台 | 否——只构建宿主平台 |
358
- | 适合 | Node 项目与 CI,沿用熟悉的 npm 流程 | 没有 Node 的机器、首次构建要快、GUI 应用 |
379
+ | 适合 | Node 项目与 CI,沿用熟悉的 npm 流程 | 没有 Node 的机器、GUI 应用、完全自包含的安装 |
359
380
 
360
- 如果只需要核心运行时和 `node` 扩展,npm 包最方便。如果需要最快的冷启动构建,
361
- 或者需要 GUI/media 归档,请使用发布压缩包(开发时也可以从源码构建)。
381
+ npm 包通过可选平台包获得同一套预编译运行时,只有在跳过该包时才会付出从源码编译
382
+ 的冷启动成本。没有 Node 时请使用发布压缩包。
362
383
 
363
384
  ## 与普通 Node 构建的差异
364
385
 
@@ -383,10 +404,10 @@ jobs:
383
404
  | `npx xbintsc` 用了意料之外的版本 | 运行 `npx --no-install xbintsc version` 和 `npm ls xbintsc`;在 `package.json` 中固定版本,CI 用 `npm ci`。 |
384
405
  | `requires Node.js 22` / engine 错误 | 升级 Node;编译器使用了较新的 Node API。 |
385
406
  | `No C compiler found` 或 `requires clang 16 or newer` | 安装 clang 16+,运行 `npx xbintsc doctor`;需要时用 `xbintsc_CLANG` 指定 clang。 |
386
- | 第一次构建很慢 | 正常:正在编译并缓存运行时 C 源码。后续构建会复用 `.xbintsc/`;`--time` 可确认。如果冷启动必须快,请使用发布压缩包。 |
407
+ | 第一次构建很慢 | 可选包 `@xbintsc/<os>-<arch>` 被跳过(或该宿主没有预编译包),正在编译并缓存运行时 C 源码。用 `npm ls @xbintsc/<os>-<arch>` 检查,并去掉 `--omit=optional` 重新安装;`--time` 可确认。 |
387
408
  | 写 `.xbintsc/` 权限错误 | 用 `xbintsc_CACHE_DIR` 指向可写目录,或在可写目录中运行。 |
388
409
  | `module 'fs' is provided by the 'node' extension` | 加 `--ext node`,或在配置里写 `"extensions": ["node"]`。 |
389
- | `GUI native library not found` / `media native library not found` | npm 包不包含 `gui.a`/`gui.lib` 或 `media.a`/`media.lib`;请使用 Linux/macOS/Windows x64 发布压缩包,或从源码检出构建。 |
410
+ | `GUI native library not found` / `media native library not found` | 携带 `gui.a`/`gui.lib` 或 `media.a`/`media.lib` 的可选平台包被跳过,或该宿主没有预编译的 GUI/media 归档(Windows arm64)。去掉 `--omit=optional` 重新安装,或使用 Linux/macOS/Windows x64 发布压缩包,或从源码检出构建。 |
390
411
  | `require("xbintsc")` 失败 | 包只提供 ESM;使用 `import`(或动态 `import()`)。 |
391
412
  | Windows 链接时报缺少 MSVC 库 | 在 Native Tools 命令提示符中运行,安装 VS C++ 生成工具,并检查 `npx xbintsc doctor`。 |
392
413
  | `npm ci --omit=dev` 后构建找不到 `xbintsc` | 在构建阶段安装 devDependencies,或把 `xbintsc` 移到 `dependencies`。 |
@@ -76,7 +76,10 @@ xbintsc-<os>-<arch>/
76
76
  runtime/ C 运行期 + 预编译 runtime/lib/<os>-<arch>/
77
77
  ```
78
78
 
79
- Windows 归档不含预编译 `runtime/lib/`;驱动会用用户的 clang 按需编译 C 运行期。
79
+ 每个归档都带有该宿主的预编译运行期,位于 `runtime/lib/<os>-<arch>/`:所有平台都有
80
+ `core` 与 `ext_node`(Windows 的 MSVC ABI 下是 `.lib` 而不是 `.a`),发布为其构建
81
+ 时还包括 `gui`/`media`。npm 包通过可选的 `@xbintsc/<os>-<arch>` 依赖获得同一套归档,
82
+ 因此从 npm 安装也不需要编译 C 运行期。
80
83
 
81
84
  解压后把 `bin/` 加入 `PATH`(或直接调用 `bin/xbintsc`),再按下面的平台说明安装
82
85
  工具链。建议先校验下载内容:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xbintsc",
3
- "version": "0.5.32",
3
+ "version": "0.5.36",
4
4
  "description": "xbintsc - a TypeScript binary compiler (TypeScript -> LLVM IR -> native binary)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,7 +24,12 @@
24
24
  "files": [
25
25
  "src",
26
26
  "dist",
27
+ "!dist/release",
28
+ "!dist/npm-platform",
29
+ "!dist/xbintsc",
30
+ "!dist/*.exe",
27
31
  "runtime",
32
+ "!runtime/lib",
28
33
  "scripts",
29
34
  "bin",
30
35
  "doc",
@@ -39,6 +44,9 @@
39
44
  "gui": "tsx scripts/build-gui.ts",
40
45
  "media": "tsx scripts/build-media.ts",
41
46
  "package-release": "tsx scripts/package-release.ts",
47
+ "package-platform": "tsx scripts/package-platform.ts",
48
+ "platform-versions": "tsx scripts/set-platform-version.ts",
49
+ "verify:platform": "tsx scripts/verify-platform-package.ts",
42
50
  "runtime:clean": "node -e \"require('fs').rmSync('build/runtime-obj',{recursive:true,force:true});require('fs').rmSync('runtime/lib',{recursive:true,force:true})\"",
43
51
  "xbintsc": "tsx src/cli/main.ts",
44
52
  "typecheck": "tsc -p tsconfig.json --noEmit",
@@ -63,6 +71,14 @@
63
71
  "typescript-eslint": "^8.70.1",
64
72
  "vitest": "^2.1.8"
65
73
  },
74
+ "optionalDependencies": {
75
+ "@xbintsc/linux-x64": "0.5.36",
76
+ "@xbintsc/linux-arm64": "0.5.36",
77
+ "@xbintsc/darwin-x64": "0.5.36",
78
+ "@xbintsc/darwin-arm64": "0.5.36",
79
+ "@xbintsc/win32-x64": "0.5.36",
80
+ "@xbintsc/win32-arm64": "0.5.36"
81
+ },
66
82
  "engines": {
67
83
  "node": ">=22"
68
84
  }