Skip to content

Commit f458618

Browse files
committed
feat: add friendly error for cross-hook property access (#8813)
When accessing one hook's struct properties from within another hook's begin/end block, show a helpful error suggesting sharedVec3 or sharedFloat instead of the cryptic undefined TypeError.
1 parent 7c8211b commit f458618

1 file changed

Lines changed: 48 additions & 14 deletions

File tree

src/strands/strands_api.js

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,50 @@ export function createShaderHooksFunctions(strandsContext, fn, shader) {
795795
hook.set = function(result) {
796796
hook._result = result;
797797
};
798+
hook._active = false;
799+
800+
const numStructArgs = hookType.parameters.filter(
801+
param => param.type && param.type.properties
802+
).length;
803+
let argIdx = -1;
804+
if (numStructArgs === 1) {
805+
argIdx = hookType.parameters.findIndex(
806+
param => param.type && param.type.properties
807+
);
808+
}
809+
if (argIdx >= 0) {
810+
const structParam = hookType.parameters[argIdx];
811+
if (structParam.type.properties) {
812+
for (const prop of structParam.type.properties) {
813+
const key = prop.name;
814+
Object.defineProperty(hook, key, {
815+
get() {
816+
if (!this._active) {
817+
FES.userError(
818+
'scope error',
819+
`It looks like you're trying to access "${hookType.name}.${key}" outside of its begin()/end() block.\n\n` +
820+
`Properties of ${hookType.name} are only available between ` +
821+
`${hookType.name}.begin() and ${hookType.name}.end().\n\n` +
822+
`To share data between hooks, use sharedVec3() or sharedFloat() ` +
823+
`to pass values between them.`
824+
);
825+
}
826+
return this._args[this._argIdx][key];
827+
},
828+
set(val) {
829+
if (!this._active) {
830+
FES.userError(
831+
'scope error',
832+
`It looks like you're trying to set "${hookType.name}.${key}" outside of its begin()/end() block.`
833+
);
834+
}
835+
this._args[this._argIdx][key] = val;
836+
},
837+
enumerable: true,
838+
});
839+
}
840+
}
841+
}
798842

799843
let entryBlockID;
800844
function setupHook() {
@@ -803,25 +847,14 @@ export function createShaderHooksFunctions(strandsContext, fn, shader) {
803847
CFG.addEdge(cfg, cfg.currentBlock, entryBlockID);
804848
CFG.pushBlock(cfg, entryBlockID);
805849
const args = createHookArguments(strandsContext, hookType.parameters);
806-
const numStructArgs = hookType.parameters.filter(param => param.type.properties).length;
807-
let argIdx = -1;
808-
if (numStructArgs === 1) {
809-
argIdx = hookType.parameters.findIndex(param => param.type.properties);
810-
}
850+
hook._active = true;
851+
hook._args = args;
852+
hook._argIdx = argIdx;
811853
hook._properties = [];
812854
for (let i = 0; i < args.length; i++) {
813855
if (i === argIdx) {
814856
for (const key of args[argIdx].structProperties || []) {
815857
hook._properties.push(key);
816-
Object.defineProperty(hook, key, {
817-
get() {
818-
return args[argIdx][key];
819-
},
820-
set(val) {
821-
args[argIdx][key] = val;
822-
},
823-
enumerable: true,
824-
});
825858
}
826859
if (hookType.returnType?.typeName === hookType.parameters[argIdx].type.typeName) {
827860
hook.set(args[argIdx]);
@@ -835,6 +868,7 @@ export function createShaderHooksFunctions(strandsContext, fn, shader) {
835868
};
836869

837870
function finishHook() {
871+
hook._active = false;
838872
const userReturned = hook._result;
839873
strandsContext.activeHook = undefined;
840874

0 commit comments

Comments
 (0)