Loading...
Loading...
Workbench agent panel system — ef-edit CustomEvent pipeline, registry roll-up, selector grouping, and element property schema. Use when adding new GUI edit capture points, expanding the inspector schema, or continuing development of the EFAgentPanel feature.
npx skill4agent add editframe/skills agent-panelEFAgentPanelef-editGUI interaction (canvas drag, inspector change, trim drag, loop toggle)
└─ component.dispatchEvent(createEditCustomEvent(editEvent))
└─ [bubbles: true, composed: true]
└─ EFWorkbench listener → agentPanel.addEdit(event)
└─ Map<editChangeKey, EditEvent> registry (deduplicates)
└─ groupEditsBySelector() → buildAgentPrompt() → copy buttonEFWorkbenchaddEventListener('ef-edit', ...)ef-editeditEvents.ts// EditEvent — what the panel accumulates
interface EditEvent {
operation: EditOperation;
description: string; // human sentence
selector: string; // CSS path from composition root
elementHtml: string; // cleaned outerHTML snippet
timestamp: number;
}
// Operation union — extend here when adding new interaction types
type EditOperation =
| { type: "element-property-changed"; elementId; tagName; label; property; oldValue; newValue }
| { type: "element-moved"; elementId; tagName; label; fromX; fromY; toX; toY }
| { type: "element-resized"; elementId; tagName; label; x; y; width; height }
| { type: "element-rotated"; elementId; tagName; label; rotation }selector::prop:propNameselector::moveselector::resizeselector::rotateimport {
createEditCustomEvent, buildSelectorPath, getElementHtml,
buildEditDescription, type ElementPropertyChangedOperation,
} from "../../editEvents.js";
const oldValue = element.someProperty;
element.someProperty = newValue;
const op: ElementPropertyChangedOperation = {
type: "element-property-changed",
elementId: el.id,
tagName: el.tagName.toLowerCase(),
label: el.textContent?.trim().slice(0, 30) || el.id || el.tagName.toLowerCase(),
property: "attr-name", // attribute name as used in HTML source
oldValue,
newValue,
};
this.dispatchEvent(createEditCustomEvent({
operation: op,
description: buildEditDescription(op),
selector: buildSelectorPath(el),
elementHtml: getElementHtml(el),
timestamp: Date.now(),
}));buildPropertyEditEvent(element, property, oldValue, newValue)EFInspector.ts# Every call site that produces an ef-edit event
rg 'createEditCustomEvent' elements/packages/elements/src/
# Track subclasses that override render() — each must bind @trim-change-end
rg 'override render' elements/packages/elements/src/gui/timeline/tracks/
# Registered element schemas
rg 'SCHEMA_REGISTRY' elements/packages/elements/src/gui/elementPropertySchema.tsef-edithierarchy-reorderEFHierarchyElementReorderedOperationtrim-change-endcomposed: trueEFTrimHandlesTrackItem.render()@trim-change-endef-trim-handlesEFVideoTrackrender()ef-trim-handlesrender()ef-trim-handles@trim-change@trim-change-endTrackItem.render()render()elementPropertySchema.tsSCHEMA_REGISTRYtimeDescriptor(attr, label, opts)${ms}msenumDescriptor(attr, label, options, condition?)boolDescriptor(attr, label, condition?)numberDescriptor(attr, label, opts)stringDescriptor(attr, label)elementPropertySchema.test.tseditEvents.tseditChangeKeyrollUpEditsgroupEditsBySelectorbuildAgentPrompttrim-change-endef-trim-handlesconst trimHandles = track.shadowRoot?.querySelector("ef-trim-handles");
trimHandles?.dispatchEvent(new CustomEvent("trim-change-end", {
detail: { elementId: video.id, type: "start" },
bubbles: true, composed: true,
}));shadowRoot.querySelector("button[title='Loop']").click()documentef-editbubbles: true, composed: truedocument