How to Use Scripting in Questsmith
Use scenario scripts to control input, context, and output behavior beyond the editor UI.
Scripting lets creators customize player experience beyond what the Scenario editor supports.
In Questsmith, scripts are attached to scenarios and shared by adventures started from that scenario, while each adventure keeps its own separate game state.
Scenario Support and Visibility
- Scripts are available for Simple Start and Character Creator scenarios.
- Multiple Choice parent scenarios cannot have scripts, but their options can.
- Only the scenario creator can view and edit scripts.
- Published scenario scripts may be moderation-reviewed for guideline compliance.
Scripting UI Overview
Open scripting from the bottom of the Details tab while editing a supported scenario.
- Library: Shared helpers and constants available to other scripts.
- Input: Runs during the onInput lifecycle hook.
- Context: Runs during the onModelContext lifecycle hook.
- Output: Runs during the onOutput lifecycle hook.
For non-library scripts, the last line must call modifier(text).
Script Test Panel
- Input: Editable test payload for simulating script behavior.
- Submit: Sends script + library + input to the server for execution.
- Output: Shows returned text, stop, logs, state, and storyCards.
Console Log Panel
- Displays recent logs from your own playtest adventures started from that scenario.
- Streams in real time, useful with split tabs (editor + playtest).
- Logs are retained for 15 minutes.
Lifecycle Hooks
The Scripting API exposes three hooks, each running in an isolated sandbox.
- onInput
- onModelContext
- onOutput
Runtime limits: 16 MB memory and 2-second timeout per hook.
Available Params
You can reference these directly in script scope:
- text: Player input, model context text, or output text depending on hook.
- history: Recent action array with text/rawText/type.
- storyCards: Adventure card array (legacy alias worldInfo still supported).
- state: Persistent object for custom script memory across turns.
- info: Helper metadata like actionCount, characterNames, maxChars, memoryLength.
State Object Notes
- Modify state directly (no helper needed).
- state.memory supports context, authorsNote, and frontMemory overrides.
- state.placeholders stores scenario placeholder question/answer values and persists across turns.
- state.message may be surfaced to players depending on client support.
Available Functions
- log
- addStoryCard
- removeStoryCard
- updateStoryCard
Return Contract
Scripts should return an object, most commonly:
return { text: 'New text' }
return { stop: true }- text: Replaces the hook text stream (input, model context, or output).
- stop: Halts loop progression. Use carefully and intentionally.
Important Error Behavior
- Returning empty text in onInput throws a script error to the player.
- Returning empty text in onModelContext behaves as if the script did not run.
- Returning empty text in onOutput throws a custom script failure to the player.
- Returning stop in onOutput is not recommended.
Minimal Input Script Example
const modifier = (text) => {
let modifiedText = text
if (text.includes('grab a sword')) {
state.items = ['sword']
state.memory = { context: 'You have a sword.' }
state.message = 'You got a sword!'
log('Added a sword to player')
modifiedText = text + '\nYou also now have a sword!'
}
return { text: modifiedText }
}
modifier(text)Practical Use Cases
- Command parsers (custom player commands).
- Inventory or status tracking in state.
- Dynamic memory/authorsNote/frontMemory adjustments.
- Context post-processing and safety rails.
- Automated Story Card insertion/removal based on events.
Best Practices
- Start with small scripts and test every hook independently.
- Keep scripts deterministic and avoid heavy computation.
- Use Library for reusable logic and constants.
- Guard against undefined fields (history, placeholders, info values).
- Prefer additive modifications over full text rewrites when possible.
- Use Console Log during live playtests and reproduce issues minimally.
For script issues or feature requests, use the Discord bugs/feature-request channel and include reproducible steps when possible.