GTS Syntax Reference
GamingTS (GTS) is a superset of TypeScript. A .gts file can contain any valid TypeScript, plus GTS-specific define statements and query expressions.
Formal Grammar
The GTS parser extends ECMAScript/TypeScript with these productions (comments show the grammar from gts_plugin.ts):
Statement:
+ DefineStatement
DefineStatement:
"define" [no LineTerminator here] NamedAttributeDefinition
NamedAttributeDefinition:
AttributeName AttributeBody AttributeBindingClause? ";"
AttributeName:
Identifier
StringLiteral
AttributeBody:
PositionalAttributeList? NamedAttributeBlock?
AttributeBindingClause:
"as" BindingAccessModifier? Identifier
BindingAccessModifier:
"private"
"protected"
"public"
PositionalAttributeList:
AttributeExpression
AttributeExpression "," PositionalAttributeList
NamedAttributeBlock:
"{" NamedAttributeList DirectShortcutFunction? "}"
NamedAttributeList:
[empty]
NamedAttributeDefinition NamedAttributeList
AttributeExpression:
":" ShortcutFunction
[lookahead != "{"] PrimaryExpression
DirectShortcutFunction:
[lookahead = one of ":", ReservedWord]
FunctionBody[~Yield, ~Await]
ShortcutFunction:
"(" Expression[+In, ~Yield, ~Await] ")"
"{" FunctionBody[~Yield, ~Await] "}"
PrimaryExpression:
+ ShortcutArgumentExpression
ShortcutArgumentExpression:
":" Identifier
UnaryExpression:
+ "query" "*"? UnaryExpressionDefine Statement
The define keyword starts a top-level declaration. It is only valid at the module (top) level.
define character {
id 1201 as Barbara;
since "v3.3.0";
tags hydro, catalyst, mondstadt;
health 10;
energy 3;
skills WhisperOfWater;
}Anatomy
define <RootAttributeName> {
<AttributeName> <positional1>, <positional2>, ... {
<NestedAttributeName> <positionals> ;
...
} as <BindingName> ;
}define— keyword (must be followed immediately by an identifier, no line break allowed).- Root attribute name — the first identifier after
define(e.g.,character,skill,summon). This tells the runtime which ViewModel to use. - Named attribute block (
{ ... }) — contains a list of nested attribute definitions. - Positional attributes — comma-separated expressions appearing before a
{or;. - Binding clause (
as Name) — exports the attribute's return value as a variable. Access modifierspublic(default),private, orprotectedcontrol visibility.
Positional Attributes
Lowercase identifiers in positional position are automatically converted to string literals:
tags hydro, catalyst, mondstadt;
// transpiles to: tags("hydro", "catalyst", "mondstadt")Expressions starting with uppercase or non-identifier characters are kept as-is:
skills WhisperOfWater;
// transpiles to: skills(WhisperOfWater) — a variable referenceShortcut Functions
The colon (:) prefix creates shortcut functions — concise syntax for calling methods on a context object.
Shortcut Expression (:( expr ))
when :( true )
// transpiles to: when((__gts_fnArg, { cryo, hydro, ... } = __gts_fnArg[Prelude]) => true)Shortcut Block (:{ stmts })
:{ console.log("hello"); return 42; }
// transpiles to: ((__gts_fnArg, { cryo, hydro, ... } = __gts_fnArg[Prelude]) => { ... })Shortcut Argument (:identifier)
Inside a shortcut function, :identifier accesses a property on the function argument:
:damage(hydro, 1);
// transpiles to: __gts_fnArg.damage("hydro", 1)
// (inside an arrow function with __gts_fnArg as the first parameter)The shortcut function parameters are:
__gts_fnArg— the context object{ cryo, hydro, pyro, electro, anemo, geo, dendro, omni } = __gts_fnArg[Prelude]— destructured prelude symbols (element constants)
Direct Shortcut Function
Inside a named attribute block, if the parser encounters a : token or a reserved word, it enters "direct function" mode — the remaining statements are treated as the function body:
define skill {
id 12011 as WhisperOfWater;
cost hydro, 3;
:damage(hydro, 1); // <-- direct function starts here
:summon(MelodyLoop);
}This is equivalent to having an [Action] attribute with the function body.
Query Expressions
The query keyword creates a query expression for accessing game state:
query my.character // query({ my, opp }) => my.character
query* my.character // query with star flag (e.g., multi-select)The * after query sets a star: true flag on the generated call. Query expressions are transformed into calls to a query function with destructured bindings (default: my, opp).
Binding Exports
The as clause after an attribute exports its return value:
define character {
id 1201 as Barbara; // export const Barbara = ...
id 1201 as private Barbara; // const Barbara = ... (not exported)
}as Name— public export (default)as public Name— explicit public exportas private Name— local variable, not exportedas protected Name— not supported (throws error)
TypeScript Interop
GTS files can contain standard TypeScript alongside define statements:
import { A } from "./test2.gts";
export const add = (a: number, b: number) => a + b;
define character {
id 1201 as Barbara;
// ...
}
const sub = (a: number, b: number) => a - b;The transpiler preserves all TypeScript code and only transforms GTS-specific constructs. TypeScript type annotations are erased in the final JS output (same as standard TS compilation).
Reserved Words
GTS adds two keywords to the language:
define— starts a define statement (top-level only)query— creates a query expression (inside shortcut functions)
These are contextual keywords — define is only recognized at the start of a top-level statement (with no line break after it), and query is only recognized in unary expression position.