@kubohiroya/turbowarp-runtime-expression
v0.9.0
Published
A safe condition evaluator and conditional broadcast monitor for TurboWarp runtime variables.
Maintainers
Readme
TurboWarp-Runtime-Expression
English | 日本語
Turn Temporary Variables into safe Boolean conditions, then broadcast only when a condition changes between false and true.
Full user guide: English · 日本語
Runnable sample
Open the demo in TurboWarp Editor · Download the SB3
Select Run without sandbox, then Allow, and click the green flag. The score condition is false at 9 and true at 10.
The project also loads the official Temporary Variables extension from the TurboWarp gallery. It is required for runtime variable evaluation; an internet connection is needed.
Editable sources and expected results: samples/README.md.
Run pnpm run samples:build after source/bundle changes and pnpm run samples:check before committing.
What it does
Runtime Expression adds two ways to use runtime state in a TurboWarp project:
- Check the current state: the
conditionreporter evaluates an expression and returnstrueorfalse. - React to a state change: a conditional broadcast watcher sends one message when a condition becomes true and another when it becomes false.
Temporary Variables → restricted expression parser → current result
false ⇄ true
│
└─ broadcast only on a transitionThe expression language looks like a small part of JavaScript, but it cannot run functions, assignments, or arbitrary property access. The implementation does not use eval or new Function.
Before you start
You need:
- TurboWarp Desktop or another environment that can load an unsandboxed custom extension.
- TurboWarp's Temporary Variables extension, loaded before Runtime Expression.
- Permission to select Run extension without sandbox when loading Runtime Expression.
[!CAUTION] Unsandboxed extensions can access the TurboWarp VM directly. Load the extension only from a source you trust.
Quick start
Add the Temporary Variables extension to your project.
Add the following URL as a custom extension:
https://cdn.jsdelivr.net/npm/@kubohiroya/[email protected]/dist/runtime-expression.jsEnable Run extension without sandbox when TurboWarp asks.
Create a runtime variable named
statewith Temporary Variables and set it toready.Put this expression in the
conditionblock:state == "ready"
The block now reports true. If state is missing or contains another value, it reports false.
To install the reviewed build from npm instead:
pnpm add --save-exact @kubohiroya/[email protected]Then load node_modules/@kubohiroya/turbowarp-runtime-expression/dist/runtime-expression.js.
Composition API
Applications that already own their runtime state can evaluate the same restricted condition language without registering Scratch blocks or using Temporary Variables:
import {createRuntimeExpressionComposition} from
'@kubohiroya/turbowarp-runtime-expression/composition';
const expressions = createRuntimeExpressionComposition();
const canContinue = expressions.evaluateCondition(
'state === "ready" && score >= 10',
{state: 'ready', score: 10}
);
expressions.releaseAll();The variables argument must be a plain object whose own enumerable data properties
contain only strings, finite numbers, or booleans. Inherited and unknown variables
are not resolved. An unknown variable that is actually evaluated throws a
RuntimeExpressionCompositionError; normal logical short-circuiting still applies.
releaseAll() clears the bounded parsed-expression cache and the composition remains
reusable. Importing this entry point does not read Scratch, the DOM, network,
storage, or Temporary Variables.
Check the current state
A bare name reads the runtime variable with the same name:
state == "ready" && score >= 10String values must be quoted. An unquoted word such as ready is treated as another variable name.
For a variable name containing spaces, Japanese, or other non-ASCII characters, use the exact vars["name"] form:
vars["current state"] === "ready" && vars["得点"] >= 10A missing runtime variable evaluates as undefined, so you can check for it explicitly:
nextScene === undefinedBroadcast when the result changes
Register a watcher with five values:
| Input | Purpose | Example |
|---|---|---|
| ID | Stable name used to replace or unregister this watcher | level-ready |
| CONDITION | Expression to monitor | state == "ready" |
| MESSAGE_ON_TRUE | Broadcast on false → true | state ready |
| MESSAGE_ON_FALSE | Broadcast on true → false | state not ready |
| TIMEOUT | Seconds before automatic removal; 0 means no timeout | 0 |
The watcher evaluates once when registered and remembers that initial result without broadcasting. After that:
| Result change | Behavior |
|---|---|
| false → true | Broadcasts MESSAGE_ON_TRUE |
| true → false | Broadcasts MESSAGE_ON_FALSE |
| false → false or true → true | Sends nothing |
Important lifecycle rules:
- Registering the same ID again replaces the previous watcher and its remembered state.
- A positive timeout removes the watcher silently; zero or less keeps it active.
- The unregister block removes the watcher with the matching ID. An unknown ID has no effect.
- Project start and stop clear all watchers, so register them again from your startup scripts.
- Multiple variable updates within one VM frame are combined; the watcher observes the final state on the next frame.
Expression syntax
| Supported | Examples |
|---|---|
| Values | finite numbers, quoted strings, true, false, null, undefined |
| Unary operators | !, unary +, unary - |
| Arithmetic | +, -, *, /, % |
| Comparison | ==, !=, ===, !==, <, <=, >, >= |
| Logic | &&, || with short-circuit evaluation |
| Grouping and lookup | parentheses, exact vars["name"] lookup |
Assignments, function calls, general property access, new, arrays, objects, optional chaining, and template strings are rejected. Expression length, token count, nesting depth, and the parsed-expression cache are bounded.
Blocks
condition [EXPRESSION]
Safely evaluates a JavaScript-like condition using Temporary Variables runtime variables.
| Property | Value |
|---|---|
| Type | Boolean |
| Opcode | runtimeCondition |
| Feature flag | runtimeExpression |
| EXPRESSION | String, default: state == "ready" |
register [ID] conditional broadcast [CONDITION] [MESSAGE_ON_TRUE] / [MESSAGE_ON_FALSE] with [TIMEOUT] seconds timeout
Registers broadcasts for false-to-true and true-to-false runtime condition changes.
| Property | Value |
|---|---|
| Type | Command |
| Opcode | registerConditionalBroadcast |
| Feature flag | conditionalBroadcast |
| ID | String, default: watcher |
| CONDITION | String, default: state == "ready" |
| MESSAGE_ON_TRUE | String, default: state ready |
| MESSAGE_ON_FALSE | String, default: state not ready |
| TIMEOUT | Number, default: 0 |
unregister [ID] conditional broadcast
Unregisters the conditional broadcast with the matching ID.
| Property | Value |
|---|---|
| Type | Command |
| Opcode | unregisterConditionalBroadcast |
| Feature flag | conditionalBroadcast |
| ID | String, default: watcher |
Compatibility
The extension ID is kubohiroyaruntimeexpression. Projects that still store the old twRuntimeExpression opcodes need a schema-aware project migration; replacing only the JavaScript file will break those stored blocks.
The runtimeExpression and conditionalBroadcast compile-time feature flags live in config/feature-flags.ts. Both are enabled by default.
Development
npm install --global corepack@latest
corepack enable
pnpm install --frozen-lockfile
pnpm run checkThe build produces dist/runtime-expression.js, dist/composition.js, and declarations in dist/types/. Commit the rebuilt files whenever source changes. The block reference above is generated from src/block-definitions.json; keep the marker comments intact.
GitHub Pages
The workflow in .github/workflows/pages.yml publishes docs/ after documentation changes reach main. The English guide is served at the site root and the Japanese guide at /ja/.
To roll back the guide, revert the documentation and workflow change. For an immediate withdrawal, disable the Pages workflow and GitHub Pages in the repository settings; this does not affect the extension runtime.
Releases
The tag-triggered release workflow checks the immutable source, packs the npm artifact, and attaches the standalone bundle, composition bundle, declarations, and tarball to the matching GitHub Release. Follow RELEASING.md for versioning, npm publication, verification, and rollback.
License
SPDX-License-Identifier: MPL-2.0
Fixed input editing
With a compatible TurboWarp GUI, enable fixed-input forms to edit only standard literal fields. Numbers use complete finite JSON number tokens; menu fields use existing choices. Connected reporters and unavailable fields stay read-only and are never evaluated. Saving an unchanged form preserves exact existing raw values, including legacy spellings and unknown choices. Invalid drafts stay in the same editing session; cancel, project/target replacement, or block removal discards them. Disabling the GUI feature flag restores native field editing. This form does not run blocks, open network/audio/key/QR sessions, resolve names, or edit Schema arguments. Nonpositive timeout values retain the no-deadline sentinel.
Canonical contracts: schemas/block-editor-fixed-inputs.schema.json; codecs and optional registration: src/fixed-input-editors.ts. These contracts describe new fixed-field candidates; they do not redefine all runtime data. The GUI integration is optional and existing standalone/composition APIs stay available.
registerConditionalBroadcast: TIMEOUT — block documentation.
