TurboWarp Bubble Block Manual

This manual explains how to use turbowarp-bubble as an unsandboxed TurboWarp custom extension. A Bubble combines an SVG body, text, a character portrait, blinking and lip-sync layers, and an animated continue indicator.

Kamishibai DSL 4.0 bundle: In the combined runtime palette, click the documentation button directly below the Bubble member heading to open this manual. The bundled blocks keep the styles, placement, portrait, reveal, audio, wait, animation, clone, and cleanup behavior documented here; their member namespace and Bubble icon identify their origin.

A quick-start block sequence that registers Next1 and Next2 separately, prepares input listeners, then uses Bubble's integrated wait

1. Load the required extensions

The complete input-wait example uses five extensions. Add Temporary Variables from TurboWarp's extension library, then load the custom extensions needed by the selected features with Run without sandbox enabled. Bubble bundles the host-neutral SVG Text 0.8.1 layout provider and creates no text skin on its default SVG overlay. Asset Manager is required for portrait, lip-sync, continue indicator, voice, and display-sound assets. Async Input and Runtime Expression are required only for condition-based Bubble waits and close policies; a timeout-only close policy needs neither.

Order Extension URL
1 Temporary Variables Add from the TurboWarp extension library
2 Async Input 0.4.0 https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-async-input@0.4.0/dist/async-input.js
3 Runtime Expression 0.4.0 https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-runtime-expression@0.4.0/dist/runtime-expression.js
4 Asset Manager 0.12.1 https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-manager@0.12.1/dist/asset-manager.js
5 Bubble 0.10.0 https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-bubble@0.10.0/dist/turbowarp-bubble.js

To try a development build, load this repository's dist/turbowarp-bubble.js as a local custom extension. Bubble reports an explicit error if the renderer lacks the default SVG overlay APIs, if an image/media feature is used without Asset Manager, or if Async Input or Runtime Expression is missing when it starts a condition-based Bubble wait. The lower-level Composition API can inject another text capability.

See also:

2. Prepare portrait assets

The following example stores costumes in a hidden asset sprite named Assets.

Costume Asset Manager name Contents
HeroFace HeroFace Face, hair, and outline, excluding the animated eyes/mouth
HeroEyesOpen HeroEyesOpen Transparent overlay containing only the open eyes
HeroEyesClosed HeroEyesClosed Transparent overlay containing only the closed eyes
HeroMouthClosed HeroMouthClosed Transparent overlay containing only the closed mouth
HeroMouthOpen HeroMouthOpen Transparent overlay containing only the open mouth
Next1 Next1 First frame of the continue indicator
Next2 Next2 Second frame of the continue indicator

Use the same canvas size and center point for the base, eye, and mouth images. Keep overlay backgrounds transparent; mismatched canvases or centers make the layers drift when composed.

Register each costume with Asset Manager:

register resource [costume:Assets:HeroFace] as asset [HeroFace]
register resource [costume:Assets:HeroEyesOpen] as asset [HeroEyesOpen]
register resource [costume:Assets:HeroEyesClosed] as asset [HeroEyesClosed]
register resource [costume:Assets:HeroMouthClosed] as asset [HeroMouthClosed]
register resource [costume:Assets:HeroMouthOpen] as asset [HeroMouthOpen]
register resource [costume:Assets:Next1] as asset [Next1]
register resource [costume:Assets:Next2] as asset [Next2]

For a remote image, pass its HTTPS URL as RESOURCE_ID. Bubble accepts only assets already registered with Asset Manager whose MIME type is image/*.

3. Select a text layout style

Standalone Bubble bundles the SVG Text 0.8.1 layout composition and installs two Bubble styles: say owns the speech body and speech tail, while think owns the thought body and round trail. A style's body and tail/trail shapes are one visual choice, not separately selected properties. The short say [MESSAGE] and think [MESSAGE] blocks select the matching style automatically, so the basic path needs neither a style definition nor a style input. Both styles use the reserved text profile default, a content-sized body, 14px Helvetica text, right-first placement with a fit-dependent left flip, 330-character block-input limit, and empty-message close behavior. Their 4px SVG stroke is painted before the white fill, hiding the inner half so the visible outline matches TurboWarp's standard bubble. Any other text style name or explicit style-setting block selects the custom profile. Custom text styles are initialized on first use with transparent-background SVG Text defaults. If a project separately loads the stock SVG Text 0.8.1 extension before Bubble, Bubble uses its public getLayoutCapability() instead and preserves the named styles defined by SVG Text blocks. An older loaded SVG Text extension without that handoff produces an explicit compatibility error rather than silently replacing the style; select the documented scratch-render fallback only when needed.

define bubble style [hero-dialogue] using text style [default]

Application hosts that need custom fonts, colors, or alignment can define styles on createSvgTextLayoutComposition() and inject them through createSvgTextOverlayTextCapability(). The custom profile uses the same layoutText() API and does not create an SVG text skin on the default overlay backend. Bubble owns placement, tail, and outer shape.

4. Define a Bubble style

For a basic Bubble, use the short blocks directly. They select the built-in Bubble styles say and think, respectively:

say [Hello!]
think [Hmm…]

TurboWarp standard comparison

These screenshots come from one TurboWarp Editor project using the English UI, a Cat sprite at x=-80, y=0, size 80%, a white Stage, and matching Hello! / Hmm... inputs. The standard Looks blocks are on the left. Bubble's short basic blocks are on the right and use their matching built-in say / think styles; no definition or setter block is used.

TurboWarp standard say and think bubbles compared on the Stage with Bubble's basic profile

The Stage panels show the right-side placement, content-sized body, and the speech tail or thought trail pointing back toward the Actor in each implementation. Bubble renders an independent SVG surface, and every panel is a crop of the actual TurboWarp Stage.

TurboWarp standard say and think blocks compared with Bubble's no-setup basic say and think blocks and built-in default profile values

The block image shows the no-setup path and the unified custom-style block. The short blocks select the matching built-in styles automatically. The callout shows each inseparable body-plus-tail/trail pair, maps both styles to the reserved text profile default, and lists the shared typography, geometry, colors, border paint order, and placement. Use show [MESSAGE] with bubble style [STYLE] for named custom styles. The former styled say/think opcodes remain hidden compatibility definitions for saved projects.

The following setters intentionally switch the style to the custom profile:

define bubble style [hero-dialogue] using text style [default]
set bubble placement [up-right] for bubble style [hero-dialogue]
set bubble distance [12] for bubble style [hero-dialogue]
set bubble visual style [NORMAL] for bubble style [hero-dialogue]
set bubble tail length [18] for bubble style [hero-dialogue]
set bubble offset x [0] y [0] scale [100] % for bubble style [hero-dialogue]

Actor-relative and stage-relative placement

Actor-relative 16-way and angle placement compared with three stage-relative placements

Each of the 16 actor-relative directions is shown as a complete mini-scene containing an actor, Bubble body, tail, and text. The two tail-base points lie on the body border. The renderer uses a JSClipper union to produce a single path, so no internal border remains at the join.

The three stage-relative diagrams show the Stage frame, safe area, Bubble dimensions, horizontal centerline, and relevant reference edge or center. The diagrams and the TurboWarp drawable are generated by the same shared renderBubbleSvg implementation.

Actor-relative placement applies to the custom profile and specifies the direction from the actor's center toward the center of the entire Bubble. The untouched basic profile uses Scratch's right-first placement and automatic left flip. The menu provides these 16 canonical directions:

up / up-up-right / up-right / right-up-right
right / right-down-right / down-right / down-down-right
down / down-down-left / down-left / left-down-left
left / left-up-left / up-left / up-up-left

Compass aliases such as north, north-northeast, and northeast may also be typed directly or supplied by a reporter. A number uses Scratch direction semantics from 0 through 360 degrees: 0 is up, 90 right, 180 down, 270 left, and 360 normalizes to 0. Arbitrary angles are not rounded to the 16 menu directions. The default is up-right.

Stage-relative placements do not point at an actor and are positioned within the Stage safe area.

Placement Position
HEADER_LIKE Top of the Stage safe area, centered
CENTER Horizontal and vertical center of the Stage
FOOTER_LIKE Bottom of the Stage safe area, centered

These placements do not depend on actor coordinates, bounds, or visibility. Use one of them when running say or think from the Stage. A stage-relative Bubble has no actor-pointing tail.

Actor distance, tail, body offset, and scale

Real Bubble SVGs comparing distance, tail length, offset, and scale

Scale applies to the body, SVG Text, portrait base, blink/lip-sync layers, continue indicator, and internal padding as one unit, so the displayed font size scales by the same factor. When scale alone changes, the body center moves away from the actor by the increase in radius, preserving the actor-side gap. The x/y offset is added afterward. The tail tip remains fixed and the union with the body border is regenerated, so an offset can change the effective tail length.

Near a Stage edge, keeping the scaled Bubble on-screen takes priority and can reduce the requested distance. Actor-relative distance, tail, offset, and scale settings do not apply to HEADER_LIKE, CENTER, or FOOTER_LIKE.

Width, automatic wrapping, and Japanese line-breaking rules

Automatic wrapping at different maxWidth values and Japanese line-breaking examples

The diagram is generated by running the production wrapText implementation. @cto.af/linebreak supplies Unicode UAX #14 break opportunities, which are filtered against Intl.Segmenter grapheme boundaries. The renderer then chooses the last candidate that fits the measured width. It avoids unnatural breaks before punctuation, closing brackets, small kana and prolonged sound marks, and inside a combined emoji grapheme.

Bubble visual styles

Ten Bubble visual styles rendered by the production SVG renderer

Available shapes are NORMAL, THINKING, DREAMING, YELLING, OFF_PANEL, WAVY, WHISPERING, ANNOUNCEMENT, NARRATION, and NO_BUBBLE.

set bubble visual style [YELLING] for bubble style [hero-dialogue]

The diagram and TurboWarp drawable both use Bubble's shared renderBubbleSvg function. Shapes with triangular tails use a platener/jsclipper union between the body and tail. THINKING and DREAMING use circular trails and are excluded from that union. Actor-relative placement points the tail toward the actor; stage-relative placement has no tail. NO_BUBBLE hides the body drawable and displays only text, portrait, and other layers.

The default visual style is NORMAL. The body drawable is created before text and portrait drawables so it remains behind them. close this bubble, target/clone disposal, and runtime disposal release the body drawable and its owned SVG skin.

NEGATIVE is not a separate style because it can be expressed with fill and border colors. Orientation and segments are also not public inputs; dimensions are calculated from width, font, character count, and the number of lines after wrapping.

Now configure the portrait and continue animation layers:

set portrait base [HeroFace] for bubble style [hero-dialogue]
set portrait [top-left] offset x [-4] y [6] zoom [120] % corner radius [12] px for bubble style [hero-dialogue]

set blink frames [HeroEyesOpen,HeroEyesClosed]
  every [0.4] seconds for bubble style [hero-dialogue]

set lip-sync frames [HeroMouthClosed,HeroMouthOpen]
  every [0.1] seconds for bubble style [hero-dialogue]

set continue frames [Next1,Next2]
  every [0.2] seconds for bubble style [hero-dialogue]

ASSETS is a comma-separated list of Asset Manager names. Surrounding whitespace is removed; commas cannot be part of an asset name.

5. Sequential reveal, audio, and layout

Bubble can reveal a message as CHARACTER, WORD, LINE, or BLOCK units. WORD does not perform morphological analysis; it uses whitespace or the configured delimiter character set. Delimiters can remain visible or be hidden.

set bubble reveal unit [CHARACTER] every [0.05] seconds layout [RESERVED] for bubble style [hero-dialogue]
set bubble word delimiters [ /] show [false] for bubble style [hero-dialogue]
set bubble reveal sound [Typewriter] for bubble style [hero-dialogue]
set bubble voice [HeroVoice] for bubble style [hero-dialogue]
show [Let's head for the sea!] with bubble style [hero-dialogue]
finish [CHARACTER] with condition [input == "pressed"] or timeout after [10] seconds

DYNAMIC recalculates the Bubble size and placement after each unit. RESERVED measures the final text first and reserves that layout while units appear. set bubble reveal sound plays a named Asset Manager audio asset per unit, while set bubble voice plays full voice audio when the Bubble starts. Text display remains available without audio.

6. Show dialogue and wait for input

say and think show a Bubble immediately, continue to the next block, and begin in talking animation mode.

set runtime variable [input] to []
listen for key [Space] set runtime var [input] to [pressed]
listen for touch on this sprite set runtime var [input] to [pressed]
show [Let's head for the sea!] with bubble style [hero-dialogue]
wait with this bubble until condition [input == "pressed"] or timeout after [10] seconds
close this bubble

Initialize input with Temporary Variables before registering the Async Input listeners. The listeners update that runtime variable when Space is pressed or the sprite is tapped. The Bubble wait delegates input == "pressed" to Runtime Expression immediately and once per VM frame. While waiting it automatically enters awaiting-continue, stops lip-sync, and loops the images configured by set continue frames. When the condition becomes true or the timeout expires, it enters idle and continues to close this bubble. Set the timeout to 0 to wait without a timeout.

Reset input to an empty string before each later wait; otherwise the previous pressed value makes the next condition succeed immediately. Starting another Bubble, closing it, stopping its target, restarting or stopping the project, and disposing the runtime all cancel the target-owned wait and release its listener and timer.

Use a named Bubble close policy when the same closing rule is reused. The trigger is explicit: condition, timeout, or condition-or-timeout. Applying a policy snapshots its definition, waits, runs the Bubble's hide animation, and releases the Bubble in one blocking command.

define bubble close policy [advance-or-timeout] trigger [condition-or-timeout] condition [input == "pressed"] timeout [10] seconds
show [Let's head for the sea!] with bubble style [hero-dialogue]
wait and close this bubble using close policy [advance-or-timeout]

A timeout-only policy leaves the current animation mode unchanged and needs no input extension. A policy containing a condition enters awaiting-continue and uses the same Async Input and Runtime Expression setup as the integrated wait. Redefining the same name during a pending wait affects only later applications. Bubble replacement or lifecycle cleanup cancels the pending policy and does not close the replacement Bubble.

When combining Bubble with audio or a separate text-reveal system, switch to awaiting-continue when that process completes.

A say Bubble lip-syncs, shows continue frames while awaiting continue, then closes after input

If animated GIF playback is unavailable, use this static animation-mode comparison:

Blink, lip-sync, and continue-frame states in talking, awaiting-continue, and idle modes

7. Bubble animation modes

Mode Blink Lip-sync Continue frames Typical use
talking Runs Runs Hidden Dialogue display or audio playback
awaiting-continue Runs Stops/hidden Loops Await the user's request to continue
idle Runs Stops/hidden Stops/hidden Keep a Bubble visible and still

set this bubble animation mode [MODE] changes only the Bubble owned by the calling sprite, clone, or Stage. It reports an error if that target has not first run say or think.

8. Show, in-display, and hide animations

Use fadeIn, floatIn, zoomIn, or riseUp when a Bubble starts displaying, and fadeOut, floatOut, zoomOut, or sink when it finishes displaying. These animations work with both DYNAMIC and RESERVED layout.

set bubble show animation [fadeIn] for [0.2] seconds for bubble style [hero-dialogue]
set bubble hide animation [fadeOut] for [0.2] seconds for bubble style [hero-dialogue]
animate this bubble [shake]
shake this bubble direction [90] count [2] ease [easeInOut]
explode this bubble relative scale [1.15] count [2] ease [easeOut]
animate bubble shape to [WAVY] speed [1] for [0.5] seconds

The TurboWarp adapter advances these motions on scheduler frames and applies ease to each frame. shake applies direction and count to the complete Bubble surface, explode expands and returns the relative scale of text and portrait together, and animate bubble shape cross-fades the current outline into styles such as THINKING, DREAMING, YELLING, WAVY, or WHISPERING during the requested speed and duration.

Use close this bubble to remove the current Bubble. It runs the configured hide animation and then releases the Bubble's timers and rendering resources. set bubble hide animation ... only configures that exit effect; it does not remove a Bubble by itself. For the built-in basic profile, passing an empty value to say or think also closes the Bubble, matching TurboWarp's standard behavior. Bubble does not expose a separate hide block because closing destroys the display rather than preserving a hidden instance for later reuse.

9. Showing a named Bubble style

show [MESSAGE] with bubble style [STYLE]

The selected Bubble style determines the body and tail/trail together, along with its text profile, portrait layers, placement, and animation settings. set bubble visual style selects an inseparable pair such as NORMAL (speech body + speech tail) or THINKING (thought body + round trail); there is no independent tail-shape setting. The standalone extension derives its internal rendering kind from that style instead of asking the display block for a second, potentially conflicting choice.

Running a new say or think on the same sprite, clone, or Stage disposes the previous Bubble and its timers/drawables before replacing it. The Stage supports stage-relative placement only.

10. Using Bubble with clones

Bubble style definitions are shared within the extension, but each sprite or clone owns its currently displayed Bubble.

  1. Define assets and styles once from the original sprite when the green flag is clicked.
  2. Run say or think from each clone itself.
  3. Change the animation mode and close the Bubble from the same clone that displayed it.

When a clone stops or is deleted, its timers, overlay DOM, and image leases are released automatically. Explicit scratch-render mode also releases skins and drawables.

11. Block reference

Block Description
define bubble style [STYLE] using text style [TEXT_STYLE] Define or redefine a Bubble style
define bubble close policy [POLICY] trigger [TRIGGER] condition [CONDITION] timeout [TIMEOUT] seconds Define or replace a named closing condition
set bubble placement [PLACEMENT] for bubble style [STYLE] Set an actor direction/angle or a stage-relative region
set bubble distance [DISTANCE] for bubble style [STYLE] Set the distance from actor bounds to the tail tip
set bubble visual style [VISUAL_STYLE] for bubble style [STYLE] Select one of ten inseparable SVG body + tail/trail pairs
set bubble tail length [LENGTH] for bubble style [STYLE] Set the nominal border-to-tip tail length
set bubble offset x [X] y [Y] scale [SCALE] % for bubble style [STYLE] Set body position and whole-Bubble scale, including text
set portrait base [ASSET] for bubble style [STYLE] Set the portrait base image
set portrait [PLACEMENT] offset x [X] y [Y] zoom [ZOOM] % corner radius [RADIUS] px for bubble style [STYLE] Set portrait visibility, edge/corner placement, transform, and rounding
set blink frames [ASSETS] every [SECONDS] seconds for bubble style [STYLE] Set blink overlays and interval
set lip-sync frames [ASSETS] every [SECONDS] seconds for bubble style [STYLE] Set lip-sync overlays and interval
set continue frames [ASSETS] every [SECONDS] seconds for bubble style [STYLE] Set the animation shown during awaiting-continue
set bubble reveal unit [UNIT] every [SECONDS] seconds layout [LAYOUT] for bubble style [STYLE] Configure CHARACTER/WORD/LINE/BLOCK sequential reveal
set bubble word delimiters [DELIMITERS] show [SHOW] for bubble style [STYLE] Configure WORD delimiters and visibility
set bubble reveal sound [ASSET] for bubble style [STYLE] Set the per-unit reveal sound
set bubble voice [ASSET] for bubble style [STYLE] Set full voice played when display starts
finish [UNIT] with condition [CONDITION] or timeout after [TIMEOUT] seconds Reveal remaining units and wait for condition or timeout
set bubble show animation [MOTION] for [SECONDS] seconds for bubble style [STYLE] Configure show animation
set bubble hide animation [MOTION] for [SECONDS] seconds for bubble style [STYLE] Configure hide animation
animate this bubble [MOTION] Play a whole-Bubble animation
shake this bubble direction [DIRECTION] count [COUNT] ease [EASE] Shake the complete Bubble surface
explode this bubble relative scale [SCALE] count [COUNT] ease [EASE] Apply relative scale cycles to the Bubble
animate bubble shape to [VISUAL_STYLE] speed [SPEED] for [SECONDS] seconds Transition the Bubble outline
say [MESSAGE] Show built-in style say: speech body and speech tail
think [MESSAGE] Show built-in style think: thought body and round trail
show [MESSAGE] with bubble style [STYLE] Show the complete body and tail/trail pair owned by a style
set this bubble animation mode [MODE] Select talking, awaiting-continue, or idle for this Bubble
wait with this bubble until condition [CONDITION] or timeout after [TIMEOUT] seconds Await a Runtime Expression condition or optional timeout
wait and close this bubble using close policy [POLICY] Snapshot a policy, wait for it, and close the Bubble
close this bubble Release this target's Bubble and owned resources
Bubble version Report the Bubble implementation version

Saved projects using the former say/think [MESSAGE] with bubble style [STYLE] opcodes continue to run, but those two compatibility blocks are hidden from the palette. New scripts use the unified show block so the selected style alone determines the complete body and tail/trail shape.

12. Troubleshooting

Symptom Cause and solution
Asset Manager required error Load Asset Manager 0.12.x without sandbox before using image/media assets
SVG overlay backend error Use a host with renderer.addOverlay() or explicitly select scratch-render
Async Input required error Load Async Input 0.3.x without sandbox before using the Bubble wait
Runtime Expression required error Load Runtime Expression 0.3.x without sandbox before using the Bubble wait
bubble style is not defined Use the built-in short say/think blocks, or define the named custom style first
bubble close policy is not defined Define the named close policy before applying it
Image asset is not registered Wait for register resource ... as asset ... before showing the Bubble
Asset is not an image Confirm MIME type of asset [NAME] is image/*
Only one continue frame Supply at least two frames, or clear the setting
Frame interval error Use a finite SECONDS value greater than zero
Actor-relative Bubble from the Stage Use HEADER_LIKE, CENTER, or FOOTER_LIKE
Invalid placement Use a 16-way direction, alias, 0–360 degree angle, or stage-relative value
Eyes or mouth are misaligned Match canvas size, center, and transparent area across all portrait layers

13. Automatic cleanup

Bubble automatically releases its owned timers, overlay DOM, and image leases in the following cases. Explicit scratch-render mode also releases its text skins and renderer drawables.

Assets registered with Asset Manager are not owned by Bubble. To remove an unused registered image from memory, close the Bubble first and then use Asset Manager's delete asset [NAME] from memory block.

14. Regenerating the manual assets

The diagrams and GIF are generated from scripts in this repository. GIF generation requires the ImageMagick magick command.

The two turbowarp-say-think-*-comparison.png files are real TurboWarp Editor screenshots rather than generated renderer previews. They use the capture conditions documented in section 4 and are not overwritten by docs:render.

pnpm docs:render
pnpm docs:check

docs:check verifies SVG viewBoxes, production-renderer and wrapText markers, every visual style, the GIF dimensions/frame count/loop setting, references to all images and 16 blocks in both language manuals, and that the generated GitHub Pages HTML is current.