fluvie 0.3.1
fluvie: ^0.3.1 copied to clipboard
Write a video like a Flutter screen: declarative widgets in, a real video file out. No timelines to scrub, no frame math.
Changelog #
The format follows Keep a Changelog and the versions follow Semantic Versioning.
[Unreleased] #
0.3.1 - 2026-07-16 #
0.3.0 - 2026-07-15 #
The single-file release. A composition is a file with a top-level
Video build(), and renderVideo is the one capture entry a host drives.
See the migration guide.
Added #
renderVideoonpackage:fluvie/rendering.dart: the one capture entry a host drives. It takes aVideoand derives geometry, media, audio, captions, and reactive audio from it; the host supplies onlypumpWidget,pumpFrame,setViewSize, andrunAsync. Encoding stays out of it: the returnedRenderManifestcarries the complete ffmpeg argument array.SetViewSize,ShellRunAsync, andrunAsyncDirectlyon the rendering barrel: the host seamsrenderVideotakes.parseAspect,parseQuality,parseExportFormat,parsePosterTime, andwriteRenderProgressare now public onpackage:fluvie/rendering.dart, so a generated harness turns CLI defines into typed arguments without reaching intosrc/.LivePlayerandLivePlaybackController: clock-driven live playback of a composition (play, pause, seek, hold, playRange, rate) on the same frame pipeline capture uses.introspectTimeline: the resolved timeline as data, with per-element windows and lookups by anchor, key, or widget.LocalMotionScope: mount animated content under aVideoafter the composition resolved, on its own frame base.
Fixed #
- WebM/VP9 clips work, including alpha. A
.webmfailed the probe because Matroska stores nonb_framesand no per-stream duration; the frame count is now counted with a-count_framespass, falling back to duration times frame rate. The pass runs only for a container that stored no count, so an MP4 never pays it. - VP9 alpha is no longer silently dropped. VP9 codes alpha as a second layer
that only
libvpx-vp9reads; ffmpeg's nativevp9decoder ignored it and the clip composited over black. A VP9 stream taggedALPHA_MODE=1now selectslibvpx-vp9. An opaque VP9 clip stays on the native decoder, which is much faster. LivePlaybackControllersurvives a ticker restart: when a remountedLivePlayerhands it a fresh ticker (elapsed starts over at zero), the clock rebases at the current frame and carries on instead of rewinding to frame 0 and replaying.
0.2.0 - 2026-07-06 #
The API restructuring release. Old names are gone, not deprecated; every rename is mechanical. The full map lives in the migration guide.
Changed #
- Barrel split.
package:fluvie/fluvie.dartkeeps only the authoring surface; the pipeline moved to the newpackage:fluvie/rendering.dart(RenderService,RenderConfig,render,renderToSandbox,renderTemplate, sandboxes, capture services, resolver contracts,resolveAudioMix, collectors,FadeBox, the wasm runtime,FfmpegVersion).NumberFormatis no longer re-exported; importpackage:intl/intl.dartyourself. FfmpegProviderandffmpegProviderProviderare nowFfmpegRunnerandffmpegRunnerProvider, which selects the platform runner throughFfmpegRunnerRegistry;RenderService.render(provider:)isrender(runner:).Trigger.afteris nowTrigger.whenEnds, the parallel twin ofTrigger.whenStarts; the spec kind"after"fails with a rename hint.- One reveal vocabulary. Charts (
growIn/drawIn/sweepIn/popIn),Counter(duration:), and annotations (drawIn/slideIn) all takereveal:. Animation.slideFadeisslideFadeIn;Animation.maskWipeismaskWipeIn; ambient presets takeperiod:(spin(per:)andfloat(frequency:)are gone).Timelineno longer takes anfps; it resolves at the enclosingVideo's fps, so a 60 fps video can no longer silently mistime a schedule.timeline.placementsisplacementsAt(fps).- The decorative photo mat
Frameis nowPhotoFrame; "Frame" always means the render clock (FrameBuilder,n.frames,RawFrame).
Added #
- The
VideoRenderer<T>render contract andDesktopVideoRenderer;OnDeviceVideoRendererandWebVideoRendererimplement the same shape. - Preset mirrors
scaleOut,glitchOut,slideFadeOut, andmaskWipeOutcomplete every directional In/Out pair.
Fixed #
- Offscreen capture wraps the composition in an ambient
Directionality, so a headless render no longer fails when the tree provides none.
0.1.10 - 2026-06-24 #
Added #
- Generative-media prerender seam. Declare AI-generated visual and audio sources
with
GenerativeMedia/GenerativeAudio(GenerativeSource,GenerativeKind,GenerativeCarrier) and resolve them before the frame loop through the newGenerativeResolvercontract (generativeResolverProvider, defaulting toNoGenerativeResolver).collectGenerativeSourcesplus the now generative-aware media, clip, clip-audio, and audio collectors fold each produced file back in as a plainMediaSource.file/AudioSource.file, so a generated video (with Veo 3 audio) and generated music mix and stay in sync like local assets. The render orchestrators run generation before media pre-resolution; the real backend lives influvie_ai. - The default FFmpeg render now mixes a clip's embedded audio.
render()probes every clip and the encoder stages the audio of any clip that carries a track (regularClipor a generated video such as Veo 3), delayed to its scene window.ClipMetadatagainedhasAudio(the probe reports it) so a silent clip is never given a broken audio map. render()andrenderToSandbox()acceptonGenerativeProgressto surface per-asset generation progress (GenerativeProgress) before the frame loop.
0.1.9 - 2026-06-23 #
Lockstep maintenance release; demo (mobile layout) and CI fixes only, no library changes since 0.1.8.
0.1.8 - 2026-06-23 #
Lockstep maintenance release; demo and deploy fixes only, no library changes since 0.1.6.
0.1.7 - 2026-06-23 #
Lockstep maintenance release; demo and deploy fixes only, no library changes since 0.1.6.
0.1.6 - 2026-06-23 #
Lockstep maintenance release; no functional changes since 0.1.5.
0.1.5 - 2026-06-23 #
Added #
- Non-fatal spec diagnostics: an unknown spec property is surfaced on the default render path instead of being silently dropped, backed by the JSON-schema variants and defs.
- A pluggable
ClipFramePreparercontract so a host can pre-resolve clip frames without ffmpeg.
0.1.4 - 2026-06-22 #
Added #
- In-browser rendering paints declared image media. A
dart:io-freeWebImageMediaResolver(selected bymediaResolverProvideron web) resolves and decodes asset, network, and memoryImagesources before the frame loop, andrenderToSandboxaccepts an injected resolver. Audio, snapshots, and captions are not supported on web yet and fail with a clear typed error. - On-device video
Clipsupport, shared across desktop and web. AClipResolveCachemixin probes a clip, plans the source frames its scene window reads (planClipFrames), extracts and caches them, and serves them synchronously per frame; a clip pre-pass (preResolveCompositionClips) runs before the frame loop in every render entry point. The browser decodes through an injectedWebClipDecoder(WebCodecs), wired bywebClipDecoderProvider; with no decoder a clip fails with a clear typed error. - Shared on-device render primitives so the mobile and web encoders stay thin and
consistent:
RenderPhase+RenderProgress/RenderProgressCallback,frameCountFor,runGuarded(cleanup that never masks the render error),runStage(stamps a stage onto a thrownFluvieRenderException),DisposableResolver, andresolverScope. FluvieRenderException.stagerecords whether a failure happened while capturing or encoding.- Media resolvers (
MediaRepository,WebImageMediaResolver) nowdispose()their decoded images, freeing native memory instead of waiting for GC.
0.1.3 - 2026-06-22 #
Added #
- Off-screen renders can pre-resolve a composition's declared media: an injected
MediaResolverdecodes and caches theImage/Clipsources before the first frame, so the on-device mobile and web renderers can paint declared media.
0.1.2 - 2026-06-21 #
Added #
- On-device audio: audio sources and a resolved audio-track model, mixed through the deterministic encode path, including looping audio beds.
- A render-sandbox seam with file and in-memory backends, so a composition can be captured to disk or to memory for the on-device mobile and web renderers.
Changed #
- The render service stages audio and frames through the sandbox and runs a dedicated frame-capture loop, in place of the previous single render loop.
0.1.0 - 2026-06-20 #
The first public release. The API is feature-complete and well tested; the 0.x
line means it can still change before 1.0, so pin a version.
Added #
- The declarative composition model:
Video,Scene,Scene.sequence,Scene.centered,Background.*, and theDefaultscascade. - The timing engine:
Timeextensions,Anchor,Trigger, frame resolution, and a deterministic resolved timeline. - Animation:
.animate([...]), the preset menu,Animation.from/to/keyframes, springs,Stagger, andRepeat. - Elements:
Text,Typewriter,Counter,Image,Clip,Timeline,Chart,Code,Terminal,Markdown,Mermaid,WebView,Html, annotations. - Effects: pixel post-effects, seeded particles,
maskWipe, parallax, ambient motion, and shader animations. - Transitions, shared-element morphs, and a scene-wide
Camera. - Audio and captions:
Audio.music/sfx, beat detection, reactive inputs, SRT and VTT captions. resolveAudioMix: the encoder-neutralResolvedAudioMix/ResolvedAudioTrackview of aVideo's audio (the same timing math the FFmpeg mix uses) for custom encoders such asfluvie_mobile_encoderandfluvie_web_encoder.- Looping music beds in the FFmpeg path (
-stream_loop), so a short bed fills the whole video on the desktop, server, and web. Thedart:io-freerenderToSandboxaccepts audio through an injectedAudioByteLoaderandstageResolvedAudioToSandbox, the seam the in-browser encoder mixes through;NetworkAllowlistis now exported for on-device network audio. - The power layer:
FluvieTheme,Adaptiveand multi-aspect render, templates, theFrameBuilderescape hatch, andExport.*modes. - Content-hash media caching, so an unchanged frame is read from cache rather than redrawn.