@luma.gl/shadertools 9.3.5 → 9.4.0-alpha.1

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 (113) hide show
  1. package/dist/dist.dev.js +6555 -2373
  2. package/dist/dist.min.js +2984 -237
  3. package/dist/index.cjs +4356 -268
  4. package/dist/index.cjs.map +4 -4
  5. package/dist/index.d.ts +13 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/preprocessor/preprocessor.d.ts +11 -1
  10. package/dist/lib/preprocessor/preprocessor.d.ts.map +1 -1
  11. package/dist/lib/preprocessor/preprocessor.js +47 -2
  12. package/dist/lib/preprocessor/preprocessor.js.map +1 -1
  13. package/dist/lib/shader-assembler.d.ts +10 -10
  14. package/dist/lib/shader-assembler.d.ts.map +1 -1
  15. package/dist/lib/shader-assembler.js +36 -20
  16. package/dist/lib/shader-assembler.js.map +1 -1
  17. package/dist/lib/shader-assembly/assemble-shaders.d.ts +28 -7
  18. package/dist/lib/shader-assembly/assemble-shaders.d.ts.map +1 -1
  19. package/dist/lib/shader-assembly/assemble-shaders.js +133 -15
  20. package/dist/lib/shader-assembly/assemble-shaders.js.map +1 -1
  21. package/dist/lib/shader-assembly/platform-info.d.ts +2 -0
  22. package/dist/lib/shader-assembly/platform-info.d.ts.map +1 -1
  23. package/dist/lib/shader-assembly/shader-hooks.d.ts +1 -1
  24. package/dist/lib/shader-assembly/shader-hooks.d.ts.map +1 -1
  25. package/dist/lib/shader-assembly/shader-hooks.js +6 -3
  26. package/dist/lib/shader-assembly/shader-hooks.js.map +1 -1
  27. package/dist/lib/shader-assembly/shader-injections.d.ts +4 -1
  28. package/dist/lib/shader-assembly/shader-injections.d.ts.map +1 -1
  29. package/dist/lib/shader-assembly/shader-injections.js +68 -11
  30. package/dist/lib/shader-assembly/shader-injections.js.map +1 -1
  31. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts +15 -0
  32. package/dist/lib/shader-assembly/shader-plugin-varyings.d.ts.map +1 -0
  33. package/dist/lib/shader-assembly/shader-plugin-varyings.js +412 -0
  34. package/dist/lib/shader-assembly/shader-plugin-varyings.js.map +1 -0
  35. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts +12 -0
  36. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.d.ts.map +1 -0
  37. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js +237 -0
  38. package/dist/lib/shader-assembly/shader-plugin-vertex-inputs.js.map +1 -0
  39. package/dist/lib/shader-module/shader-module.d.ts +3 -0
  40. package/dist/lib/shader-module/shader-module.d.ts.map +1 -1
  41. package/dist/lib/shader-module/shader-module.js.map +1 -1
  42. package/dist/lib/shader-module/shader-pass-pipeline.d.ts +14 -0
  43. package/dist/lib/shader-module/shader-pass-pipeline.d.ts.map +1 -0
  44. package/dist/lib/shader-module/shader-pass-pipeline.js +5 -0
  45. package/dist/lib/shader-module/shader-pass-pipeline.js.map +1 -0
  46. package/dist/lib/shader-module/shader-pass.d.ts +21 -4
  47. package/dist/lib/shader-module/shader-pass.d.ts.map +1 -1
  48. package/dist/lib/shader-plugin.d.ts +68 -0
  49. package/dist/lib/shader-plugin.d.ts.map +1 -0
  50. package/dist/lib/shader-plugin.js +98 -0
  51. package/dist/lib/shader-plugin.js.map +1 -0
  52. package/dist/lib/utils/assert.js +1 -1
  53. package/dist/lib/utils/assert.js.map +1 -1
  54. package/dist/modules/color/float-colors.d.ts +111 -5
  55. package/dist/modules/color/float-colors.d.ts.map +1 -1
  56. package/dist/modules/color/float-colors.js +200 -34
  57. package/dist/modules/color/float-colors.js.map +1 -1
  58. package/dist/modules/engine/clip/clip.d.ts +12 -0
  59. package/dist/modules/engine/clip/clip.d.ts.map +1 -0
  60. package/dist/modules/engine/clip/clip.js +129 -0
  61. package/dist/modules/engine/clip/clip.js.map +1 -0
  62. package/dist/modules/engine/filter/filter.d.ts +12 -0
  63. package/dist/modules/engine/filter/filter.d.ts.map +1 -0
  64. package/dist/modules/engine/filter/filter.js +88 -0
  65. package/dist/modules/engine/filter/filter.js.map +1 -0
  66. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts +3 -0
  67. package/dist/modules/geospatial/dggs/dggs-wgsl.d.ts.map +1 -0
  68. package/dist/modules/geospatial/dggs/dggs-wgsl.js +1892 -0
  69. package/dist/modules/geospatial/dggs/dggs-wgsl.js.map +1 -0
  70. package/dist/modules/geospatial/dggs/dggs.d.ts +6 -0
  71. package/dist/modules/geospatial/dggs/dggs.d.ts.map +1 -0
  72. package/dist/modules/geospatial/dggs/dggs.js +10 -0
  73. package/dist/modules/geospatial/dggs/dggs.js.map +1 -0
  74. package/dist/modules/lighting/water-material/water-material.d.ts +28 -0
  75. package/dist/modules/lighting/water-material/water-material.d.ts.map +1 -0
  76. package/dist/modules/lighting/water-material/water-material.js +179 -0
  77. package/dist/modules/lighting/water-material/water-material.js.map +1 -0
  78. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts +3 -0
  79. package/dist/modules/lighting/water-material/water-shaders-glsl.d.ts.map +1 -0
  80. package/dist/modules/lighting/water-material/water-shaders-glsl.js +232 -0
  81. package/dist/modules/lighting/water-material/water-shaders-glsl.js.map +1 -0
  82. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts +2 -0
  83. package/dist/modules/lighting/water-material/water-shaders-wgsl.d.ts.map +1 -0
  84. package/dist/modules/lighting/water-material/water-shaders-wgsl.js +230 -0
  85. package/dist/modules/lighting/water-material/water-shaders-wgsl.js.map +1 -0
  86. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts +2 -1
  87. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.d.ts.map +1 -1
  88. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js +268 -0
  89. package/dist/modules/math/fp64/fp64-arithmetic-wgsl.js.map +1 -1
  90. package/package.json +2 -2
  91. package/src/index.ts +50 -3
  92. package/src/lib/preprocessor/preprocessor.ts +68 -3
  93. package/src/lib/shader-assembler.ts +49 -20
  94. package/src/lib/shader-assembly/assemble-shaders.ts +242 -30
  95. package/src/lib/shader-assembly/platform-info.ts +2 -0
  96. package/src/lib/shader-assembly/shader-hooks.ts +7 -3
  97. package/src/lib/shader-assembly/shader-injections.ts +96 -11
  98. package/src/lib/shader-assembly/shader-plugin-varyings.ts +524 -0
  99. package/src/lib/shader-assembly/shader-plugin-vertex-inputs.ts +279 -0
  100. package/src/lib/shader-module/shader-module.ts +3 -0
  101. package/src/lib/shader-module/shader-pass-pipeline.ts +19 -0
  102. package/src/lib/shader-module/shader-pass.ts +29 -4
  103. package/src/lib/shader-plugin.ts +214 -0
  104. package/src/lib/utils/assert.ts +1 -1
  105. package/src/modules/color/float-colors.ts +272 -37
  106. package/src/modules/engine/clip/clip.ts +149 -0
  107. package/src/modules/engine/filter/filter.ts +107 -0
  108. package/src/modules/geospatial/dggs/dggs-wgsl.ts +1892 -0
  109. package/src/modules/geospatial/dggs/dggs.ts +12 -0
  110. package/src/modules/lighting/water-material/water-material.ts +234 -0
  111. package/src/modules/lighting/water-material/water-shaders-glsl.ts +233 -0
  112. package/src/modules/lighting/water-material/water-shaders-wgsl.ts +230 -0
  113. package/src/modules/math/fp64/fp64-arithmetic-wgsl.ts +268 -0
package/src/index.ts CHANGED
@@ -14,13 +14,33 @@ export type {ShaderBindingDebugRow} from './lib/shader-assembly/wgsl-binding-deb
14
14
  // ShaderModules
15
15
 
16
16
  export type {ShaderModule} from './lib/shader-module/shader-module';
17
- export type {ShaderPass} from './lib/shader-module/shader-pass';
17
+ export type {
18
+ ResolvedShaderPlugins,
19
+ ResolvedShaderPluginVarying,
20
+ ShaderPlugin,
21
+ ShaderPluginInjection,
22
+ ShaderPluginInjectionTarget,
23
+ ShaderPluginVarying,
24
+ ShaderPluginVaryingInterpolation,
25
+ ShaderPluginVariant
26
+ } from './lib/shader-plugin';
27
+ export type {
28
+ ShaderPass,
29
+ ShaderPassInputSource,
30
+ ShaderPassRenderTarget,
31
+ ShaderSubPass
32
+ } from './lib/shader-module/shader-pass';
33
+ export type {
34
+ ShaderPassPipeline,
35
+ ShaderPassPipelineStep
36
+ } from './lib/shader-module/shader-pass-pipeline';
18
37
  export type {ShaderModuleUniformValue, UniformTypes} from './lib/utils/uniform-types';
19
38
 
20
39
  export {initializeShaderModule, initializeShaderModules} from './lib/shader-module/shader-module';
21
40
  export {getShaderModuleUniforms} from './lib/shader-module/shader-module';
22
41
  export {getShaderModuleDependencies} from './lib/shader-module/shader-module-dependencies';
23
42
  export {checkShaderModuleDeprecations} from './lib/shader-module/shader-module';
43
+ export {mergeShaderPluginModules, resolveShaderPlugins} from './lib/shader-plugin';
24
44
  export type {
25
45
  GLSLUniformBlockInfo,
26
46
  ShaderModuleUniformLayoutStage,
@@ -81,8 +101,26 @@ export {random} from './modules/math/random/random';
81
101
 
82
102
  export {fp32} from './modules/math/fp32/fp32';
83
103
  export {fp64, fp64arithmetic} from './modules/math/fp64/fp64';
84
- export type {FloatColorsProps, FloatColorsUniforms} from './modules/color/float-colors';
85
- export {floatColors} from './modules/color/float-colors';
104
+ export {dggs} from './modules/geospatial/dggs/dggs';
105
+ export type {
106
+ ColorsProps,
107
+ ColorsUniforms,
108
+ FloatColorsProps,
109
+ FloatColorsUniforms,
110
+ StorageColorFormat,
111
+ StorageColorFormatValue,
112
+ StorageColorsBindings,
113
+ StorageColorsProps,
114
+ StorageColorsUniforms
115
+ } from './modules/color/float-colors';
116
+ export {
117
+ colors,
118
+ floatColors,
119
+ STORAGE_COLOR_DEFAULT_BYTE_STRIDES,
120
+ STORAGE_COLOR_FORMAT,
121
+ STORAGE_COLOR_FORMAT_BYTE_LENGTHS,
122
+ storageColors
123
+ } from './modules/color/float-colors';
86
124
 
87
125
  // engine shader modules
88
126
 
@@ -91,6 +129,10 @@ export {floatColors} from './modules/color/float-colors';
91
129
  // export {projection} from './modules/engine/project/project';
92
130
  export type {PickingProps, PickingUniforms} from './modules/engine/picking/picking';
93
131
  export {picking} from './modules/engine/picking/picking';
132
+ export type {FilterShaderPluginProps} from './modules/engine/filter/filter';
133
+ export {filterShaderPlugin} from './modules/engine/filter/filter';
134
+ export type {ClipShaderPluginProps} from './modules/engine/clip/clip';
135
+ export {clipShaderPlugin} from './modules/engine/clip/clip';
94
136
  export {skin} from './modules/engine/skin/skin';
95
137
 
96
138
  // lighting
@@ -114,6 +156,11 @@ export type {GouraudMaterialProps} from './modules/lighting/gouraud-material/gou
114
156
  export {gouraudMaterial} from './modules/lighting/gouraud-material/gouraud-material';
115
157
  export type {PhongMaterialProps} from './modules/lighting/phong-material/phong-material';
116
158
  export {phongMaterial} from './modules/lighting/phong-material/phong-material';
159
+ export type {
160
+ WaterMaterialProps,
161
+ WaterMaterialUniforms
162
+ } from './modules/lighting/water-material/water-material';
163
+ export {waterMaterial} from './modules/lighting/water-material/water-material';
117
164
  export type {
118
165
  PBRMaterialBindings,
119
166
  PBRMaterialProps,
@@ -3,6 +3,7 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  const DEFINE_NAME_PATTERN = '([a-zA-Z_][a-zA-Z0-9_]*)';
6
+ const IF_REGEXP = /^\s*\#\s*if\s+(.+?)\s*(?:\/\/.*)?$/;
6
7
  const IFDEF_REGEXP = new RegExp(`^\\s*\\#\\s*ifdef\\s*${DEFINE_NAME_PATTERN}\\s*$`);
7
8
  const IFNDEF_REGEXP = new RegExp(`^\\s*\\#\\s*ifndef\\s*${DEFINE_NAME_PATTERN}\\s*(?:\\/\\/.*)?$`);
8
9
  const ELSE_REGEXP = /^\s*\#\s*else\s*(?:\/\/.*)?$/;
@@ -12,10 +13,20 @@ const IFDEF_WITH_COMMENT_REGEXP = new RegExp(
12
13
  );
13
14
  const ENDIF_WITH_COMMENT_REGEXP = /^\s*\#\s*endif\s*(?:\/\/.*)?$/;
14
15
 
16
+ /** Options for the luma.gl shader source preprocessor. */
15
17
  export type PreprocessorOptions = {
16
- defines?: Record<string, boolean>;
18
+ /** Boolean or numeric values used by `#if`, `#ifdef`, and `#ifndef` conditionals. */
19
+ defines?: Record<string, boolean | number>;
17
20
  };
18
21
 
22
+ /**
23
+ * Removes inactive conditional branches from shader source.
24
+ * Supports `#ifdef`, `#ifndef`, and simple `#if` expressions using a define name,
25
+ * `!NAME`, `defined(NAME)`, `!defined(NAME)`, or a boolean or numeric literal.
26
+ * @param source Shader source containing luma.gl-supported conditional directives.
27
+ * @param options Defines used while evaluating conditional directives.
28
+ * @returns Shader source with inactive branches removed.
29
+ */
19
30
  export function preprocess(source: string, options?: PreprocessorOptions): string {
20
31
  const lines = source.split('\n');
21
32
  const output: string[] = [];
@@ -28,12 +39,21 @@ export function preprocess(source: string, options?: PreprocessorOptions): strin
28
39
  let conditional = true;
29
40
 
30
41
  for (const line of lines) {
42
+ const matchIfExpression = line.match(IF_REGEXP);
31
43
  const matchIf = line.match(IFDEF_WITH_COMMENT_REGEXP) || line.match(IFDEF_REGEXP);
32
44
  const matchIfNot = line.match(IFNDEF_REGEXP);
33
45
  const matchElse = line.match(ELSE_REGEXP);
34
46
  const matchEnd = line.match(ENDIF_WITH_COMMENT_REGEXP) || line.match(ENDIF_REGEXP);
35
47
 
36
- if (matchIf || matchIfNot) {
48
+ if (matchIfExpression) {
49
+ const branchTaken: boolean = evaluateIfExpression(
50
+ matchIfExpression[1],
51
+ options?.defines || {}
52
+ );
53
+ const active: boolean = conditional && branchTaken;
54
+ conditionalStack.push({parentActive: conditional, branchTaken, active});
55
+ conditional = active;
56
+ } else if (matchIf || matchIfNot) {
37
57
  const defineName = (matchIf || matchIfNot)?.[1];
38
58
  const defineValue: boolean = Boolean(options?.defines?.[defineName!]);
39
59
  const branchTaken: boolean = matchIf ? defineValue : !defineValue;
@@ -43,7 +63,7 @@ export function preprocess(source: string, options?: PreprocessorOptions): strin
43
63
  } else if (matchElse) {
44
64
  const currentConditional = conditionalStack[conditionalStack.length - 1];
45
65
  if (!currentConditional) {
46
- throw new Error('Encountered #else without matching #ifdef or #ifndef');
66
+ throw new Error('Encountered #else without matching #if, #ifdef or #ifndef');
47
67
  }
48
68
  currentConditional.active =
49
69
  currentConditional.parentActive && !currentConditional.branchTaken;
@@ -65,3 +85,48 @@ export function preprocess(source: string, options?: PreprocessorOptions): strin
65
85
 
66
86
  return output.join('\n');
67
87
  }
88
+
89
+ function evaluateIfExpression(
90
+ expression: string,
91
+ defines: Record<string, boolean | number>
92
+ ): boolean {
93
+ const trimmedExpression = expression.trim();
94
+
95
+ if (/^[+-]?\d+(?:\.\d+)?$/.test(trimmedExpression)) {
96
+ return Number(trimmedExpression) !== 0;
97
+ }
98
+
99
+ if (trimmedExpression === 'true') {
100
+ return true;
101
+ }
102
+
103
+ if (trimmedExpression === 'false') {
104
+ return false;
105
+ }
106
+
107
+ const negatedDefineMatch = trimmedExpression.match(new RegExp(`^!\\s*${DEFINE_NAME_PATTERN}$`));
108
+ if (negatedDefineMatch) {
109
+ return !Boolean(defines[negatedDefineMatch[1]]);
110
+ }
111
+
112
+ const defineMatch = trimmedExpression.match(new RegExp(`^${DEFINE_NAME_PATTERN}$`));
113
+ if (defineMatch) {
114
+ return Boolean(defines[defineMatch[1]]);
115
+ }
116
+
117
+ const definedMatch = trimmedExpression.match(
118
+ new RegExp(`^defined\\s*\\(\\s*${DEFINE_NAME_PATTERN}\\s*\\)$`)
119
+ );
120
+ if (definedMatch) {
121
+ return defines[definedMatch[1]] !== undefined;
122
+ }
123
+
124
+ const negatedDefinedMatch = trimmedExpression.match(
125
+ new RegExp(`^!\\s*defined\\s*\\(\\s*${DEFINE_NAME_PATTERN}\\s*\\)$`)
126
+ );
127
+ if (negatedDefinedMatch) {
128
+ return defines[negatedDefinedMatch[1]] === undefined;
129
+ }
130
+
131
+ throw new Error(`Unsupported #if expression "${expression}"`);
132
+ }
@@ -32,7 +32,7 @@ export class ShaderAssembler {
32
32
 
33
33
  /**
34
34
  * A default shader assembler instance - the natural place to register default modules and hooks
35
- * @returns
35
+ * @returns Shared default shader assembler.
36
36
  */
37
37
  static getDefaultShaderAssembler(): ShaderAssembler {
38
38
  ShaderAssembler.defaultShaderAssembler =
@@ -41,7 +41,8 @@ export class ShaderAssembler {
41
41
  }
42
42
 
43
43
  /**
44
- * Add a default module that does not have to be provided with every call to assembleShaders()
44
+ * Add a default module that does not have to be provided with every assembly call.
45
+ * @param module Shader module to include in later assembly calls.
45
46
  */
46
47
  addDefaultModule(module: ShaderModule): void {
47
48
  if (
@@ -55,6 +56,7 @@ export class ShaderAssembler {
55
56
 
56
57
  /**
57
58
  * Remove a default module
59
+ * @param module Shader module to remove from later assembly calls.
58
60
  */
59
61
  removeDefaultModule(module: ShaderModule): void {
60
62
  const moduleName = typeof module === 'string' ? module : module.name;
@@ -63,8 +65,8 @@ export class ShaderAssembler {
63
65
 
64
66
  /**
65
67
  * Register a shader hook
66
- * @param hook
67
- * @param opts
68
+ * @param hook Stage-prefixed hook signature, such as `vs:OFFSET_POSITION(inout vec4 position)`.
69
+ * @param opts Optional hook metadata such as always-on header and footer source.
68
70
  */
69
71
  addShaderHook(hook: string, opts?: any): void {
70
72
  if (opts) {
@@ -75,9 +77,8 @@ export class ShaderAssembler {
75
77
 
76
78
  /**
77
79
  * Assemble a WGSL unified shader
78
- * @param platformInfo
79
- * @param props
80
- * @returns
80
+ * @param props WGSL source, platform information, shader modules, defines, and injections.
81
+ * @returns Assembled WGSL source, resolved modules, uniforms, and binding debug metadata.
81
82
  */
82
83
  assembleWGSLShader(props: AssembleShaderProps): {
83
84
  source: string;
@@ -88,24 +89,29 @@ export class ShaderAssembler {
88
89
  } {
89
90
  const modules = this._getModuleList(props.modules); // Combine with default modules
90
91
  const hookFunctions = this._hookFunctions; // TODO - combine with default hook functions
91
- const {source, getUniforms, bindingAssignments} = assembleWGSLShader({
92
+ const defines = getShaderPreprocessorDefines(props, modules);
93
+ const preprocessedApplicationSource =
94
+ props.platformInfo.shaderLanguage === 'wgsl' && props.source
95
+ ? preprocess(props.source, {defines})
96
+ : props.source;
97
+ const {
98
+ source: assembledSource,
99
+ getUniforms,
100
+ bindingAssignments
101
+ } = assembleWGSLShader({
92
102
  ...props,
93
103
  // @ts-expect-error
94
- source: props.source,
104
+ source: preprocessedApplicationSource,
105
+ defines,
95
106
  _bindingRegistry: this._wgslBindingRegistry,
96
107
  modules,
97
108
  hookFunctions
98
109
  });
99
- const defines = {
100
- ...modules.reduce<Record<string, boolean>>((accumulator, module) => {
101
- Object.assign(accumulator, module.defines);
102
- return accumulator;
103
- }, {}),
104
- ...props.defines
105
- };
106
110
  // WGSL does not have built-in preprocessing support (just compile time constants)
107
111
  const preprocessedSource =
108
- props.platformInfo.shaderLanguage === 'wgsl' ? preprocess(source, {defines}) : source;
112
+ props.platformInfo.shaderLanguage === 'wgsl'
113
+ ? preprocess(assembledSource, {defines})
114
+ : assembledSource;
109
115
  return {
110
116
  source: preprocessedSource,
111
117
  getUniforms,
@@ -117,9 +123,8 @@ export class ShaderAssembler {
117
123
 
118
124
  /**
119
125
  * Assemble a pair of shaders into a single shader program
120
- * @param platformInfo
121
- * @param props
122
- * @returns
126
+ * @param props GLSL vertex and fragment source, platform information, shader modules, defines, and injections.
127
+ * @returns Assembled GLSL source, resolved modules, and combined uniform getter.
123
128
  */
124
129
  assembleGLSLShaderPair(props: AssembleShaderProps): {
125
130
  vs: string;
@@ -172,3 +177,27 @@ export class ShaderAssembler {
172
177
  return modules;
173
178
  }
174
179
  }
180
+
181
+ function getShaderPreprocessorDefines(
182
+ props: AssembleShaderProps,
183
+ modules: ShaderModule[]
184
+ ): Record<string, boolean | number> {
185
+ return {
186
+ ...getPlatformPreprocessorDefines(props.platformInfo),
187
+ ...modules.reduce<Record<string, boolean | number>>((accumulator, module) => {
188
+ Object.assign(accumulator, module.defines);
189
+ return accumulator;
190
+ }, {}),
191
+ ...props.defines
192
+ };
193
+ }
194
+
195
+ function getPlatformPreprocessorDefines(
196
+ platformInfo: AssembleShaderProps['platformInfo']
197
+ ): Record<string, boolean> {
198
+ const limits = platformInfo.limits || {};
199
+ return {
200
+ LUMA_SUPPORTS_VERTEX_STORAGE_BUFFERS:
201
+ platformInfo.type === 'webgpu' && (limits['maxStorageBuffersInVertexStage'] || 0) > 0
202
+ };
203
+ }