NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #3909 most downloaded on pub.dev
Run JavaScript widgets as Flutter widgets using QuickJS (VM) or Web Workers (web).
Last release 5 days ago
12 Sep 2026
Ships on a steady schedule
a new release about every 8 days
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
2 months old
113 releases · first in 2026
One column per month.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
Perf: micro-optimizations in JS bootstrap:
Fix JS widget cross-engine leaks on macOS/JSC:
Nothing published for this version
Fix callEvent deadlock: _handleEventDone was nulling _eventCompleter before _runEvent could complete it. On macOS (merged thread), JSC bridge callback
Nothing published for this version
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
Fix SIGSEGV: defer old runtime release until AFTER new runtime init completes (was releasing during init via scheduleMicrotask, which ran between eval
Fix dispose: use scheduleMicrotask instead of Future.delayed(Duration.zero) to avoid event-loop ordering issues that caused widgets to get stuck in lo
Fix SIGSEGV: defer native JSContextGroup release to the next event-loop turn. During run() → dispose() → evaluate(), the current stack may still be in
Fix 3D host-flip: remember per-sceneId host selection so controllers recreated after a callEvent timeout route to the same host (Flame3dHost stays Fla
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
feat(3d): unlit: true on declarative scene3d model entries — swaps the loaded GLB's SpatialMaterial for an UnlitMaterial with the same albedo, so flat
unlit: true on declarative scene3d model entries — swaps the
loaded GLB's SpatialMaterial for an UnlitMaterial with the same albedo, so
flat brand marks (logos, UI panels) render at their exact colors instead
of being dimmed by the scene light rig.fix(3d): the 3D host dispatcher reference-counts shared controllers — when a scene3d node unmounts and remounts within the same frame (per-frame scene
fix(3d): headless capture mounts the game tree manually and renders the world's children directly — an unmounted FlameGame renders and updates nothing
scene3d configs — models: [{modelId, src, position, rotation, scale, animation}] + camera + time applied
idempotently on every rebuild (diff-only), so video pipelines that
re-render the node tree per frame can drive GLB scenes frame-accurately.Js3dCaptureSync pending-work tracker lets headless renderers
wait for GPU init / model loads before capturing a frame.- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
- Automated patch bump.
The image node now sends a browser-ish User-Agent for network URLs: dart:io's default Dart/x.y (dart:io) UA is rejected by popular CDNs (Wikimedia ans
image node now sends a browser-ish User-Agent for network URLs:
dart:io's default Dart/x.y (dart:io) UA is rejected by popular CDNs
(Wikimedia answers HTTP 400), which made every remote image render as a
broken-image icon.Fix dead button/iconButton taps: _buttonActionId ignored the documented onPressed prop (SKILL.md and every bundled demo use it) and fired the _tap fal
button/iconButton taps: _buttonActionId ignored the
documented onPressed prop (SKILL.md and every bundled demo use it) and
fired the _tap fallback instead, so JS handlers keyed by action id never
matched. onPressed now takes priority, onTap stays supported.Chore: split json_widget_renderer.dart (~1900 lines) into part files under lib/src/renderer/nodes/ (js_layout_nodes.dart, js_text_nodes.dart, js_input
json_widget_renderer.dart (~1900 lines) into part files
under lib/src/renderer/nodes/ (js_layout_nodes.dart,
js_text_nodes.dart, js_input_nodes.dart) via private extensions, so
every source file is back under the 1500-line PR gate. Pure refactor — no
behavior or public API changes.Add a pure-Dart software 3D pipeline to the scene3d node: when the node carries a meshes prop it renders on CustomPaint — perspective-projected triang
scene3d node: when the node
carries a meshes prop it renders on CustomPaint — perspective-projected
triangles, painter's z-sort, flat Lambert shading — with zero native
dependencies and no Js3dHost required. Props: meshes
({vertices, faces, color}), camera (position, target, fov),
rotation (x/y/z static transform; JS animates by re-rendering on
raf/timer), light.direction, background, and onTap (fires with
{x, y} local coordinates). Nodes without meshes keep routing to the
host-provided Js3dHost engine. Malformed meshes/vertices/faces are
skipped, never fatal. See docs/3d-spike.md for the flutter_gl evaluation
and poly-budget guidance.Add 3D scene support via the new scene3d renderer node and jsr.scene3d.* JS API. The runtime provides a Js3dHost abstraction so host apps can plug in
scene3d renderer node and
jsr.scene3d.* JS API. The runtime provides a Js3dHost abstraction so
host apps can plug in any engine (Flame 3D, three_dart,
flutter_3d_controller, etc.).create, destroy, addModel, removeModel,
setTransform, playAnimation, stopAnimation, setCamera, setLight.id, width, height, camera, lights and renders a
placeholder when no Js3dHost is registered.3d-viewer example widget using flutter_3d_controller to load and
display GLB models.Add a textArea node to the JSON renderer: a multiline text input built on the same field machinery as textField. Props: value / initialValue, hint, mi
textArea node to the JSON renderer: a multiline text input built
on the same field machinery as textField. Props: value /
initialValue, hint, minLines (default 3), maxLines (default 8,
clamped to at least minLines; the field grows to maxLines then
scrolls internally), onChange (fires per keystroke with {value},
exactly like textField), and an optional onSubmit (shows a done
keyboard action and fires with {value}; without it Enter inserts a
newline). storageKey / id / name register the live value with the
field registry. The tree normalizer aliases textarea / TextArea and
applies the same prop aliases (placeholder, value, onChanged) as
textField.listView / gridView scrolling configurable. Both accept
shrinkWrap (bool, default true) and physics ('never' / 'always'
/ 'platform'). Defaults: listView is always scrollable; gridView
keeps its previous shrinkWrap: true + non-scrollable behavior for
backwards compatibility. Previously gridView was hardcoded to
shrinkWrap: true + NeverScrollableScrollPhysics. Follows the
renderer's input tolerance: shrinkWrap accepts 'true'/'false'
strings and numbers, unknown physics values fall back to the defaults.Fix and extend the chart node. It now reads its values from the documented data prop (points remains as a backwards-compatible alias), so apps passing
chart node. It now reads its values from the
documented data prop (points remains as a backwards-compatible alias),
so apps passing data no longer render an empty box. New props:
fillColor (hex with alpha allowed, e.g. #22c55e33; falls back to the
line color at ~20% alpha), strokeWidth (default 2), and chartType —
'line' (default, the existing sparkline) or 'bar' (equal-width bars
with rounded tops and a baseline). Follows the renderer's input tolerance:
unknown chartType falls back to 'line', non-numeric data entries are
skipped, empty data renders nothing.Add transition animation nodes to the JSON renderer. entrance plays a one-shot mount animation (animation: fade, slideUp, slideDown, slideLeft, slideR
entrance plays a
one-shot mount animation (animation: fade, slideUp, slideDown,
slideLeft, slideRight, scale, fadeScale; delay ms for staggered
list entrances, duration, curve) — implemented over
TweenAnimationBuilder with an Interval curve, so no timers are ever
scheduled. animatedSwitcher wraps Flutter's AnimatedSwitcher: when
switchKey changes between renders the old child animates out and the new
one in (animation: fade, slideLeft, slideRight, slideUp,
scale, fadeScale), keyed via ValueKey(switchKey). Both follow the
renderer's input tolerance: unknown variants fall back to fade, numeric
strings parse, garbage never crashes. The curve parser is now shared as
jsCurve in js_node_helpers.dart.Add a map node to the JSON renderer, built on flutter_map + latlong2 with OpenStreetMap tiles (no API key). Props: center {lat, lng}, zoom, markers [{
map node to the JSON renderer, built on flutter_map + latlong2
with OpenStreetMap tiles (no API key). Props: center {lat, lng}, zoom,
markers [{id, lat, lng, label?, color?}], polylines [{points, color?, width?}], and fitBounds (true to fit all markers/polylines, or an
explicit [[lat, lng], [lat, lng]] corner list). Events route through the
standard bridge: onTap fires with {lat, lng} and onMarkerTap with
{id}. JsonWidgetRenderer.mapTileProvider lets hosts/tests inject a
custom TileProvider so tile loading never has to hit the network.- Automated patch bump.
Renderer no longer crashes on malformed numeric props from generated widgets: jsDouble/jsDoubleOrNull now parse numeric strings, take the first numeri
jsDouble/jsDoubleOrNull now parse numeric strings, take the
first numeric element of a list, and fall back instead of throwing a cast
error (e.g. borderRadius: [14, 14, 0, 0] previously killed the whole
render tree). borderRadius in decorations, cards, inkWell and clipRRect
also accepts CSS-style corner lists ([all], [tl-br, tr-bl],
[tl, tr-bl, br], [tl, tr, br, bl]) via the new jsBorderRadius.Fix web compilation of JsWidgetEngine: _defaultBackend referenced FlutterJsWidgetEngineBackend unconditionally, but the conditional import resolves to
JsWidgetEngine: _defaultBackend referenced
FlutterJsWidgetEngineBackend unconditionally, but the conditional import
resolves to the Web Worker backend on the web, so any web build importing
the wrapper failed with "Method not found: 'FlutterJsWidgetEngineBackend'".
The platform pick now lives in a factory behind its own conditional import
(js_widget_engine_default.dart / js_widget_engine_default_web.dart).Fix JsWidgetBridge.callEvent for rapid-fire gestures: concurrent events (tap-down / tap-up / tap) raced on a single completer, so a stale __jsr_event_
JsWidgetBridge.callEvent for rapid-fire gestures: concurrent events
(tap-down / tap-up / tap) raced on a single completer, so a stale
__jsr_event_done completed the next event early and the following
callEvent crashed with "Future already completed", permanently wedging
event delivery (dead buttons in gesture-heavy widgets). Events are now
serialized through an internal queue, and __jsr_event_done handling is
take-and-null so stray/duplicate dones are ignored.Add pluggable JS engine backend:
JsWidgetEngineBackend interface.JsRuntimeConfig.backend lets hosts use a custom engine (e.g. QuickJS FFI).flutter_js on VM and Web Worker on web.video/audio nodes:
JsMediaHost, JsVideoController, JsAudioController interfaces.JsonWidgetRenderer.mediaHost wires real players while the core package
stays free of heavy native media dependencies.ExternalAssetResolver and JsonWidgetRenderer.externalAssetResolver
for external:<id> image sources.JsFontResolver, JsFontLoader, and the
fontFamily text style prop.Export UiViewTreeNormalizer from the public API so hosts can reuse the same React/HTML-style node-name aliases.
UiViewTreeNormalizer from the public API so hosts can reuse the same React/HTML-style node-name aliases.- Automated patch bump.
Add path node for SVG path stroking with optional progress animation.
path node for SVG path stroking with optional progress animation.absoluteFill node (alias fill) for expanded background fills.stack.fit support (expand / loose).offsetX/offsetY, scale, rotation, opacity, blur) on any node.style.gradient renders text with a gradient via ShaderMask.style.fontStyle: 'italic' supported in addition to italic: true.style.lineHeight aliases style.height.asset: and file: source prefixes.imageResolver callback for custom image providers.customBuilders map for host-defined node types.video and audio placeholder nodes.Add jsr.ease.* easing helpers (linear, easeIn, easeOut, easeInOut, bounce, elastic, backIn, backOut).
jsr.ease.* easing helpers (linear, easeIn, easeOut, easeInOut, bounce, elastic, backIn, backOut).gradient.type: 'radial').decoration.shadows).blur property on containers.clip: true on rounded containers.rotateX, rotateY, perspective) on containers.textTransform (uppercase/lowercase).BREAKING CHANGE: Rename global JS object and channels from yoloit to jsr.
yoloit to jsr.
jsr.render(), jsr.onEvent(), jsr.fetchJson(), etc.__jsr_ instead of __yoloit_.JsRuntimeConfig.hostBootstrapJs so hosts can inject host-specific APIs (e.g., jsr.yoloit = {...}) without polluting the core runtime.jsr API.AGENTS.md, CLAUDE.md, and agent skills for widget authoring and engine maintenance.- Automated patch bump.
Your coding agent can read these notes before it upgrades. Set up the MCP server →