Skip to content

Introduction to TutorScript

Philip Pavlik edited this page Jul 11, 2026 · 4 revisions

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:

  1. a TDF file that names the lesson, selects the stimulus file, and defines units
  2. a stimulus file that contains the authored instructional content, prompts, responses, and SPARC documents
  3. 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.

Page 1: The Mental Model

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"
            }
          }
        ]
      }
    ]
  }
}

Page 2: Package Anatomy

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.

Page 3: SPARC Document Objects

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.

Page 4: Behavior and Production Rules

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:

  • classify records the outcome.
  • write-state with key correctness targets the learner-facing node and drives correct/incorrect highlighting.
  • message targets a message-box node and supplies the learner-facing feedback text.
  • credit records 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.

Page 5: Authoring Workflow and Checklist

Use this workflow for TutorScript packages:

  1. Start from a working package in the configuration repository.
  2. Give every meaningful object a stable id.
  3. Keep TDF structure in the TDF file and screen/content behavior in the stimulus file.
  4. For SPARC, author declarative nodes and semantic objects; let runtime expansion create concrete subnodes where supported.
  5. Put executable SPARC rules in top-level productionRules.
  6. Use behavior.steps.responses to map learner node actions into SAI facts.
  7. Use message effects for transient correctness, hints, buggy messages, and feedback.
  8. Use progressive operations for document growth at the frontier.
  9. For model-backed SPARC practice, define stimulusRegistry, use model-practice effects, and add learning-progress or progressReporter only when model targets are valid.
  10. Validate JSON before upload.
  11. Upload the package and smoke-test one or two representative learner actions.

Common mistakes:

  • tutor.setspec.stimulusfile does not match the actual stimulus filename
  • sparcsession.clusterlist points at a cluster that is missing
  • a rule message targets the wrong nodeId
  • a learner input node has no matching behavior.steps.responses entry
  • a model-practice effect names a stimulus that is absent from stimulusRegistry
  • 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.

See Also

Clone this wiki locally