Migration Guide

Main differences between Quillscript and its predecessor, Snowfall

This section exposes the differences between Snowfall Storytelling language and Quillscript language and enumerates significant changes and new features.

Although extensive, this guide can't enlist all differences between both versions. Instead, it brings major features, putting aside more in-depth topics like Internal use functions, rewritten classes, coding, programming, design, architecture, etc.

Syntax Changes

Condition instructions now start with ? (Question Mark).

$ End | ? {var} < 10

Variables are always required to be inside {} (Brackets), except when being assigned a value.

$ gold = 10

* Buy | ? {gold} > 10

Command instructions can optionally start with $ (Dollar Sign).

- Speaker | $ var = 10

// Using a marker is not mandatory.
$ Restore | var = 10

Although maintaining the same behavior, Quillscript changes from Python style comment # (Hashtag) to Javascript style comment // (Double Slash).

// This is a comment line.


Quillscript variables are stored as an Unreal Engine Text Type (FText), and the required conversions to C++ type are done under the hood when necessary. This means that you can change the data type of a variable and don't have to keep track of variable's types anymore.

$ variable = 10


Quillscript also has constants. They work exactly like variables, but if you try to change a constant value in the script, it will be ignored, preserving the original value. Constants are declared just like variables, but using just uppercase.


Assign Constructor

It is possible to assign a value to a variable only if it does not exist. This is useful mostly for setup a script on its first play.

$ x := 10

This is the same as $ x = 10, but is executed only if there is no variable already called x.

Change Variable Value

In Snowfall, variables are modified using the method below:

$ count + 1

In Quillscript, this won't work as expected. Quillscript sees every variable operation as an expression; this is seen as the literal string "count" plus 1, which usually has no logical sense.

To use the value of count, you must put it inside brackets {}:

$ {count} + 1

This expression does perform an operation and sum 1 to count's value, but the result is not stored, so it is discarded, you must assign the result of any expression, to a variable:

$ count = {count} + 1

Or you can self-reference the assigned variable using {&}:

$ count = {&} + 1

And the most reduced possible.

$ count += 1

Additionally, since this is an expression, you can perform a more complex calculation:

$ count = 1 + ((4 - {&}) / {&} ^ {level}) * 2

Deleting Variables

The method to delete variables has changed, to be more concise with the language.

$ Delete name

Asset Path

Snowfall uses its own format for asset paths. To conform with UE5 new path standards, Quillscript uses the same path format as the engine itself; it does not apply or require any adaptation.


Calling Functions by Class

Also, to conform with the new UE5 path's standard, to call a function by class, it's required to use the new path format.

// Blueprint
$ ^/Game/Path/To/MyBlueprint.MyFunction args...

// C++
$ ^MyModule.MyClass.MyFunction args...

Return Value and Outer Parameters

It's no longer required to capture the return value of a function. After a function with a return value and outer parameters is executed, the interpreter automatically creates temporary variables using the returned parametersโ€™ names in the following format:

$ MyFunctionWithOuter

- Speaker Name | ? {$ReturnValue} >= 10
  I have {$OuterParameterName}.

Removed Built-In Functions

The following functions were removed in favor of better alternatives.

$ Input

Use $ SetInputMode, $ InputEnable, $ InputDisable,

$ ShowMouseCursor, and $ HideMouseCursor

$ UI

Use $ Show, $ Hide, $ ShowDialogBox, $ RemoveSelectionBox, etc

$ ChangeScene

Use $ Travel

$ ChangeBackground

Use $ Background

$ UseWidget

Renamed to $ Use


Go To statements were renamed to Router.


It is no longer needed. Any concatenated router statement will be used when the condition fails.

-> SuccessLabel | -> FailureLabel | ? {counter} > 10

// It also works with other types of statements.
- Speaker | ? {counter} > 10 | -> FailureLabel

Go To navigation special tags were replaced by flow commands.

-> #next

$ Done

Go to next label

-> #back

$ Repeat

Restart current label

-> #stop

$ Stop

Stop script

-> #the_end

$ End

Terminate Scene

-> #jump


Jump next script line


~ start


It has a parameter to control which start point to use

~ define


Works during parsing time

~ replace


Works during runtime

~ include


Includes script at location

~ import


Includes script at end, only once

~ inject


Inject statements at a specific index.

Text and Comments

Text no longer needs to start with tabulation; it can now use any whitespace or none. This is possible because comment lines always require beginning with // (Double Slashes).

Any free text line is concatenated with the previous statement, allowing multiline text within options and other statements.

There is one exception, however. Any free text line before the first statement is also seen as a comment, by the parser.

SCENE 1 - Title
Lines before the first statement, are comments.

- Speaker
  Lines after the first statement, are text.

- Speaker
  They can be indented using spaces, tabs,
or not be indented.

// Any comment line after the first statement, requires double slash.
  // Being it indented, or not

In addition, Quillscript allows the use of inline comments and section brackets.


Tags are declared using # (Hashtag) just like in Snowfall, but you can declare a chain of tags without the need for concatenation.

- Bob | #fast #upper #red

// Snowfall concatenation also works.  
- Bob | #fast | #upper | #red

On Snowfall, tags are stored as an array of strings containing each tag, including the hashtag (#), like [ #fast, #upper, #etc ]. Quillscript however, cleans the hashtag before storing the tag in the array, [ fast, upper, etc ].

Special Tags

Some special tags were removed or replaced.



Labels also use #once, for standardization



Use $ Stop and $ Restore either in script, Blueprint or C++



Use $ Hide







Can be used with any statement, the statement is not removed from the script anymore, but won't play a second time and instead move to the next statement


On Snowfall, the #localize special tag is used to localize the entire statement at once.

On Quillscript, you can localize individual strings in a statement, allowing much more control over what has to be localized.

Surround it with ` (Backtick) to localize a string:

$ MyFunction `This text should be localized` 'this text should not'


The template syntax is significantly different. It was changed to add a layer of reusability to Quillscript code and to be in conformity with its syntax.

-> MyTemplate (Lone Wanderer, 10, Hello)

@ MyTemplate (arg1, arg2, arg3)
  - {@arg1} | ? {charisma} > {@arg2}

Script Settings

Snowfall uses default settings that are applied to each Scene on creation. On Quillscript, these settings can be controlled per script, allowing you to have a set of default settings and use custom settings for specific scripts.


A common Snowfall project's requirement is better control over how the Scene sets and changes input mode during and after play.

Quillscript lets you define default and per-script settings for Input Mode during and after script play. And brings built-in functions to allow complete control over player input.

$ SetInputMode, $ InputEnable, $ InputDisable, $ ShowMouseCursor, $ HideMouseCursor, and others.

Scene, Interpreter, Lexer, Parser and Evaluator

Snowfall uses an actor called Scene to interpret strings previously organized by a parser.

In Quillscript, the Scene actor doesn't exist; its functionalities were split between 3 specialized classes: Interpreter Actor, Lexer/Parser Static Library, and Evaluator Static Library. All codded from scratch.

These classes are responsible for converting a plain text script source file into an Unreal Engine Asset and interpreting this asset, resulting in something the player can see and interact with.

Content Browser Menu

Snowfall context browser submenu shrunk with time, to remove deprecated features like Scenarios.

Quillscript has a more helpful set of shortcuts for custom asset creation.

Tools Function Library

Snowfall is shipped with a collection of useful general-purpose functions called Tools Function Library (UTools).

On Quillscript, many of these functions are improved, and some new functions were added.


Quillscript Function Library

Some Snowfall functions are packed in a separate and independent static library called Snowfall Function Library (USnow). This allows developers to reuse and rely on the same functions used by the plugin itself when creating custom behaviors.

Quillscript continues this philosophy with the Quillscript Function Library (UQuill).


New Features

Below is a linked list containing major new features exclusive to Quillscript.

Other Changes

Console Commands

The prefix for console commands changed from sf to qsc


The sf.GoTo console command was renamed to qsc.PlayByLabel

File Extension

Quillscript files remain as plain text files, but with a new extension, changing from .sf to .qsc

Quillscript files also require another Visual Studio Code extension

Sound Channels

Previously, the Scene had a pre-defined limited number of sound channels to play 2D sounds. Quillscript manages the number of sound components and controls its lifetime without any setup.

Renamed Classes

These classes were renamed and/or modified.




























Removed Classes

These classes were removed and are no longer required.

  • USnowSaveGame

  • EVarType

  • EArithmeticOperator

  • ERelationalOperator

  • FScreenplay

  • EFlowState

  • FOuterParam

New Classes

These are new classes responsible for some of the new features and internal functionalities.

  • FEvaluator

  • EDirectory

  • ESettingsFile

  • FExpression

  • FSaveState

  • FSoundState

  • EInputMode

  • EOperator

  • EPermission

  • EPicker

  • EScriptIdMethod

  • FScriptSettings

  • FInterpreterState

Last updated