Properties node: name each shader param by its shader (#66)
game-maker / suite (push) Successful in 8m23s

The + Property menu of the Properties node offered every shader's params
for every sprite. Each shader row now carries its shader name, and a name
shared by two shaders lists both: "brightness (Adjust colors, Neon glow)".
Sprite-owned rows stay unlabelled.

The note hangs off a map keyed by the def object, not by the name -- a
sprite property and a shader param may share a name (#63), and keying by
name would label the wrong row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-13 14:05:01 +02:00
1 parent 05f7a2745e
commit 5c1c3c6fd6
5 files changed
+103 -13

No files matched your search

+17 -4
View File
@@ -237,12 +237,25 @@ export function shaderParamRows(project: Project, shaderId: string): PropertyDef
return shader ? shaderParamDefs(shader.graph) : [];
}
/** The parameters of every shader in the project, one row per name – what a sprite *may* have. */
export function allShaderParamRows(project: Project): PropertyDef[] {
const rows = new Map<string, PropertyDef>();
/** A shader parameter a sprite *may* have, with the shaders that declare it under that name. */
export interface ShaderParamRow {
def: PropertyDef;
shaders: string[];
}
/**
* The parameters of every shader in the project, one row per name – which sprite wears which shader
* is only known at runtime, so the picker offers them all and names where each one comes from.
*/
export function allShaderParamRows(project: Project): ShaderParamRow[] {
const rows = new Map<string, ShaderParamRow>();
for (const asset of project.assets)
if (asset.type === 'shader')
for (const row of shaderParamDefs(asset.graph)) if (!rows.has(row.key)) rows.set(row.key, row);
for (const def of shaderParamDefs(asset.graph)) {
const row = rows.get(def.key);
if (!row) rows.set(def.key, { def, shaders: [asset.name] });
else if (!row.shaders.includes(asset.name)) row.shaders.push(asset.name);
}
return [...rows.values()];
}
+14 -4
View File
@@ -76,12 +76,16 @@ export function buildPropertyPortSection(
}
if (target !== 'behavior') {
const owner = `a ${targetLabel(target)}`;
// A sprite's rows go on with the parameters of the shader it wears – any shader, the node cannot know which.
// A sprite's rows go on with the parameters of the shader it wears – any shader, the node cannot
// know which, so each entry says whose it is. Keyed by the def itself: a shader parameter and a
// sprite property may share a name, and only the shader's entry earns the note.
const shaderRows = target === 'sprite' ? allShaderParamRows(host.state.project) : [];
const from = new Map(shaderRows.map((row) => [row.def, row.shaders.join(', ')]));
buildPickedPortSection(host, assetId, node, {
noun: 'Property',
choices: [...targetProperties(target), ...shaderRows],
choices: [...targetProperties(target), ...shaderRows.map((row) => row.def)],
owner,
note: (def) => from.get(def),
});
return;
}
@@ -104,21 +108,27 @@ interface PickedPorts {
empty?: string;
/** Named by hand instead of picked. */
custom?: boolean;
/** Where a choice comes from, shown after its key in the menu; nothing for one that speaks for itself. */
note?: (def: PropertyDef) => string | undefined;
}
function buildPickedPortSection(
host: InspectorHost,
assetId: string,
node: GraphNode,
{ noun, choices, owner, empty, custom = false }: PickedPorts,
{ noun, choices, owner, empty, custom = false, note }: PickedPorts,
): void {
const plural = noun === 'Property' ? 'properties' : 'variables';
const ports = node.ports ?? [];
const taken = new Set(ports.map((p) => p.key));
const portOf = (def: PropertyDef): DeclaredPort => ({ key: def.key, kind: portKindOf(def) });
const choiceLabel = (def: PropertyDef): string => {
const where = note?.(def);
return where ? `${def.key} (${where})` : def.key;
};
const pick = (own: string, onPick: (port: DeclaredPort) => void): MenuItem[] =>
choices.map((def) => ({
label: def.key,
label: choiceLabel(def),
disabled: taken.has(def.key) && def.key !== own,
onSelect: () => onPick(portOf(def)),
}));