Generate a complete, self-contained HTML procedural skill practice widget for an interactive lesson scene.
This widget is for task-oriented procedural practice. It should help a learner complete an operational task through stateful steps, local decisions, consequence feedback, progress, and reset. It is not a full vocational simulator, not a quiz, and not a platform protocol extension.
This is not a checklist.
Procedural-skill widgets are:
The learner must make at least one decision, judgment, measurement, or tool-use choice. Clicking Done cannot be the only meaningful interaction.
The widget should feel like practicing a small operational task: the learner observes a state, chooses or confirms an action, sees the consequence, and moves the task toward a safe/completed state.
Procedural-skill is a procedural training mechanism, not a fixed visual style.
Do not default every widget to the same dark dashboard or checklist panel. Choose a layout that fits the scene intent, title, description, and key points while preserving the same runtime contract.
Useful visual directions include:
Regardless of visual style, the widget must remain interactive and preserve task operation, state, decision, feedback, progress, reset, completion checking, stable selectors, and postMessage compatibility. Do not turn visual variety into a read-only PPT page.
Your output must be a complete HTML document with:
<script type="application/json" id="widget-config"> tag.#feedback-panel for learner feedback and status messages.#state-panel, but it cannot replace #feedback-panel.postMessage listener for existing widget action message types only.Return only the HTML document. Do not wrap the result in Markdown fences.
The embedded widget config must be valid JSON and must use this minimum shape:
{
"type": "procedural-skill",
"task": "...",
"description": "...",
"tools": ["..."],
"steps": [
{
"id": "step-1",
"title": "...",
"description": "...",
"tools": ["..."],
"successCriteria": ["..."]
}
],
"successCriteria": ["..."],
"errorConsequences": ["..."]
}
Requirements:
type must be exactly "procedural-skill".step-1, step-2, step-3.Build a minimal stateful procedural practice UI.
resetState() function or equivalent full reset path. It must restore all learner state, not just change a single text node.Do not implement full simulation physics, domain-specific machinery, scoring systems, backend calls, data persistence, or cross-frame reporting.
Stable selector targets must be usable, not empty placeholders.
#step-1-control, #step-2-control, and other step controls must be real learner controls, not empty containers.<button>, <input>, <select>, or a semantic element with an explicit click handler and keyboard handler.#step-1-control must contain visible text or visible control content, such as "Complete step", "Check", "Measure", "Choose", "Go", or "Stop".<div id="step-1-control"></div>.#progress-display, the step row class/state, #feedback-panel, #state-panel, or success criteria gating.The HTML must include #feedback-panel as a visible text/status area for learner feedback. #feedback-panel is mandatory even when a separate #state-panel exists.
You may add a dedicated #state-panel if useful, but #state-panel cannot replace #feedback-panel.
The state/status area must:
#reset-btn is clicked.Do not make the feedback or state panel static decorative text.
At least one step must be a judgment interaction, not a simple Done button. Use one of these lightweight patterns:
The judgment should update step feedback, state/status, progress, and success criteria state.
At least one incorrect/unsafe path must show a real consequence or state change. Feedback should be phrased as an operational consequence, such as:
Do not use only "Correct", "Wrong", or "Try again" as the main feedback. Do not use scores as a substitute for consequences.
Include at least one lightweight operation proxy that gives the learner something to inspect or manipulate without requiring full simulation physics.
Good operation proxies include:
Keep the proxy simple, deterministic, and local to the widget. Do not load external resources or build complex mechanical simulation.
Success criteria must update based on actual state, not by default.
This prevents the UI from claiming completion before the learner has actually met the task conditions.
The widget must keep learner clicks, reset, and widget action SET_WIDGET_STATE on one consistent state model.
renderState() / updateUI() / equivalent render path after every learner click, reset, and SET_WIDGET_STATE.SET_WIDGET_STATE must not duplicate incompatible update logic. If a click can update progress, SET_WIDGET_STATE with the same completed step must update the same visible UI.resetState() or the equivalent reset path must clear completedSteps, return #progress-display to 0, restore #feedback-panel to its initial prompt, restore #state-panel / risk / decision / proxy state to initial values, remove completed classes from step rows, return success criteria to pending, clear highlights/annotations, and restore initial enabled/disabled controls.SET_WIDGET_STATE must support data.state.completedSteps. When received, it must synchronize the internal state and then re-render step row completed classes, #progress-display, #feedback-panel, #state-panel if present, and #success-criteria gating.SET_WIDGET_STATE must not only store internal variables. It must produce visible UI updates.SET_WIDGET_STATE changes disabled controls, first confirm each target element exists.Generated JavaScript must be defensive about optional or missing DOM targets.
const el = document.querySelector(selector); if (!el) return; before writing to DOM nodes.disabled, textContent, className, style, or event handlers on null elements.ANNOTATE_ELEMENT must not throw when data.content is missing and must not throw when the target is absent.Cannot set properties of null.Your HTML may include a small postMessage listener, but it must only support the existing platform-to-iframe message types:
SET_WIDGET_STATEHIGHLIGHT_ELEMENTANNOTATE_ELEMENTREVEAL_ELEMENTMAIC's renderer sends iframe messages using event.data.type as the platform message field. Generated HTML must read event.data.type; do not invent alternate message fields.
Use a listener pattern equivalent to:
window.addEventListener("message", (event) => {
const data = event.data || {};
const messageType = data.type;
if (messageType === "SET_WIDGET_STATE") {
// Read data.state.
}
if (messageType === "HIGHLIGHT_ELEMENT") {
// Read data.target.
}
if (messageType === "REVEAL_ELEMENT") {
// Read data.target.
}
if (messageType === "ANNOTATE_ELEMENT") {
// Read data.target. Use data.content when provided, but do not require it.
}
});
For SET_WIDGET_STATE, read state from data.state. If data.state.completedSteps is provided, update the shared state and re-render step completion, progress, feedback, state/status, and success criteria using the same render path as learner clicks.
For HIGHLIGHT_ELEMENT, REVEAL_ELEMENT, and ANNOTATE_ELEMENT, read the selector from data.target.
For ANNOTATE_ELEMENT, do not assume data.content is always present. If there is no content, the widget should still avoid errors and may show a minimal default annotation or simply highlight the target.
Do not call window.parent.postMessage.
Do not invent new message types.
Do not introduce iframe-to-platform callbacks.
Stable teacher-action targets:
Your HTML must expose stable DOM targets so existing platform widget actions can highlight, annotate, reveal, or set state without custom renderer code.
#task-panel#tool-list#step-list[data-step-id="step-1"]#step-1-control#step-1-feedback#success-criteria#progress-display#feedback-panel#reset-btnUse the actual step ID from the embedded widget config for each step-specific target, such as step-1, step-2, and step-3.
For SET_WIDGET_STATE, support a minimal state object such as:
{
"completedSteps": ["step-1", "step-2"]
}
For HIGHLIGHT_ELEMENT, apply a temporary visible outline to the target element.
For ANNOTATE_ELEMENT, display a temporary annotation near the target element using content when provided.
For REVEAL_ELEMENT, make a hidden target element visible.
Avoid these failures:
window.parent.postMessage.#step-1-control an empty div.#feedback-panel.#state-panel as a replacement for #feedback-panel.completedSteps or completed row classes after reset.data.state.completedSteps in SET_WIDGET_STATE.disabled, textContent, className, or style on null elements.Before finalizing the HTML, verify that:
#step-1-control are visible, enabled, clickable, and not empty.#feedback-panel exists as a visible feedback/status area.#state-panel does not replace #feedback-panel.SET_WIDGET_STATE with completedSteps visibly updates step rows, progress, feedback, state/status, and success criteria through the shared render path.disabled, textContent, className, or style on missing elements.widget-config.type is exactly "procedural-skill".Follow the requested language directive exactly when provided.