miniray 0.1.3 → 0.2.0

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.
package/README.md CHANGED
@@ -60,7 +60,7 @@ console.log(result.code);
60
60
 
61
61
  ### `initialize(options)`
62
62
 
63
- Initialize the WASM module. Must be called before `minify()`.
63
+ Initialize the WASM module. Must be called before `minify()` or `reflect()`.
64
64
 
65
65
  ```typescript
66
66
  interface InitializeOptions {
@@ -95,6 +95,81 @@ interface MinifyResult {
95
95
  }
96
96
  ```
97
97
 
98
+ ### `reflect(source)`
99
+
100
+ Extract binding information, struct layouts, and entry points from WGSL source.
101
+
102
+ ```typescript
103
+ interface ReflectResult {
104
+ bindings: BindingInfo[];
105
+ structs: Record<string, StructLayout>;
106
+ entryPoints: EntryPointInfo[];
107
+ errors: string[];
108
+ }
109
+
110
+ interface BindingInfo {
111
+ group: number;
112
+ binding: number;
113
+ name: string;
114
+ addressSpace: string; // "uniform", "storage", "handle"
115
+ accessMode?: string; // "read", "write", "read_write" (for storage)
116
+ type: string;
117
+ layout: StructLayout | null; // null for textures/samplers
118
+ }
119
+
120
+ interface StructLayout {
121
+ size: number;
122
+ alignment: number;
123
+ fields: FieldInfo[];
124
+ }
125
+
126
+ interface FieldInfo {
127
+ name: string;
128
+ type: string;
129
+ offset: number;
130
+ size: number;
131
+ alignment: number;
132
+ layout?: StructLayout; // for nested structs
133
+ }
134
+
135
+ interface EntryPointInfo {
136
+ name: string;
137
+ stage: string; // "vertex", "fragment", "compute"
138
+ workgroupSize: number[] | null; // [x, y, z] for compute, null otherwise
139
+ }
140
+ ```
141
+
142
+ **Example:**
143
+
144
+ ```javascript
145
+ const result = reflect(`
146
+ struct Uniforms { time: f32, resolution: vec2<u32> }
147
+ @group(0) @binding(0) var<uniform> u: Uniforms;
148
+ @compute @workgroup_size(8, 8) fn main() {}
149
+ `);
150
+
151
+ console.log(result.bindings[0]);
152
+ // {
153
+ // group: 0, binding: 0, name: "u",
154
+ // addressSpace: "uniform", type: "Uniforms",
155
+ // layout: {
156
+ // size: 16, alignment: 8,
157
+ // fields: [
158
+ // { name: "time", type: "f32", offset: 0, size: 4, alignment: 4 },
159
+ // { name: "resolution", type: "vec2<u32>", offset: 8, size: 8, alignment: 8 }
160
+ // ]
161
+ // }
162
+ // }
163
+
164
+ console.log(result.entryPoints[0]);
165
+ // { name: "main", stage: "compute", workgroupSize: [8, 8, 1] }
166
+ ```
167
+
168
+ Memory layouts follow the WGSL specification:
169
+ - `vec3` has alignment=16 but size=12
170
+ - Struct members are aligned to their natural alignment
171
+ - Struct size is rounded up to struct alignment
172
+
98
173
  ### `isInitialized()`
99
174
 
100
175
  Returns `true` if the WASM module is initialized.
package/esm/node.mjs CHANGED
@@ -40,8 +40,15 @@ export async function initialize(options) {
40
40
  const wasmModule = options.wasmModule;
41
41
 
42
42
  // Default to miniray.wasm in the package directory
43
+ // Use require.resolve to find files within the package, which works
44
+ // regardless of bundling or working directory
43
45
  if (!wasmURL && !wasmModule) {
44
- wasmURL = path.join(__dirname, '..', 'miniray.wasm');
46
+ try {
47
+ wasmURL = require.resolve('miniray/miniray.wasm');
48
+ } catch {
49
+ // Fallback to relative path for local development
50
+ wasmURL = path.join(__dirname, '..', 'miniray.wasm');
51
+ }
45
52
  }
46
53
 
47
54
  _initPromise = _doInitialize(wasmURL, wasmModule);
@@ -57,7 +64,16 @@ export async function initialize(options) {
57
64
 
58
65
  async function _doInitialize(wasmURL, wasmModule) {
59
66
  // Load wasm_exec.js - this defines Go globally
60
- const wasmExecPath = path.join(__dirname, '..', 'wasm_exec.js');
67
+ // Use require.resolve to find files within the package, which works
68
+ // regardless of bundling or working directory
69
+ let wasmExecPath;
70
+ try {
71
+ wasmExecPath = require.resolve('miniray/wasm_exec.js');
72
+ } catch {
73
+ // Fallback to relative path for local development
74
+ wasmExecPath = path.join(__dirname, '..', 'wasm_exec.js');
75
+ }
76
+
61
77
  if (!fs.existsSync(wasmExecPath)) {
62
78
  throw new Error(`wasm_exec.js not found at ${wasmExecPath}`);
63
79
  }
@@ -122,6 +138,23 @@ export function minify(source, options) {
122
138
  return globalThis.__miniray.minify(source, options || {});
123
139
  }
124
140
 
141
+ /**
142
+ * Reflect WGSL source to extract binding and struct information.
143
+ * @param {string} source - WGSL source code
144
+ * @returns {Object} Reflection result with bindings, structs, entryPoints, and errors
145
+ */
146
+ export function reflect(source) {
147
+ if (!_initialized) {
148
+ throw new Error('miniray not initialized. Call initialize() first.');
149
+ }
150
+
151
+ if (typeof source !== 'string') {
152
+ throw new Error('source must be a string');
153
+ }
154
+
155
+ return globalThis.__miniray.reflect(source);
156
+ }
157
+
125
158
  /**
126
159
  * Check if initialized.
127
160
  * @returns {boolean}
@@ -147,6 +180,7 @@ export const version = getVersion;
147
180
  export default {
148
181
  initialize,
149
182
  minify,
183
+ reflect,
150
184
  isInitialized,
151
185
  version: getVersion
152
186
  };
package/lib/browser.js CHANGED
@@ -149,6 +149,23 @@
149
149
  return globalThis.__miniray.minify(source, options || {});
150
150
  }
151
151
 
152
+ /**
153
+ * Reflect WGSL source to extract binding and struct information.
154
+ * @param {string} source - WGSL source code
155
+ * @returns {Object} Reflection result with bindings, structs, entryPoints, and errors
156
+ */
157
+ function reflect(source) {
158
+ if (!_initialized) {
159
+ throw new Error('miniray not initialized. Call initialize() first.');
160
+ }
161
+
162
+ if (typeof source !== 'string') {
163
+ throw new Error('source must be a string');
164
+ }
165
+
166
+ return globalThis.__miniray.reflect(source);
167
+ }
168
+
152
169
  /**
153
170
  * Check if initialized.
154
171
  * @returns {boolean}
@@ -171,6 +188,7 @@
171
188
  return {
172
189
  initialize: initialize,
173
190
  minify: minify,
191
+ reflect: reflect,
174
192
  isInitialized: isInitialized,
175
193
  get version() { return getVersion(); }
176
194
  };
package/lib/main.d.ts CHANGED
@@ -75,6 +75,82 @@ export interface MinifyResult {
75
75
  minifiedSize: number;
76
76
  }
77
77
 
78
+ /**
79
+ * Result of shader reflection.
80
+ */
81
+ export interface ReflectResult {
82
+ /** Binding declarations (@group/@binding variables) */
83
+ bindings: BindingInfo[];
84
+ /** Struct type layouts */
85
+ structs: Record<string, StructLayout>;
86
+ /** Entry point functions */
87
+ entryPoints: EntryPointInfo[];
88
+ /** Parse errors, if any */
89
+ errors: string[];
90
+ }
91
+
92
+ /**
93
+ * Information about a binding variable.
94
+ */
95
+ export interface BindingInfo {
96
+ /** Binding group index from @group(n) */
97
+ group: number;
98
+ /** Binding index from @binding(n) */
99
+ binding: number;
100
+ /** Variable name */
101
+ name: string;
102
+ /** Address space: "uniform", "storage", "handle", or "" */
103
+ addressSpace: string;
104
+ /** Access mode for storage: "read", "write", "read_write", or undefined */
105
+ accessMode?: string;
106
+ /** Type as a string (e.g., "MyStruct", "texture_2d<f32>") */
107
+ type: string;
108
+ /** Memory layout for struct types, null for textures/samplers */
109
+ layout: StructLayout | null;
110
+ }
111
+
112
+ /**
113
+ * Memory layout of a struct type.
114
+ */
115
+ export interface StructLayout {
116
+ /** Total size in bytes */
117
+ size: number;
118
+ /** Required alignment in bytes */
119
+ alignment: number;
120
+ /** Field layouts */
121
+ fields: FieldInfo[];
122
+ }
123
+
124
+ /**
125
+ * Layout information for a struct field.
126
+ */
127
+ export interface FieldInfo {
128
+ /** Field name */
129
+ name: string;
130
+ /** Field type as a string */
131
+ type: string;
132
+ /** Byte offset from start of struct */
133
+ offset: number;
134
+ /** Size in bytes */
135
+ size: number;
136
+ /** Required alignment in bytes */
137
+ alignment: number;
138
+ /** Nested layout for struct or array-of-struct fields */
139
+ layout?: StructLayout;
140
+ }
141
+
142
+ /**
143
+ * Information about a shader entry point.
144
+ */
145
+ export interface EntryPointInfo {
146
+ /** Function name */
147
+ name: string;
148
+ /** Shader stage: "vertex", "fragment", or "compute" */
149
+ stage: string;
150
+ /** Workgroup size [x, y, z] for compute, null otherwise */
151
+ workgroupSize: [number, number, number] | null;
152
+ }
153
+
78
154
  /**
79
155
  * Options for initializing the WASM module.
80
156
  */
@@ -106,6 +182,13 @@ export function initialize(options: InitializeOptions): Promise<void>;
106
182
  */
107
183
  export function minify(source: string, options?: MinifyOptions): MinifyResult;
108
184
 
185
+ /**
186
+ * Reflect WGSL source to extract binding and struct information.
187
+ * @param source - WGSL source code to analyze
188
+ * @returns Reflection result with bindings, structs, entryPoints, and errors
189
+ */
190
+ export function reflect(source: string): ReflectResult;
191
+
109
192
  /**
110
193
  * Check if the WASM module is initialized.
111
194
  */
package/lib/main.js CHANGED
@@ -36,8 +36,15 @@ async function initialize(options) {
36
36
  const wasmModule = options.wasmModule;
37
37
 
38
38
  // Default to miniray.wasm in the package directory
39
+ // Use require.resolve to find files within the package, which works
40
+ // regardless of bundling or working directory
39
41
  if (!wasmURL && !wasmModule) {
40
- wasmURL = path.join(__dirname, '..', 'miniray.wasm');
42
+ try {
43
+ wasmURL = require.resolve('miniray/miniray.wasm');
44
+ } catch {
45
+ // Fallback to relative path for local development
46
+ wasmURL = path.join(__dirname, '..', 'miniray.wasm');
47
+ }
41
48
  }
42
49
 
43
50
  _initPromise = _doInitialize(wasmURL, wasmModule);
@@ -62,7 +69,16 @@ async function _doInitialize(wasmURL, wasmModule) {
62
69
  globalThis.crypto ??= require('crypto');
63
70
 
64
71
  // Load wasm_exec.js to set up Go runtime
65
- const wasmExecPath = path.join(__dirname, '..', 'wasm_exec.js');
72
+ // Use require.resolve to find files within the package, which works
73
+ // regardless of bundling or working directory
74
+ let wasmExecPath;
75
+ try {
76
+ wasmExecPath = require.resolve('miniray/wasm_exec.js');
77
+ } catch {
78
+ // Fallback to relative path for local development
79
+ wasmExecPath = path.join(__dirname, '..', 'wasm_exec.js');
80
+ }
81
+
66
82
  if (!fs.existsSync(wasmExecPath)) {
67
83
  throw new Error(`wasm_exec.js not found at ${wasmExecPath}`);
68
84
  }
@@ -125,6 +141,23 @@ function minify(source, options) {
125
141
  return global.__miniray.minify(source, options || {});
126
142
  }
127
143
 
144
+ /**
145
+ * Reflect WGSL source to extract binding and struct information.
146
+ * @param {string} source - WGSL source code
147
+ * @returns {Object} Reflection result with bindings, structs, entryPoints, and errors
148
+ */
149
+ function reflect(source) {
150
+ if (!_initialized) {
151
+ throw new Error('miniray not initialized. Call initialize() first.');
152
+ }
153
+
154
+ if (typeof source !== 'string') {
155
+ throw new Error('source must be a string');
156
+ }
157
+
158
+ return global.__miniray.reflect(source);
159
+ }
160
+
128
161
  /**
129
162
  * Check if initialized.
130
163
  * @returns {boolean}
@@ -147,6 +180,7 @@ function getVersion() {
147
180
  module.exports = {
148
181
  initialize,
149
182
  minify,
183
+ reflect,
150
184
  isInitialized,
151
185
  get version() { return getVersion(); }
152
186
  };
package/miniray.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miniray",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "WGSL minifier for WebGPU shaders - WebAssembly build",
5
5
  "main": "lib/main.js",
6
6
  "module": "esm/browser.js",