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
package/doc/gui/dom.md CHANGED
@@ -14,9 +14,12 @@ close rules (`li`, `dt`/`dd`, `option`, `p`, headings, table cells/rows).
14
14
  **CSS parser** (`runtime/ext_gui/css.{h,cpp}`): comments are stripped; `@media`
15
15
  blocks are parsed recursively (nested queries combine with `and`, and a comma
16
16
  list distributes over the inner query) while other at-rules are skipped. Rules
17
- support multiple selectors and declarations. Selectors: type, `.class`, `#id`,
18
- attribute (`=`, `~=`, `|=`, `^=`, `$=`, `*=`), the four combinators
19
- (descendant, child, adjacent and general sibling), the pseudo-classes
17
+ support multiple selectors and declarations; a selector list may be formatted
18
+ across any number of lines (line breaks are ordinary whitespace, so a wrapped
19
+ combinator stays a combinator), and a quoted attribute value may contain
20
+ commas, brackets or parentheses without splitting the list. Selectors: type,
21
+ `.class`, `#id`, attribute (`=`, `~=`, `|=`, `^=`, `$=`, `*=`), the four
22
+ combinators (descendant, child, adjacent and general sibling), the pseudo-classes
20
23
  `:first-child`, `:last-child`, `:only-child`, `:empty`, `:root`, `:not(...)`,
21
24
  `:nth-child(an+b)`, `:disabled`, `:checked`, plus the stateful `:hover` and
22
25
  `:focus` (see [Input](./input.md)), and the pseudo-elements `::before`/`::after`
package/doc/gui/media.md CHANGED
@@ -112,6 +112,10 @@ platform media framework in the path either way.
112
112
  - **Threading.** The engine is single-threaded and not thread-aware, so all
113
113
  decoding happens on the main thread inside `xt_gui_media_tick` — no decode
114
114
  thread, no cross-thread GC exposure.
115
+ - **`decodeAudioData`.** The same FFmpeg build also decodes an in-memory audio
116
+ file for `AudioContext.decodeAudioData` (`runtime/ext_media/decode_audio.cpp`,
117
+ through the media table); WAV is handled by the GUI engine itself
118
+ (`audio_decode.cpp`), so only compressed formats need this extension.
115
119
  - **DOM API.** Element handles expose the media surface directly (see
116
120
  `runtime/ext_gui/dom_api_media.cpp` and the prototype in
117
121
  `dom_api_proto.cpp`): `play()` / `pause()` / `load()`, and the
package/doc/gui/webgl.md CHANGED
@@ -96,8 +96,7 @@ reflected offsets; `uniform1i` on a sampler stores the texture unit. The block
96
96
  is pushed with the dynamic uniform-buffer API on every draw.
97
97
 
98
98
  Limits of the translator: struct-typed uniforms, user uniform blocks, uniform
99
- arrays whose size is not resolved by the preprocessor, sampler arrays and cube
100
- maps are rejected (the link/shader info log says so). Shader code inside
99
+ arrays whose size is not resolved by the preprocessor, sampler arrays are rejected (the link/shader info log says so). Shader code inside
101
100
  `#ifdef` is fine; non-sampler uniform declarations are moved to the enclosing
102
101
  top-level position so the block stays unconditional.
103
102
 
@@ -115,8 +114,11 @@ available from GLSL ES 3.00, which is what the instanced example uses.
115
114
 
116
115
  - **Context**: `getContext("webgl")`, `canvas`, `drawingBufferWidth/Height`,
117
116
  `getParameter`, `getError`, `getSupportedExtensions`, `getExtension`,
118
- `getContextAttributes`, `isContextLost`, `getShaderPrecisionFormat`, and the
119
- stencil entry points (accepted; the depth target has no stencil attachment).
117
+ `getContextAttributes`, `isContextLost`, `getShaderPrecisionFormat`, and an
118
+ 8-bit stencil buffer (`getContextAttributes().stencil` is `true`,
119
+ `STENCIL_BITS` is 8). `WEBGL_lose_context`'s `loseContext`/`restoreContext`
120
+ really drop and rebuild the context (every object becomes invalid) and
121
+ dispatch `webglcontextlost`/`webglcontextrestored`.
120
122
  - **Shaders and programs**: `createShader`, `shaderSource`, `compileShader`,
121
123
  `getShaderParameter`, `getShaderInfoLog`, `getShaderSource`, `deleteShader`,
122
124
  `createProgram`, `attachShader`, `detachShader`, `linkProgram`,
@@ -131,7 +133,9 @@ available from GLSL ES 3.00, which is what the instanced example uses.
131
133
  `bufferSubData`, `deleteBuffer`, `getBufferParameter`,
132
134
  `enableVertexAttribArray`, `disableVertexAttribArray`,
133
135
  `vertexAttribPointer`, `vertexAttrib1f`…`4f` / `1fv`…`4fv`,
134
- `getVertexAttrib`.
136
+ `getVertexAttrib`. The `usage` hint from `bufferData`
137
+ (`STREAM_DRAW`/`STATIC_DRAW`/`DYNAMIC_DRAW`) is recorded and reported by
138
+ `getBufferParameter(…, BUFFER_USAGE)`.
135
139
  - **Drawing**: `drawArrays`, `drawElements` (UNSIGNED_BYTE, UNSIGNED_SHORT,
136
140
  UNSIGNED_INT; `TRIANGLE_FAN` and `LINE_LOOP` are expanded to lists).
137
141
  `POINTS`, `LINES`, `LINE_STRIP`, `TRIANGLES` and `TRIANGLE_STRIP` map to the
@@ -140,22 +144,50 @@ available from GLSL ES 3.00, which is what the instanced example uses.
140
144
  `texParameteri`/`texParameterf`, `getTexParameter`, `texImage2D` (raw pixels,
141
145
  `<img>`, `<canvas>` and `ImageData` sources), `texSubImage2D`,
142
146
  `generateMipmap`, `deleteTexture`. `UNPACK_FLIP_Y_WEBGL` and
143
- `UNPACK_PREMULTIPLY_ALPHA_WEBGL` are honoured. Everything is converted to
144
- RGBA8; `RGBA`, `RGB`, `LUMINANCE`, `ALPHA` and `LUMINANCE_ALPHA` with
145
- `UNSIGNED_BYTE` are accepted.
146
- - **Framebuffers**: `createFramebuffer`, `bindFramebuffer`,
147
- `framebufferTexture2D` (colour attachment), `checkFramebufferStatus`,
148
- `createRenderbuffer`, `bindRenderbuffer`, `renderbufferStorage` (depth),
149
- `framebufferRenderbuffer`, `delete*`. This is enough for render-to-texture,
150
- shadow maps and post-processing passes.
147
+ `UNPACK_PREMULTIPLY_ALPHA_WEBGL` are honoured. By default source data is
148
+ converted to RGBA8; `RGBA`, `RGB`, `LUMINANCE`, `ALPHA` and
149
+ `LUMINANCE_ALPHA` with `UNSIGNED_BYTE` are accepted. Float textures
150
+ (`RGBA32F`, `RGBA16F`, `RGB32F`, `RGB16F`, `RG32F`/`RG16F`, `R32F`/`R16F`
151
+ with `FLOAT` or `HALF_FLOAT` data, plus WebGL 1's
152
+ `OES_texture_float`/`OES_texture_half_float`) map to SDL's RGBA32F/RGBA16F,
153
+ and depth textures (`DEPTH_COMPONENT16/24/32F`, `DEPTH_STENCIL`,
154
+ `DEPTH24_STENCIL8`) map to `D32_FLOAT`/`D32_FLOAT_S8_UINT` and can be sampled
155
+ or used as depth attachments. Compressed textures upload through
156
+ `compressedTexImage2D`/`compressedTexSubImage2D` with
157
+ `WEBGL_compressed_texture_s3tc` (BC1/BC2/BC3),
158
+ `WEBGL_compressed_texture_s3tc_srgb` and `WEBGL_compressed_texture_astc`;
159
+ each extension is published only when the device can sample its formats.
160
+ `texImage2D` also accepts the latest decoded `<video>` frame and an
161
+ `ImageBitmap` produced by `createImageBitmap`. Cube maps
162
+ (`bindTexture(TEXTURE_CUBE_MAP)` plus six `texImage2D` faces) and 3D/array
163
+ textures (`texImage3D`/`texStorage3D`) are sampled through `samplerCube`,
164
+ `sampler3D` and `sampler2DArray`; `texSubImage3D` updates a sub-volume and
165
+ `framebufferTextureLayer` renders one array/cube layer as a colour
166
+ attachment.
167
+ - **Framebuffers**: `createFramebuffer`, `bindFramebuffer`
168
+ (`FRAMEBUFFER`/`READ_FRAMEBUFFER`/`DRAW_FRAMEBUFFER`),
169
+ `framebufferTexture2D` (`COLOR_ATTACHMENT0`, `DEPTH_ATTACHMENT`,
170
+ `DEPTH_STENCIL_ATTACHMENT`), `checkFramebufferStatus`, `createRenderbuffer`,
171
+ `bindRenderbuffer`, `renderbufferStorage` (depth or depth-stencil),
172
+ `framebufferRenderbuffer`, `delete*`, and `blitFramebuffer` (colour
173
+ attachment; depth/stencil bits are accepted but not copied). This is enough
174
+ for render-to-texture, shadow maps and post-processing passes.
151
175
  - **State**: `enable`/`disable`/`isEnabled` for `BLEND`, `DEPTH_TEST`,
152
- `CULL_FACE`, `SCISSOR_TEST` (stencil accepted but not applied),
153
- `clearColor`/`clearDepth`/`clearStencil`, `clear`, `blendFunc`/
154
- `blendFuncSeparate`, `blendEquation`/`blendEquationSeparate`, `depthFunc`,
155
- `depthMask`, `colorMask`, `cullFace`, `frontFace`, `viewport`, `scissor`,
156
- `pixelStorei`, `finish`.
176
+ `CULL_FACE`, `SCISSOR_TEST` and `STENCIL_TEST`,
177
+ `clearColor`/`clearDepth`/`clearStencil`, `clear` (with `SCISSOR_TEST` it
178
+ clears only the scissor rectangle, for colour, depth and stencil), `blendColor`,
179
+ `blendFunc`/`blendFuncSeparate`,
180
+ `blendEquation`/`blendEquationSeparate`, `depthFunc`,
181
+ `depthMask`, `colorMask`, `stencilFunc`/`stencilFuncSeparate`,
182
+ `stencilOp`/`stencilOpSeparate`, `stencilMask`/`stencilMaskSeparate`,
183
+ `cullFace`, `frontFace`, `viewport`, `scissor`,
184
+ `pixelStorei`, `finish`. The stencil test takes part in rasterisation and
185
+ `clear(STENCIL_BUFFER_BIT)` clears the stencil attachment; SDL_GPU exposes
186
+ one reference and one compare/write mask for both faces, so a front/back
187
+ pair that differs uses the front value.
157
188
  - **Readback**: `readPixels` (RGBA/UNSIGNED_BYTE) from the default framebuffer
158
- or a bound framebuffer. It blocks until the GPU finishes; use it for tests and
189
+ or a bound RGBA8 framebuffer; a float/depth attachment is sampled into an
190
+ RGBA8 target first. It blocks until the GPU finishes; use it for tests and
159
191
  screenshots, not per frame.
160
192
 
161
193
  WebGL 2 adds:
@@ -174,38 +206,46 @@ WebGL 2 adds:
174
206
  texture's own filter/wrap state for that unit.
175
207
  - **Immutable textures and buffer copies**: `texStorage2D` (the backend always
176
208
  allocates the full mip chain), `copyBufferSubData`, `getBufferSubData`.
209
+ - **Drawing buffer**: `drawingBufferStorage(width, height)` fixes the drawing
210
+ buffer size; `canvas.width`/`canvas.height` no longer rebuild it afterwards.
177
211
  - **Clears**: `clearBufferfv`, `clearBufferiv`, `clearBufferuiv`,
178
212
  `clearBufferfi`.
213
+ - **Multiple render targets**: `drawBuffers` addresses up to four colour
214
+ attachments and `readBuffer` selects the attachment `readPixels` reads;
215
+ `framebufferTexture2D` accepts `COLOR_ATTACHMENT0`…`3`, and a fragment
216
+ shader's multiple `out` variables are written in order.
179
217
  - **Queries and fences**: the objects and entry points exist
180
218
  (`createQuery`/`beginQuery`/`endQuery`/`getQueryParameter`,
181
219
  `fenceSync`/`clientWaitSync`/`waitSync`/`getSyncParameter`) and degrade
182
220
  gracefully: a fence reports `ALREADY_SIGNALED` and query results are 0.
183
- - **Uniform blocks**: `getUniformBlockIndex` answers `INVALID_INDEX` so a
184
- library falls back to individual uniforms; the block entry points are no-ops.
185
- - **Transform feedback, 3D textures and compressed formats**: the entry points
186
- are present as no-ops so feature-probing libraries do not throw.
221
+ - **Uniform blocks**: `getUniformBlockIndex`,
222
+ `getActiveUniformBlockParameter`, `getActiveUniformBlockName`,
223
+ `uniformBlockBinding`, `bindBufferBase`/`bindBufferRange` and
224
+ `getIndexedParameter`. Members are merged into the engine's single std140
225
+ block and copied from the bound buffer at draw time; scalars, vectors,
226
+ matrices and fixed-size arrays work, nested structs, sampler members and
227
+ blocks without an instance name are rejected.
228
+ - **Transform feedback**: the entry points are present as no-ops so
229
+ feature-probing libraries do not throw.
187
230
 
188
231
  Textures are created with a full mip chain; sampling clamps to level 0 until
189
232
  `generateMipmap` runs. Matrix vertex attributes consume the right number of
190
233
  consecutive locations and read one column per location. A disabled attribute
191
234
  is supplied from the last `vertexAttrib*f` value through a small constant
192
- buffer.
235
+ buffer. A vertex shader can sample textures just like a fragment shader:
236
+ `MAX_VERTEX_TEXTURE_IMAGE_UNITS` reports 16, vertex samplers live in set 0 and
237
+ are bound with `SDL_BindGPUVertexSamplers` on every draw. Depth values use the
238
+ backend's `[0, 1]` clip space rather than GL's `[-1, 1] → [0, 1]` remap:
239
+ `gl_Position.z = 0.5` stores depth `0.5` (real WebGL stores `0.75`).
193
240
 
194
241
  ## Not implemented
195
242
 
196
- Uniform buffer objects in shader source, transform feedback (the entry points
197
- are no-ops), cube maps, 3D/array textures, float/half textures, depth textures,
198
- compressed textures, multiple render targets (only the first fragment output is
199
- written), `blitFramebuffer`, MSAA/sample buffers, stencil operations (state is
200
- accepted, the stencil buffer is not written), constant blend colours,
201
- `drawingBufferStorage`, context loss, `bufferData` with a `usage` other than
202
- static/dynamic (the hint is ignored), `texImage2D` for
203
- `HTMLVideoElement`/`ImageBitmap` and scissored `clear` (a clear clears the whole
204
- attachment). Shaders that use built-in blocks, user uniform blocks or
205
- `gl_FragDepth` beyond the supported subset are rejected with a compile/link log.
206
-
207
- The engine advertises zero vertex texture units, so a well-behaved WebGL 1
208
- program will not try to sample a texture in a vertex shader.
243
+ Transform feedback (the entry points are no-ops) and MSAA/sample buffers
244
+ (SDL_GPU's Metal multisample resolve returns undefined pixels with scissor
245
+ tests and instanced draws, so contexts stay single-sampled). `blitFramebuffer`
246
+ copies the colour attachment only; depth/stencil bits are accepted but not
247
+ copied. Shaders that use built-in blocks or `gl_FragDepth` are rejected with a
248
+ compile/link log.
209
249
 
210
250
  ## Platform
211
251
 
@@ -225,10 +265,27 @@ uses the 2D canvas or the DOM pays no run-time cost beyond the archive size.
225
265
  ## Testing
226
266
 
227
267
  - `tests/e2e/gui-webgl.test.ts` compiles GLSL, draws a textured and a
228
- depth-tested quad, checks face culling and reads the pixels back.
229
- - `tests/e2e/gui-webgl2.test.ts` covers the WebGL 2 additions: `#version 300 es`
230
- shaders, a VAO round trip, instanced draws with a divisor, `texStorage2D`,
231
- `clearBufferfv`, buffer copies, sampler objects and struct-uniform fields.
268
+ depth-tested quad, checks face culling and reads the pixels back; it also
269
+ covers blend constants, dynamic buffer usage, vertex-shader texture sampling,
270
+ `gl_FragDepth` diagnostics, context loss/restore and cube maps.
271
+ - `tests/e2e/gui-webgl2.test.ts` covers the WebGL 2 shader/state additions:
272
+ `#version 300 es` shaders, a VAO round trip, instanced draws with a divisor,
273
+ `texStorage2D`, `clearBufferfv`, buffer copies, sampler objects, struct-uniform
274
+ fields and `drawingBufferStorage`.
275
+ - `tests/e2e/gui-webgl2-formats.test.ts` covers stencil, float/depth textures,
276
+ compressed textures and `ImageBitmap`.
277
+ - `tests/e2e/gui-webgl2-blit.test.ts` covers scissored colour/depth clears,
278
+ framebuffer blits, and the pixels around a partial blit that must survive
279
+ (a destination load-op that discards them fails there on Metal).
280
+ - `tests/e2e/gui-media.test.ts` also uploads the latest decoded `<video>` frame
281
+ as a texture and reads it back.
282
+ - `tests/e2e/gui-webgl2-3d.test.ts` covers 2D-array and 3D texture layer
283
+ sampling, `texSubImage3D` sub-volume updates and rendering to a colour
284
+ attachment layer.
285
+ - `tests/e2e/gui-webgl2-mrt.test.ts` writes two fragment outputs to two
286
+ colour attachments and reads each back.
287
+ - `tests/e2e/gui-webgl2-ubo.test.ts` binds a std140 block, updates its members
288
+ and verifies the drawn colour.
232
289
  - `examples/gui/webgl-cube` is a spinning, lit, textured cube; it runs in a
233
290
  browser unchanged and is covered by
234
291
  `tests/e2e/gui-example-webgl.test.ts`.
@@ -249,8 +306,10 @@ is bundled any more**. Verified with three.js r160 through SDL_GPU:
249
306
  `CanvasTexture`, linear fog, ambient/directional/point/spot/hemisphere lights,
250
307
  `Sprite`, `Line`, `Points` and `InstancedMesh`.
251
308
 
252
- Features outside this engine's subset still cannot be emulated: shadow maps
253
- (depth textures), cube textures/environment maps, HDR/float render targets,
254
- multiple render targets, transform feedback and compressed textures. A scene
255
- that needs one of those will not render correctly; everything the previous
256
- Canvas2D fallback could show now goes through the GPU.
309
+ Features outside this engine's subset still cannot be emulated: transform
310
+ feedback and MSAA.
311
+ Depth textures, float render targets and compressed textures are available, but
312
+ three.js shadow maps still need comparative `sampler2DShadow` sampling, which
313
+ is not translated yet. A scene that needs one of those will not render
314
+ correctly; everything the previous Canvas2D fallback could show now goes
315
+ through the GPU.
package/doc/gui.md CHANGED
@@ -25,7 +25,10 @@ engine bounded memory: see [Node lifetime](./gui/dom.md#node-lifetime) and
25
25
  thread with a vendored minimal FFmpeg, video frames go through the image texture
26
26
  path and audio to an SDL stream, with the DOM media API exposing
27
27
  `play`/`pause`/`currentTime`/… and media events. Enabling `gui` alone does not
28
- link FFmpeg.
28
+ link FFmpeg. The browser globals also get a real `AudioContext`: a 48 kHz mixer
29
+ in `runtime/ext_gui/audio_mixer.cpp` plus `decodeAudioData` (WAV in-engine,
30
+ compressed formats through `media`) — see
31
+ [GUI API](./gui/api.md#web-audio).
29
32
  **M14** adds `<canvas>` with a self-written 2D software rasteriser (anti-aliased
30
33
  fills, paths, text and `drawImage`) uploaded through the image texture path —
31
34
  see [Canvas](./gui/canvas.md). **M15** adds CSS `transform` /
@@ -188,8 +191,9 @@ engine were Rust.
188
191
  annotating the run.
189
192
  - The `package` job builds `gui.a`/`gui.lib` and `media.a`/`media.lib` before
190
193
  assembling the release, so both ship inside the existing runtime archive
191
- (`package-release` copies all of `runtime/`). Windows x64 is included;
192
- Windows arm64 still skips them.
194
+ (`package-release` copies all of `runtime/`) and inside the optional
195
+ `@xbintsc/<os>-<arch>` npm package. Windows x64 is included; Windows arm64
196
+ still skips them.
193
197
  - `vendor/` (SDL3/FreeType/HarfBuzz for the GUI archive, FFmpeg for `media`)
194
198
  is cached per OS/arch, keyed by `scripts/build-gui.ts` /
195
199
  `scripts/build-media.ts`. Windows x64 gets its own source cache plus the
@@ -36,8 +36,9 @@ If you are an agent asked to build a project that already depends on `xbintsc`:
36
36
  4. Run the artifact (`./build/<name>`, `.exe` on Windows) and report its path.
37
37
  5. If the build reports unsupported syntax, read the installed subset guide at
38
38
  `node_modules/xbintsc/doc/ai/language-support.md`; do not assume
39
- Node-compatible TypeScript. The first build also compiles the C runtime, so
40
- allow more time than for an incremental build.
39
+ Node-compatible TypeScript. With the optional platform package installed the
40
+ first build links a prebuilt runtime; without it, the C runtime is compiled
41
+ from source and that build is noticeably slower.
41
42
 
42
43
  Do not run `npm install` inside `node_modules/xbintsc`, and do not substitute
43
44
  `tsc`/`esbuild` for xbintsc: the native artifact must come from `npx xbintsc`.
@@ -54,15 +55,22 @@ The package contains:
54
55
  It runs the compiler through Node.js. The binary it produces is still
55
56
  standalone: it does not embed Node, V8 or a TypeScript compiler.
56
57
 
58
+ Installing it also installs the optional `@xbintsc/<os>-<arch>` package for the
59
+ host (for example `@xbintsc/linux-x64`). That package contains the prebuilt
60
+ runtime archives under `runtime/lib/<os>-<arch>/`: `core`, `ext_node` and, where
61
+ the release publishes them, `gui` and `media`. The driver links those archives
62
+ in place, so the first build does not compile the C runtime and needs no extra
63
+ download from the release page.
64
+
57
65
  The package does **not** contain:
58
66
 
59
- - a C compiler — you need clang 16+ on the machine that builds;
60
- - prebuilt runtime archives (`runtime/lib/<os>-<arch>/core.a`). The driver
61
- compiles the C runtime from the shipped sources on first use and caches the
62
- objects, so the first build is slower (see [the cache](#the-first-build-and-the-cache));
63
- - the GUI/media native archives (`gui.a`, `media.a`). If you need `--ext gui` or
64
- `--ext media`, use a Linux/macOS release archive or build those archives from
65
- a source checkout.
67
+ - a C compiler — you need clang 16+ on the machine that builds.
68
+
69
+ If npm skips the optional package (`--omit=optional`, a package manager that
70
+ does not install optional dependencies, or a host the release does not build
71
+ for), the driver falls back to compiling the C runtime from the shipped sources
72
+ and caches the objects; that build works but is slower, and `--ext gui` /
73
+ `--ext media` need the archive to be present.
66
74
 
67
75
  ## Requirements
68
76
 
@@ -182,7 +190,7 @@ npm run build:native
182
190
  ./build/main # .\build\main.exe on Windows
183
191
  ```
184
192
 
185
- Expected output (the first build also compiles the C runtime):
193
+ Expected output:
186
194
 
187
195
  ```text
188
196
  xbintsc: wrote /absolute/path/my-app/build/main
@@ -195,17 +203,38 @@ pass the file explicitly: `xbintsc build src/main.ts --out build`.
195
203
 
196
204
  ## The first build and the cache
197
205
 
198
- The runtime objects are cached by source/header content hash. The default cache
199
- is `.xbintsc/` **in the directory you run the command from** (not necessarily
200
- next to the config file); set `xbintsc_CACHE_DIR` to put it elsewhere.
206
+ With the platform package installed, the first build links the prebuilt
207
+ `runtime/lib/<os>-<arch>/core.a` (`.lib` on Windows) and does not compile C at
208
+ all, so it takes about as long as an incremental build.
209
+
210
+ If the optional package is missing — `npm install --omit=optional`, a package
211
+ manager that does not install optional dependencies, or a host the release does
212
+ not build for — the driver compiles the C runtime from the shipped sources
213
+ instead. The runtime objects are cached by source/header content hash. The
214
+ default cache is `.xbintsc/` **in the directory you run the command from** (not
215
+ necessarily next to the config file); set `xbintsc_CACHE_DIR` to put it
216
+ elsewhere. Expect that fallback build to take noticeably longer than the ones
217
+ after it.
218
+
219
+ To ignore the platform archive on purpose and compile the runtime from the
220
+ sources shipped in the package — for example after patching `runtime/`, or when
221
+ the prebuilt archive does not match the environment — set:
222
+
223
+ ```bash
224
+ xbintsc_PREFER_PREBUILT=0 npx xbintsc build src/main.ts --out build
225
+ ```
226
+
227
+ The objects are still cached in `.xbintsc/`; point `xbintsc_CACHE_DIR` at an
228
+ empty directory (or delete `.xbintsc/`) for a full rebuild. `--force` alone
229
+ does not bypass a prebuilt archive. The archive files themselves are produced
230
+ by `npm run runtime` in a source checkout; users never need to regenerate them
231
+ just to compile.
201
232
 
202
- Because the npm package ships the runtime as C sources but not as a prebuilt
203
- `core.a`, the first build compiles each runtime translation unit. Expect that
204
- build to take noticeably longer than the ones after it. `--time` shows where the
205
- time went:
233
+ `--time` shows where the time went:
206
234
 
207
235
  ```bash
208
236
  npx xbintsc build src/main.ts --out build --time
237
+ # fallback without the platform package:
209
238
  # xbintsc: timing (frontend 4ms, codegen 7ms, clang 1089ms, runtime 37770ms, link 1966ms)
210
239
  ```
211
240
 
@@ -220,7 +249,7 @@ Practical consequences:
220
249
 
221
250
  - add `.xbintsc/` to `.gitignore`;
222
251
  - keep `.xbintsc/` between CI runs (or point `xbintsc_CACHE_DIR` at a persistent
223
- directory) to avoid paying the runtime-compile cost every time;
252
+ directory) so a fallback build does not recompile the runtime every time;
224
253
  - deleting `.xbintsc/` is safe — the next build recreates it;
225
254
  - `--force` ignores the build freshness record, but cached runtime objects are
226
255
  still reused. Delete `.xbintsc/` if you want to force a full C rebuild.
@@ -368,17 +397,16 @@ jobs:
368
397
  | | npm package (`xbintsc`) | Prebuilt release archive |
369
398
  | --- | --- | --- |
370
399
  | Needs Node.js | Yes, 22+ | No |
371
- | First build | Compiles the C runtime from source | Links the prebuilt runtime |
372
- | GUI / media extensions | Not included | Included in Linux/macOS and Windows x64 archives |
400
+ | First build | Links the prebuilt runtime from the optional platform package | Links the prebuilt runtime |
401
+ | GUI / media extensions | Included on Linux/macOS and Windows x64 (the hosts the release builds them for) | Included in Linux/macOS and Windows x64 archives |
373
402
  | Installation | `npm install` + lockfile / provenance | Download, verify `.sha256`, unpack |
374
403
  | Programmatic API | Yes | No (CLI only) |
375
404
  | Cross-compiles | No — host only | No — host only |
376
- | Best for | Node projects and CI, familiar npm workflow | Machines without Node, fastest first build, GUI apps |
405
+ | Best for | Node projects and CI, familiar npm workflow | Machines without Node, GUI apps, a fully self-contained install |
377
406
 
378
- If you only need the core runtime and the `node` extension, the npm package is
379
- the most convenient option. If you need the fastest possible cold build or the
380
- GUI/media archives, use a release archive (or build from source for
381
- development).
407
+ The npm package gets the same prebuilt runtime through its optional platform
408
+ package, so the cold-build penalty only applies when that package is skipped.
409
+ Use a release archive when Node is not available.
382
410
 
383
411
  ## Things that differ from a regular Node build
384
412
 
@@ -408,10 +436,10 @@ the same file under `node_modules/xbintsc/doc/ai/`.
408
436
  | `npx xbintsc` uses an unexpected version | Run `npx --no-install xbintsc version` and `npm ls xbintsc`; pin the version in `package.json` and use `npm ci` in CI. |
409
437
  | `requires Node.js 22` / engine error | Upgrade Node; the compiler uses modern Node APIs. |
410
438
  | `No C compiler found` or `requires clang 16 or newer` | Install clang 16+ and run `npx xbintsc doctor`; set `xbintsc_CLANG` to a specific clang if needed. |
411
- | The first build takes a long time | Expected: the runtime C sources are compiled and cached. Later builds reuse `.xbintsc/`; `--time` confirms. Use a release archive if cold builds must be fast. |
439
+ | The first build takes a long time | The optional `@xbintsc/<os>-<arch>` package was skipped (or this host has no prebuilt package), so the runtime C sources are compiled and cached. Check `npm ls @xbintsc/<os>-<arch>` and reinstall without `--omit=optional`; `--time` confirms. |
412
440
  | Permission errors writing `.xbintsc/` | Set `xbintsc_CACHE_DIR` to a writable directory, or run from a writable working directory. |
413
441
  | `module 'fs' is provided by the 'node' extension` | Add `--ext node`, or `"extensions": ["node"]` in the config. |
414
- | `GUI native library not found` / `media native library not found` | The npm package does not ship `gui.a`/`gui.lib` or `media.a`/`media.lib`; use a Linux/macOS/Windows x64 release archive or build them from a source checkout. |
442
+ | `GUI native library not found` / `media native library not found` | The optional platform package that ships `gui.a`/`gui.lib` or `media.a`/`media.lib` was skipped, or this host has no prebuilt GUI/media archive (Windows arm64). Reinstall without `--omit=optional`, use a Linux/macOS/Windows x64 release archive, or build the archive from a source checkout. |
415
443
  | `require("xbintsc")` fails | The package is ESM-only; use `import` (or dynamic `import()`). |
416
444
  | Windows link errors about missing MSVC libraries | Run from a Native Tools prompt, install the VS C++ build tools, and check `npx xbintsc doctor`. |
417
445
  | `npm ci --omit=dev` then the build cannot find `xbintsc` | Install devDependencies for the build stage, or move `xbintsc` to `dependencies`. |
@@ -81,8 +81,12 @@ xbintsc-<os>-<arch>/
81
81
  runtime/ C runtime sources + prebuilt runtime/lib/<os>-<arch>/
82
82
  ```
83
83
 
84
- Windows archives omit the prebuilt `runtime/lib/`; the driver compiles the C
85
- runtime on demand with the user's clang.
84
+ Every archive carries the prebuilt runtime for its host under
85
+ `runtime/lib/<os>-<arch>/`: `core` and `ext_node` on all platforms (`.lib`
86
+ instead of `.a` with the MSVC ABI on Windows), plus `gui`/`media` where the
87
+ release builds them. The npm package receives the same archives from its
88
+ optional `@xbintsc/<os>-<arch>` dependency, so an npm install does not compile
89
+ the C runtime either.
86
90
 
87
91
  Unpack it, put `bin/` on `PATH` (or call `bin/xbintsc` directly), and install the
88
92
  toolchain for your platform below. Verify the download against the checksum
@@ -30,6 +30,12 @@ API 编写的文档可以原样运行。
30
30
  窗口;这也意味着从资源管理器启动时 stdout/stderr 无处可去,调试时可在
31
31
  `xbintsc.config.json` 里设置 `app.console: true` 保留控制台子系统。
32
32
 
33
+ 没有可用 GPU 的宿主无法运行 GUI。当 SDL 无法打开视频驱动,或无法创建
34
+ Metal/Vulkan/D3D12 设备时,引擎会打印原因并以状态码 **77** 退出——这是 autotools
35
+ 的“跳过”约定,CI 与脚本因此可以区分“这台机器没有 GUI”和“程序失败”。此后若窗口仍
36
+ 无法打开(SDL 窗口或 GPU claim 错误),`createWindow` 会抛出 JavaScript `Error`,
37
+ 而不再返回 `undefined` 句柄、让下一行以 `Cannot read properties of undefined` 失败。
38
+
33
39
  触发的事件:
34
40
  `ready`(首个呈现帧之后)、`load`、`close`、`resize`,以及输入事件
35
41
  `mousemove`、`mousedown`、`mouseup`、`click`、`wheel`、`keydown`、`keyup`。
@@ -53,10 +59,11 @@ requestAnimationFrame(frame);
53
59
  | `document` | 该窗口的 document 句柄 |
54
60
  | `navigator` | `userAgent`(以 `xbintsc` 结尾的桌面 Chrome 字符串)、`platform`、`vendor`、`language(s)`、`hardwareConcurrency`、`maxTouchPoints`、`onLine`、`vibrate()` |
55
61
  | `localStorage` | 内存中的 `getItem` / `setItem` / `removeItem` / `clear` / `key` / `length` |
56
- | `AudioContext`、`webkitAudioContext` | Web Audio 图构建器(见下) |
62
+ | `AudioContext`、`webkitAudioContext` | 带真实混音器与解码器的 Web Audio 图(见下) |
57
63
  | `Event`、`CustomEvent`、`ProgressEvent` 等 | 事件构造器 |
58
64
  | `HTMLCanvasElement`、`HTMLImageElement`、`WebGLRenderingContext`、`WebGL2RenderingContext`、`WebGLBuffer`/`WebGLTexture`/`WebGLShader`/`WebGLProgram`/`WebGLFramebuffer`/`WebGLRenderbuffer`/`WebGLUniformLocation`/`WebGLActiveInfo`/`WebGLVertexArrayObject`/`WebGLSampler`/`WebGLQuery`/`WebGLSync`/`WebGLTransformFeedback` | 真实的构造函数值。`canvas.getContext("webgl")` 与 `getContext("webgl2")` 返回 GPU 上下文(见 [WebGL](./webgl.md))。 |
59
- | `ImageBitmap`、`ImageData`、`OffscreenCanvas`、`XRWebGL*`、`Request`、`Headers`、`Response`、`ReadableStream`、`DOMParser` | `typeof` 探测返回 `"undefined"`(没有 XR/fetch/流式后端),让页面走自己的“不支持”分支,而不是调用空壳。Three.js 页面在本后端上使用真实渲染器(见[已知问题](./known-issues.md))。 |
65
+ | `ImageBitmap`、`createImageBitmap(source)` | 由已解码像素支撑的不可变位图(`<img>`、`<canvas>`、`<video>` 帧与 `ImageData` 形状);promise 立即 settle,`texImage2D` 可直接接受该对象 |
66
+ | `ImageData`、`OffscreenCanvas`、`XRWebGL*`、`Request`、`Headers`、`Response`、`ReadableStream`、`DOMParser` | `typeof` 探测返回 `"undefined"`(没有 XR/fetch/流式后端),让页面走自己的“不支持”分支,而不是调用空壳。Three.js 页面在本后端上使用真实渲染器(见[已知问题](./known-issues.md))。 |
60
67
  | `requestAnimationFrame` / `cancelAnimationFrame` | 排入窗口的动画帧列表,见[运行时集成](./runtime.md) |
61
68
  | `alert` / `confirm` / `prompt`、`matchMedia`、`getComputedStyle`、`escape` | 宿主实现(Annex B `escape` 按 UTF-16 码元编码,与 `decodeURIComponent(escape(bytes))` 一致) |
62
69
 
@@ -66,15 +73,49 @@ requestAnimationFrame(frame);
66
73
 
67
74
  ### Web Audio
68
75
 
69
- `new AudioContext()` 会构建音频图,但**不做混音也不渲染音频**:背后没有后端。已实现的是
70
- 页面运行与自检所需的接口 —— `createGain` / `createOscillator` / `createBufferSource` /
71
- `createBiquadFilter` / `createDynamicsCompressor` / `createBuffer`(真实的
72
- `Float32Array` 声道)/ `decodeAudioData`(以空缓冲区兑现)/ `resume` / `suspend` /
73
- `close`,`AudioParam` 的 `value` 与 `setValueAtTime` / `linearRampToValueAtTime` /
76
+ `new AudioContext()` 会构建**真正参与混音的音频图**:`runtime/ext_gui/audio_mixer.cpp`
77
+ 以 48 kHz 立体声 float、128 帧为一个渲染量子进行混音,每个节点对多路输入求和;
78
+ 首次 `start()`/`resume()` 会尽力打开默认 SDL 播放设备(无头环境下保持静音但仍在渲染)。
79
+ 音频在 SDL 音频线程上基于原生状态渲染,页面无须自行驱动,音频线程也不会触碰任何运行时值。
80
+
81
+ 已实现的节点:`createGain`、`createOscillator`(sine、square、sawtooth、triangle)、
82
+ `createBufferSource`(buffer、loop、loopStart/loopEnd、playbackRate/detune)、
83
+ `createBiquadFilter`(lowpass、highpass、bandpass、lowshelf、highshelf、peaking、notch、allpass)、
84
+ `createDynamicsCompressor`、`createStereoPanner`、`createConstantSource` 与
85
+ `createDelay(maxDelayTime)`。`connect` 返回目标节点,因此可链式连接
86
+ (`src.connect(gain).connect(ctx.destination)`);`disconnect()` / `disconnect(target)`
87
+ 会更新原生图;`start(when, offset, duration)` / `stop(when)` 按图的时钟生效。
88
+ 列表之外的节点(`createAnalyser`、`createConvolver`、`createWaveShaper`、
89
+ `createChannelSplitter`、`createPeriodicWave` 等)不提供,其方法就是缺失的。
90
+
91
+ 每个 `AudioParam` 都有实时 `value`,以及 `setValueAtTime` / `linearRampToValueAtTime` /
74
92
  `exponentialRampToValueAtTime` / `setTargetAtTime` / `cancelScheduledValues` /
75
- `cancelAndHoldAtTime`,节点 `connect`(返回目标节点,因此可链式连接)/ `disconnect` /
76
- `start` / `stop`。`sampleRate` 为 48000、`state` 为 `"running"`,`currentTime` 仅随
77
- 事件循环推进。
93
+ `cancelAndHoldAtTime`。自动化时间线**逐采样**求值,因此页面空闲时斜坡仍会继续推进;
94
+ `currentTime` 随渲染量子前进。
95
+
96
+ `createBuffer(channels, length, sampleRate)` 返回的 AudioBuffer 的
97
+ `getChannelData(i)` 是真正的 `Float32Array`,可以用代码逐样本填充。
98
+ `decodeAudioData(bytes)` 返回解码后的 AudioBuffer Promise:WAV(PCM 8/16/24/32 位、
99
+ IEEE float 32/64、A-law 与 µ-law)由引擎自身解码;MP3、AAC/M4A、Vorbis、Opus 与 FLAC
100
+ 需要可选的 `media` 扩展(`--ext gui,media`),以其中的 FFmpeg 解码器作为回退。
101
+ `bytes` 可以是 ArrayBuffer、类型化数组、Node `Buffer`,或 `fs.readFileSync`
102
+ 返回的原始字节字符串(本运行时没有专门的二进制类型,而该字符串的存储正是文件字节)。
103
+ 解码结果会重采样到上下文的 48 kHz,因此 `buffer.sampleRate` 与
104
+ `context.sampleRate` 一致;若没有可用的解码器,Promise 会以 `EncodingError` 拒绝。
105
+
106
+ `resume()` / `suspend()` / `close()` 控制设备与 `state` 属性;`sampleRate` 为 48000,
107
+ 与媒体解码器一致。
108
+
109
+ 测试与诊断可以创建**离线**上下文同步渲染:
110
+
111
+ ```ts
112
+ const ctx = new AudioContext({ __offline: true });
113
+ // … 构建音频图并启动音源 …
114
+ const samples = ctx.__render(480); // 交错立体声 Float32Array
115
+ ```
116
+
117
+ 这个私有钩子不会打开设备,也不属于 Web Audio API;`tests/e2e/gui-audio.test.ts`
118
+ 用它来固定混音数学。
78
119
 
79
120
  输入处理器接收单个负载对象(生命周期处理器不接收任何参数):
80
121
 
@@ -52,10 +52,15 @@
52
52
  `vendor/ffmpeg-build-msvc/dist`,而不是执行 `make install`。
53
53
  - CI 在组装发布归档之前构建 `gui.a`/`gui.lib` 与 `media.a`/`media.lib`,因此它们
54
54
  会随 `runtime/lib/<slug>/` 一起发布(发布 tarball 会复制整个 `runtime/` 树)。
55
- 归档在 Linux(Xvfb 下,使用 lavapipe 软件 Vulkan 驱动)与 macOS 上构建并运行
55
+ 同一批目录还会打进可选的 `@xbintsc/<slug>` npm 包,因此发布覆盖的宿主平台从
56
+ npm 安装后也能使用 `--ext gui`/`--ext media`。归档在 Linux(Xvfb 下,使用
57
+ lavapipe 软件 Vulkan 驱动)与 macOS 上构建并运行
56
58
  示例;Windows x64 也会构建两个归档并链接一个 `gui,media` 程序,因此 MSVC
57
59
  构建在 CI 中得到验证,只是*运行*示例仍为试验性(托管 runner 没有 GPU/Vulkan
58
- 驱动)。Windows arm64 仍跳过两个归档(FFmpeg 的 MSVC arm64 构建尚未验证)。
60
+ 驱动)。macOS 的运行同样是试验性的:Intel runner 的虚拟 GPU 缺少
61
+ `MTLGPUFamilyMac2`,引擎会以 **77**(“此机器无法运行 GUI”)退出,任务记录为跳过,
62
+ 而不是去编译一套无法呈现的测试。Windows arm64 仍跳过两个归档(FFmpeg 的
63
+ MSVC arm64 构建尚未验证)。
59
64
  - Windows CI 通过 `.github/actions/vs-toolchain` →
60
65
  `scripts/setup-vs-toolchain.ps1` 使用与本地构建相同的 Visual Studio
61
66
  `vcvarsall` 环境和自带的 LLVM(不再单独安装 Chocolatey LLVM)。媒体构建时该
@@ -14,7 +14,9 @@ doctype 跳过,实体解码(命名 + 十进制/十六进制),空元素
14
14
 
15
15
  **CSS 解析器**(`runtime/ext_gui/css.{h,cpp}`):会剥离注释;`@media` 块递归解析
16
16
  (嵌套查询用 `and` 合并,逗号列表会分配到内层查询),其他 at-rule 跳过。规则支持
17
- 多选择器与声明。选择器:类型、`.class`、`#id`、属性
17
+ 多选择器与声明;选择器列表可以跨任意多行书写(换行就是普通空白,换行后的
18
+ 组合器仍按组合器处理),引号内的属性值即使包含逗号、方括号或圆括号也不会
19
+ 拆开列表。选择器:类型、`.class`、`#id`、属性
18
20
  (`=`、`~=`、`|=`、`^=`、`$=`、`*=`)、四种组合器(后代、子、相邻兄弟与
19
21
  通用兄弟)、伪类 `:first-child`、`:last-child`、`:only-child`、`:empty`、
20
22
  `:root`、`:not(...)`、`:nth-child(an+b)`、`:disabled`、`:checked`、有状态的
@@ -91,6 +91,9 @@ Windows 已不再特殊:`media.lib` 是用 clang-cl 为 MSVC ABI 编译的 FFm
91
91
  `media.a`/`media.lib` 只依赖 FFmpeg。
92
92
  - **线程。** 引擎是单线程且非线程感知,因此所有解码都在主线程的
93
93
  `xt_gui_media_tick` 内完成——没有解码线程,也没有跨线程 GC 暴露。
94
+ - **`decodeAudioData`。** 同一套 FFmpeg 还会为 `AudioContext.decodeAudioData`
95
+ 解码内存中的音频文件(`runtime/ext_media/decode_audio.cpp`,经媒体表分发);
96
+ WAV 由 GUI 引擎自身处理(`audio_decode.cpp`),因此只有压缩格式需要该扩展。
94
97
  - **DOM API。** 元素句柄直接暴露媒体接口(见
95
98
  `runtime/ext_gui/dom_api_media.cpp` 与 `dom_api_proto.cpp` 中的原型):
96
99
  `play()` / `pause()` / `load()`,以及 `paused` / `ended` / `duration` /