-
Notifications
You must be signed in to change notification settings - Fork 1
Introduction to TutorScript
Last Updated: 2026-06-18 | For: Content Creators & Developers | Level: Intermediate
TutorScript is the JSON authoring language used by MoFaCTS TDF and stimulus packages. A complete package usually has:
- a TDF file that names the lesson, selects the stimulus file, and defines units
- a stimulus file that contains the authored instructional content, prompts, responses, and SPARC documents
- optional media files referenced by the stimulus content
This tutorial is organized as five short pages. Start with ordinary lessons, then move into SPARC, the declarative node-based document system. The implementation-backed SPARC palette and rule vocabulary are cataloged in TutorScript SPARC Authoring Catalog.
TutorScript separates lesson structure from lesson content.
The TDF file answers questions like:
- What is the lesson called?
- Which stimulus file does it use?
- Which units run, and in what order?
- Is this a learning session, assessment session, video session, AutoTutor session, or SPARC session?
The stimulus file answers questions like:
- What content appears on the screen?
- What answer or learner action is expected?
- What media, nodes, feedback, or rules belong to a stimulus?
A minimal TDF points at a stimulus file:
{
"tutor": {
"setspec": {
"lessonname": "My Lesson",
"stimulusfile": "my_stims.json",
"userselect": "true"
},
"unit": [
{
"unitname": "Practice",
"learningsession": {
"clusterlist": "0",
"unitMode": "distance"
}
}
]
}
}A minimal stimulus file organizes items into clusters:
{
"setspec": {
"lessonname": "My Lesson",
"clusters": [
{
"clusterid": 0,
"stims": [
{
"display": {
"text": "What is the capital of France?"
},
"response": {
"correctResponse": "Paris"
}
}
]
}
]
}
}The key TDF fields are:
| Field | Meaning |
|---|---|
tutor.setspec.lessonname |
Display name of the lesson |
tutor.setspec.stimulusfile |
Stimulus JSON filename in the package |
tutor.setspec.userselect |
Whether students can select the lesson |
tutor.unit |
Ordered list of units in the lesson |
unitname |
Name of one unit |
learningsession |
Adaptive card-style practice unit |
assessmentsession |
Fixed assessment unit |
videosession |
Video unit |
autotutorsession |
AutoTutor unit |
sparcsession |
SPARC instructional document unit |
A SPARC unit uses sparcsession:
{
"unitname": "Progressive History Practice",
"sparcsession": {
"clusterlist": "0",
"unitMode": "distance"
}
}The matching stimulus file declares the selected page once in setspec.sparcPages:
{
"setspec": {
"sparcPages": [{
"pageId": "sparc-american-history-progressive",
"display": {
"type": "sparc",
"schema": "tutorscript-sparc/2.0",
"unitType": "sparc-progressive-chapter",
"nodes": [],
"behavior": {},
"productionRules": []
}
}]
}
}The TDF selects clusters. The stimulus file supplies the authored objects inside those clusters.
SPARC TutorScript is a declarative document tree. Authors describe nodes, groups, layout intent, learner actions, and rules. The runtime renders and executes that document.
The enclosing sparcPages[].pageId is the single authored page identity. Runtime
derives the neutral pageKey used in state addresses from that pageId; authors
must not add a separate display.pageKey.
Top-level SPARC display fields commonly include:
| Field | Meaning |
|---|---|
schema |
Required authored schema name: tutorscript-sparc/2.0
|
unitType |
Author-facing kind of SPARC activity |
layout |
Document layout, zones, and frontiers |
nodes |
Authored document nodes |
behavior |
SAI response mapping and step structure |
workingMemoryFacts |
Initial facts available to rules |
productionRules |
Executable rule objects |
stimulusRegistry |
Model-practice identities available to SPARC rules and progress reporters |
progressReporter |
Optional request for document or sidebar model-progress display |
response |
Scoring/evaluation metadata |
Nodes have stable ids:
{
"id": "node-intro-paragraph",
"nodeType": "group",
"groupType": "text-panel",
"placement": {
"region": "chapterFlowBox",
"order": 1
},
"children": [
{
"id": "node-intro-text",
"nodeType": "atomic",
"atomType": "text-block",
"value": "In April 1775, tensions between British troops and colonial militia turned into open fighting."
}
]
}Current authored node styles include:
| Pattern | Purpose |
|---|---|
nodeType: "atomic" |
A single displayed or interactive object |
nodeType: "group" |
A container with child nodes |
nodeType: "semantic" |
A clean authored object that runtime expands into concrete nodes |
atomType: "html-block" |
Sanitized rich HTML display |
atomType: "text-block" |
Plain text display |
atomType: "message-box" |
Correct/incorrect/hint/feedback message target |
atomType: "text-input" |
Fill-in learner input |
atomType: "button" |
Button input |
atomType: "dropdown" |
Select/dropdown input rendered by the SPARC surface |
atomType: "select" |
Legacy select input recognized by the SPARC bridge |
atomType: "checkbox" |
Checkbox input |
atomType: "panel-selector" |
Tabbed selector that displays one panel at a time |
atomType: "learning-progress" |
Inline model-backed progress display |
atomType: "skill-bar" |
Static authored progress-style display |
atomType: "fraction-box" / "fraction-input"
|
Renderer-recognized fraction cells that are normalized into groupType: "fraction" pairs when authored as adjacent numerator/denominator atoms |
Semantic multiple choice is the clean authoring form for multiple-choice questions:
{
"id": "node-mc-problem",
"nodeType": "semantic",
"semanticType": "multiple-choice",
"label": "Multiple choice",
"feedbackNodeId": "node-mc-feedback-message",
"prompt": {
"id": "node-mc-question",
"value": "Which event marked the beginning of open fighting in the American Revolution?"
},
"answerGroupId": "node-mc-answers",
"choices": [
{
"id": "node-choice-lexington-concord",
"label": "Lexington and Concord",
"value": "Lexington and Concord"
}
]
}At runtime, that semantic node is expanded into a group with a prompt, an answer-list group, button children, and an optional header feedback message box. The semantic object is the authored content; the expanded group is the execution/rendering detail.
Converted OLI content currently produces concrete SPARC groups for sections, examples/OLI groups, multiple choice, select-many TargetedCATA, dropdown exercises, text-input exercises, short-answer exercises, answer lists, checkbox rows, dropdown rows, text-input rows, and panel selectors for alternative tool directions such as Excel, R, and calculator panels.
SPARC can also report live adaptive-model progress when the document is connected to model-practice identities. The authored display may place an inline progress node:
{
"id": "node-learning-progress",
"nodeType": "atomic",
"atomType": "learning-progress",
"label": "Progress"
}or request the shared sidebar progress panel:
{
"progressReporter": {
"placement": "sidebar",
"label": "Progress"
}
}progressReporter.placement must be "document" or "sidebar". An inline learning-progress node requests document placement even when progressReporter is omitted. A sidebar request keeps the shared progress panel enabled; otherwise SPARC disables the sidebar panel and relies on document placement when requested.
SPARC behavior currently uses SAI-style response mapping:
{
"behavior": {
"schema": "sparc-behavior/1.0",
"orderPolicy": "progressive",
"responseFormalism": "SAI",
"steps": [
{
"id": "answer-opening-multiple-choice",
"responses": [
{
"selection": "choiceLexingtonConcord",
"action": "ButtonPressed",
"input": "Lexington and Concord",
"nodeRef": "node-choice-lexington-concord",
"modelTarget": "american-revolution-opening"
}
]
}
]
}
}behavior.steps.responses maps learner actions on nodes into rule facts. This is the path for preserving CTAT-style SAI labels, authored paths, and focused-selection hint behavior. Native SPARC controls can also emit direct node-id actions such as ButtonPressed, UpdateTextField, UpdateComboBox, and UpdateCheckbox; use explicit behavior mappings when authored rules need legacy SAI names or path-specific selections.
The executable rules live in top-level productionRules, not in descriptive behavior.authoredProductionRules. Current runtime validation fails clearly when behavior.authoredProductionRules is present because that field is not executable.
The production-rule condition language is fact-pattern based. It is separate from the reactive visibleWhen/enabledWhen condition language used for state/model conditions on nodes and reactive rules.
A production rule has:
| Field | Meaning |
|---|---|
id |
Stable rule id |
module |
Optional grouping name |
salience |
Higher-priority rules fire first |
when |
Working-memory fact patterns |
tests |
Optional comparisons after variables bind |
then |
Effects to apply when the rule fires |
Example correct multiple-choice rule:
{
"id": "history.mc.correct.lexington-concord",
"module": "american-history-progressive",
"salience": 20,
"when": [
{
"factType": "interface-event",
"slots": {
"pageKey": {
"type": "bind",
"variable": "pageKey"
},
"selection": {
"type": "literal",
"value": "choiceLexingtonConcord"
},
"action": {
"type": "literal",
"value": "ButtonPressed"
},
"input": {
"type": "literal",
"value": "Lexington and Concord"
}
}
}
],
"then": [
{
"type": "classify",
"outcome": "correct"
},
{
"type": "message",
"messageType": "success",
"template": "Correct.",
"target": {
"pageKey": {
"type": "variable",
"name": "pageKey"
},
"nodeId": {
"type": "literal",
"value": "node-mc-feedback-message"
}
}
},
{
"type": "credit",
"kc": "american-revolution-opening"
}
]
}Supported production-rule effect types include:
| Effect | Purpose |
|---|---|
classify |
Mark the learner action as correct, incorrect, partial, study, skipped, unknown, or buggy
|
message |
Send hint, buggy, success, or feedback text to a target message node |
write-state |
Write addressed node state |
assert-fact |
Add a working-memory fact |
credit |
Credit a KC |
model-practice |
Write adaptive model-practice history for a resolved model target |
append-node |
Add or replace a node at a frontier/box |
append-node-if-missing |
Add a node only if that id is not already present |
append-text |
Append text to an existing text node |
insert-node |
Insert a node before or after another top-level node |
For ordinary correctness feedback, pair these effects:
-
classifyrecords the outcome. -
write-statewith keycorrectnesstargets the learner-facing node and drives correct/incorrect highlighting. -
messagetargets amessage-boxnode and supplies the learner-facing feedback text. -
creditrecords KC credit.
For progressive feedback, use append-node-if-missing once and then append-text:
[
{
"type": "append-node-if-missing",
"frontier": "main",
"boxId": "chapterFlowBox",
"node": {
"id": "node-remediation-feedback",
"nodeType": "atomic",
"atomType": "text-block",
"placement": {
"region": "chapterFlowBox"
},
"value": ""
}
},
{
"type": "append-text",
"nodeId": "node-remediation-feedback",
"separator": " ",
"text": "Bunker Hill was an early major battle, but the war had already begun at Lexington and Concord."
}
]This creates one growing remediation paragraph instead of a new paragraph for every wrong answer.
For model-backed SPARC practice, rules use model-practice effects. The target must resolve through display-level stimulusRegistry and either an explicit stimulusId on the effect or exactly one stimulus attachment on the addressed node. Missing registry entries, duplicate stimulus ids, ambiguous node attachments, and node-only modelTarget usage fail before model history is written.
{
"type": "model-practice",
"outcome": "correct",
"stimulusId": "determine-lcd",
"nodeId": {
"type": "variable",
"name": "node"
},
"responseValue": {
"type": "variable",
"name": "input"
},
"input": {
"type": "variable",
"name": "input"
}
}A registry entry uses the same shared model identity fields as card practice:
{
"stimulusId": "determine-lcd",
"label": "Determine least common denominator",
"stimuliSetId": "sparc-fractions-addition",
"stimulusKC": "fractions.lcd",
"clusterKC": "fractions.addition",
"KCId": "fractions.lcd",
"KCDefault": "fractions.lcd",
"KCCluster": "fractions.addition"
}This is how current SPARC Fractions Addition content drives adaptive probabilities without making SPARC nodes themselves into model stimuli.
Use this workflow for TutorScript packages:
- Start from a working package in the configuration repository.
- Give every meaningful object a stable
id. - Keep TDF structure in the TDF file and screen/content behavior in the stimulus file.
- For SPARC, author declarative nodes and semantic objects; let runtime expansion create concrete subnodes where supported.
- Put executable SPARC rules in top-level
productionRules. - Use
behavior.steps.responsesto map learner node actions into SAI facts. - Use
messageeffects for transient correctness, hints, buggy messages, and feedback. - Use progressive operations for document growth at the frontier.
- For model-backed SPARC practice, define
stimulusRegistry, usemodel-practiceeffects, and addlearning-progressorprogressReporteronly when model targets are valid. - Validate JSON before upload.
- Upload the package and smoke-test one or two representative learner actions.
Common mistakes:
-
tutor.setspec.stimulusfiledoes not match the actual stimulus filename -
sparcsession.clusterlistpoints at a cluster that is missing - a rule message targets the wrong
nodeId - a learner input node has no matching
behavior.steps.responsesentry - a
model-practiceeffect names a stimulus that is absent fromstimulusRegistry - a SPARC progress reporter is added without valid model-practice configuration
- remediations create many new nodes when one growing feedback paragraph is intended
- authored descriptive rule notes are left in
behavior.authoredProductionRules, which is not executable - layout is treated like fixed CTAT regions instead of SPARC boxes, glue, nodes, and frontiers
Keep these boundaries clear:
- Authored TutorScript is the clean content representation.
- Runtime expansion and compiled executable rules are implementation details.
- SPARC is a declarative, node-based instructional document system.
- CTAT examples can inform visual and pedagogical expectations, but BRD/example tracing is not the SPARC runtime architecture.
Getting Started
- Teacher: First Hour
- Quick Start: Content Creation
- Class Setup and Assignment Workflow
- Anki Import Guide
Authoring Reference
- Introduction to TutorScript
- TutorScript SPARC Authoring Catalog
- Content Creation Reference Tables
- Stimulus Files (Content)
- Trial Types Reference
- Audio and Speech Settings
Advanced Authoring
- Learning Units
- Assessment Units
- Video Units and Adaptive Logic
- AutoTutor Sessions
- H5P Trial Displays
Reports and Help
- Researcher Guide
- Data Output and Reports
- Data Privacy, IRB, and FERPA Notes
- Experiment Routes
- TDF Field Reference
- Learning Algorithms Reference
- Video Units and Adaptive Logic
- AutoTutor Sessions
- H5P Trial Displays
- Deployment Guide
- Remote Install
- Runtime Settings Reference
- Admin Features Reference
- Custom Help Page Setup
- Troubleshooting
- Local Install
- Developer Reference Guide
- Learning Algorithms Reference
- Introduction to TutorScript
- TutorScript SPARC Authoring Catalog
- AutoTutor Sessions
- H5P Trial Displays
- Runtime Settings Reference
- Deployment Guide
- Glossary
- FAQ
- Screenshots
- License Guidance
- Implementation Cost Analysis
- GitHub Repository
- GitHub Issues