TurboWarp custom extension

Real data, without the string juggling.

Load JSON or YAML once, give it a name, and work with it directly: read one field, change one value, loop over a list, then turn the result back into text. No more splitting strings or keeping parallel lists in sync.

parse YAML speed: 4 as cfg
set cfg at path $.speed to JSON 6
to JSON cfg {"speed":6}

01 · Start here

Ready in three steps.

Structured Data is an opt-in preview. Its blocks appear only when the startup flag is set before the extension loads, so an existing project is never affected by accident.

1

Turn on the feature flag

In the page that runs TurboWarp (for example, from the browser console or your own host page), run globalThis.STRUCTURED_DATA_MVP = true before loading the extension.

2

Load the extension

Add the extension URL below as a custom extension and choose Run extension without sandbox.

3

Parse your first value

Drag parse JSON [ ] as [data] or parse YAML [ ] as [data] into a script and click it. The name data now holds your value.

Version-pinned extension URL
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-structured-data@0.6.2/dist/structured-data.js

Unsandboxed access is required. Each sprite and the stage keep their own named values, and loops track the running script. That needs direct access to the TurboWarp VM. The extension makes no network requests and stores nothing outside the running project. Only load extension files from a source you trust.

02 · How it works

Parse once. Work by name. Render when you need text.

Text goes in, a named value lives in the sprite, and you only get text back when you ask for it. In between, every block works on the real structure: objects, arrays, numbers, strings, Booleans, and null.

The life of a named value
JSON or YAML text from a variable, a list item, a file, or a web response
Named value read, test, set, delete, and loop by $.path
JSON or YAML text stable key order, ready to save or send

Each sprite has its own names

config in Sprite1 and config on the stage are two separate values. Parsing the same name again replaces it.

Values last until Stop

Named values live only while the project runs. Clicking Stop clears them, and they are not saved in the project file. Keep the source text in a variable if you need it later.

Read a setting

blocks
parse JSON [{"level":{"speed":4}}] as [cfg]
get JSON from [cfg] at path [$.level.speed]
→ 4

Use the reporter wherever you would use a number or a piece of text.

Update and save

blocks
set [save] at path [$.score] to JSON [120]
set [save] at path [$.name] to JSON ["Mio"]
set [saved text] to (to JSON [save])

The value is JSON, so text needs quotes: "Mio", not Mio.

Check before you read

blocks
if <structured data [save] has path [$.items]?>
  say (length of array in [save] at path [$.items])

Test first to avoid errors from missing data or paths.

03 · Paths

Point at exactly one place.

A path starts at $, the whole value, and steps into it one key or index at a time. Paths are deliberately simple: each one names a single location, so a block can never touch more than you meant.

Path Points at
$ The whole value.
$.player.name Key name inside key player. Dot keys use letters, digits, and _, and do not start with a digit.
$.items[0] The first item of the items array. Indexes start at 0.
$["key.with dots"] Any key, including spaces, dots, or Japanese text, written in quotes and brackets.

What set and delete path do

  • set can replace the root, replace an existing array item, or add or replace a key in an existing object.
  • Deleting an array item moves later items forward by one.
  • A change is applied only after it fully succeeds, so a failed block leaves your value unchanged.

What is rejected

  • Creating missing parent objects or arrays automatically.
  • Appending past the end of an array.
  • Deleting $; use delete structured data instead.
  • Wildcards, slices, filters, recursive search, and expressions.

04 · Loops

Visit every item, in a predictable order.

for each in [ ] at path [ ] max [ ] runs its inner blocks once per array item or object key. Inside the loop, three reporters tell you where you are.

blocks
parse JSON [{"items":["apple","pear"]}] as [shop]
for each in [shop] at path [$.items] max [100]
  say (join (current index) (current value JSON))
→ 0"apple"   1"pear"
Reporter Inside the loop
current key The object key, or the array index as text.
current index The step number, starting at 0.
current value JSON The current item as JSON.

Same order every time

Arrays go by index. Objects go by key, sorted by Unicode code point, so results do not depend on how the text was written.

max is a safety limit

Use a whole number from 1 to 1000 (default 100). If the collection is bigger, the loop fails instead of silently skipping items.

Safe to nest

Loops can be placed inside other loops. The reporters always describe the innermost loop that is running.

05 · Block guide

Choose a block by what you want to do.

Every block below takes a NAME. The complete block reference lists each argument and default value.

I want to… Use
Load text into a named value parse JSON [ ] as [ ], parse YAML [ ] as [ ]
Get the whole value back as text to JSON [ ], to YAML [ ]
Check or remove a named value structured data [ ] exists?, delete structured data [ ]
Read or test one location get JSON from [ ] at path [ ], structured data [ ] has path [ ]?
Change one location set [ ] at path [ ] to JSON [ ], delete path [ ] from [ ]
Inspect a collection keys in [ ] at path [ ] (sorted, as a JSON array), length of array in [ ] at path [ ]
Repeat for each item for each in [ ] at path [ ] max [ ] with current key, current index, current value JSON

06 · Limits and safety

Strict input, predictable output.

Structured Data accepts plain data only and fails clearly instead of guessing. That keeps large or unusual input from freezing a project or changing meaning.

Size limits

Each parse accepts up to 256 KiB of text, nesting up to 64 levels deep, and up to 50,000 values in total.

Safe YAML

Aliases, unknown tags, duplicate keys, non-text keys, unsupported scalar types, and parser warnings are rejected.

Stable output

to JSON and to YAML always sort keys, so the same data gives the same text: easy to compare, save, or send.

07 · Optional integrations

Editing forms and shared named data.

These features are off by default and need nothing for normal use. Turn them on only in a TurboWarp build or host that supports them.

Source and Form editor

With the GUI startup options blockEditorDialogs=1 and blockEditorSourceForms=1, the JSON/YAML inputs of parse JSON, parse YAML, and set … to JSON open in an editor that switches between source text and a form. Unchanged text is kept exactly as written, and input the block would reject cannot be saved.

Fixed-input editor for max

With blockEditorDialogs and blockEditorFixedInputs both on, the max input of for each gets a form that accepts whole numbers from 1 to 1000. Existing values are not rewritten unless you edit them, and connected reporters are never evaluated.

Named Data provider

With globalThis.NAMED_DATA_REGISTRY_MVP = true, named values are also offered to other extensions through the shared Named Data registry as structured data. Add __TW_NAMED_DATA_FEATURE_FLAGS__ = {NAMED_DATA_SCHEMA_REF: true} to pass along schema identities.

08 · Troubleshooting

When a block does not do what you expect.

Most problems come from the startup flag, JSON quoting, or a value that was cleared by Stop. When a block fails it reports one of the stable error codes below, and your named value stays as it was.

The palette is empty

Set globalThis.STRUCTURED_DATA_MVP = true first, then load the extension again. The flag is read only once, at startup.

Text values come back with quotes

get JSON returns JSON, so the text Mio comes back as "Mio". Store text with quotes too: set … to JSON ["Mio"].

“DATA_NOT_FOUND” after Stop

Stop clears all named values. Parse your data again from a when green flag clicked script.

Another sprite cannot see my data

Names belong to the sprite or stage that ran the parse. Parse in each sprite that needs the value, or pass the JSON text through a global variable.

“PATH_NOT_FOUND” when setting

set does not create missing parents. Set the parent first, for example $.player to {}, then $.player.name.

“ITERATION_LIMIT_EXCEEDED”

The collection is larger than max. Raise max (up to 1000) or loop over a smaller part of the data.

Error code Meaning
INVALID_JSON / INVALID_YAMLThe text could not be parsed, or uses YAML features that are not allowed.
PARSE_LIMIT_EXCEEDEDThe text is larger, deeper, or has more values than the limits allow.
INVALID_NAMEThe name is empty or only spaces.
DATA_NOT_FOUNDNo value with that name exists in this sprite.
INVALID_PATHThe path is not written in the supported form.
PATH_NOT_FOUNDThe path, or its parent, does not exist.
TYPE_MISMATCHThe location holds a different type, such as a number where an array was expected.
INDEX_OUT_OF_RANGEThe array index is past the end of the array.
ITERATION_LIMIT_EXCEEDEDThe collection has more items than max.
ITERATION_CONTEXT_REQUIREDA current … reporter was used outside a for each loop.

Structured Data: complete block reference

All 16 blocks are documented below, including compatibility blocks and blocks available through optional features. Select a block to read its behavior, arguments, default values, and menu choices. Each block has a permanent link.

parse JSON [TEXT] as [NAME]

Parse JSON text into the target-local structured data namespace.

Block type: COMMAND. Opcode: parseJson. Permanent link

ArgumentTypeDefault valueMenu choices
TEXTSTRING{"name":"TurboWarp"}
NAMESTRINGdata

parse YAML [TEXT] as [NAME]

Parse safe YAML text into the target-local structured data namespace.

Block type: COMMAND. Opcode: parseYaml. Permanent link

ArgumentTypeDefault valueMenu choices
TEXTSTRINGname: TurboWarp
NAMESTRINGdata

to JSON [NAME]

Render named structured data as canonical JSON.

Block type: REPORTER. Opcode: toJson. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata

to YAML [NAME]

Render named structured data as deterministic YAML.

Block type: REPORTER. Opcode: toYaml. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata

structured data [NAME] exists?

Report whether the current target has named structured data.

Block type: BOOLEAN. Opcode: hasStructuredData. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata

delete structured data [NAME]

Delete named structured data from the current target.

Block type: COMMAND. Opcode: deleteStructuredData. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata

get JSON from [NAME] at path [PATH]

Return a named value at a path as JSON.

Block type: REPORTER. Opcode: getJsonAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$.name

structured data [NAME] has path [PATH]?

Report whether a path exists in named structured data.

Block type: BOOLEAN. Opcode: hasPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$.name

set [NAME] at path [PATH] to JSON [VALUE]

Immutably update a named value and replace its binding.

Block type: COMMAND. Opcode: setJsonAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$.name
VALUESTRING"Scratch"

delete path [PATH] from [NAME]

Immutably delete a path and replace its named binding.

Block type: COMMAND. Opcode: deleteAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$.name

keys in [NAME] at path [PATH]

Return sorted object keys as JSON.

Block type: REPORTER. Opcode: keysAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$

length of array in [NAME] at path [PATH]

Return the array length.

Block type: REPORTER. Opcode: lengthAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$

for each in [NAME] at path [PATH] max [MAX]

Iterate named data deterministically with a static maximum.

Block type: LOOP. Opcode: forEachAtPath. Permanent link

ArgumentTypeDefault valueMenu choices
NAMESTRINGdata
PATHSTRING$
MAXNUMBER100

When the fixed-input editor is enabled, MAX can be edited as a whole number from 1 to 1000. Partial, blank, or non-finite new values cannot be saved. NAME and PATH are not changed. The editor is off by default: enable both the blockEditorDialogs and blockEditorFixedInputs GUI startup options, then reload. Unchanged raw values are never rewritten, and connected reporters are never evaluated.

current key

Return the current object key or array index string.

Block type: REPORTER. Opcode: currentKey. Permanent link

This block has no arguments.

current index

Return the zero-based iteration number.

Block type: REPORTER. Opcode: currentIndex. Permanent link

This block has no arguments.

current value JSON

Return the current iteration value as JSON.

Block type: REPORTER. Opcode: currentValueJson. Permanent link

This block has no arguments.

Repository guide and examples