Repository navigation
Releases: oxygenframe/oxframe-sdk
Release list
v0.23.8: Release 0.23.8: checks in the browser build (#45)
Added
- The browser build of a project can run the checks: the wasm module exports
check(the report and the storyboard PNG),inspectand a frame as PNG.
The remote MCP server at mcp.oxframe.dev uses them to check a scene
without a local install.
v0.23.7: Release 0.23.7: recorded voice-overs (#43)
Added
- Voice-overs you recorded yourself:
voice("…").recording("vo/intro.wav")
plays the file instead of calling a speech provider, and the line lasts as
long as the file.oxframe transcribe vo/intro.wav(oxframe-cli) times
its words with whisper.cpp on your machine and writes
vo/intro.words.json, soline.at_word("…")and.caption()follow the
recording. Without that file the words are spread over its length.
v0.23.6: Release 0.23.6: keep MixRequest compatible; check-semver (#41)
Fixed
- Projects on oxframe 0.23.0–0.23.4 build again. 0.23.5 added a field to
oxframe_export::MixRequest, and since a project'soxframe-export
resolves to the newest 0.23.x, the olderoxframestopped compiling. The
target loudness is now an argument:oxframe_export::mix_with_loudness.
0.23.5 is yanked;oxframe upgrademoves a project to 0.23.6.
v0.23.5: Release 0.23.5 (#40)
Added
-
No ffmpeg installed?
oxframe renderdownloads a static build once into
the oxframe cache and uses it (oxframe-cli);oxframe ffmpegdoes it
ahead of time. -
Six more blocks for
oxframe add(oxframe-cli), 24 in all: metric-row,
key-combo, steps, social-post, split-screen and search-bar. -
voice("…").caption(): the line is shown at the bottom of the frame
while it is spoken, up to seven words at a time, each part on screen
while its words are said (word timings from the provider, or the
estimate). Captions burned into the video, for feeds that play muted. -
oxframe check: most issues carryfix, the change that clears them with
the numbers worked out —movebydx/dypixels,shrinkto a size,
a textcolor(the same hue, lightened or darkened) and thecontrastit
reaches,widenby pixels or afont_scale,holdorslowin seconds.
The hints say the same in words ("Move it 140 px to the left").lint::Fix
in Rust. -
Project::loudness, say at -14 LUFS: the rendered sound (music, voice
and effects) is brought to that integrated loudness (EBU R128) before the
-1 dBFS limiter, so a video plays as loud as others on YouTube or in a feed.
renderprints the loudness of every mix;oxframe_export::loudness
measures one. -
GIF export:
render --format gif(or--out demo.gif) writes a looping
GIF with one palette for the whole clip and an ordered dither that does
not shimmer. It is 720 pixels wide and 15 fps unless--sizeand--fps
say otherwise; frames are taken from the project's rate, so only the
frames the GIF shows are rendered. No sound.Format::Gifin
oxframe-export.
v0.23.4: Release 0.23.4 (#33)
Added
oxframe mcp --dir(oxframe-cli): serve the project at a given path, not the
current directory, for MCP clients that start servers elsewhere.
Fixed
oxframe checkno longer reportsdead_timewhile aVideoplays: the
clip frame it shows counts as change (inspectlists it as theframe
param). A paused or finished clip still counts as a still shot.
v0.23.3: Merge pull request #31 from oxygenframe/release-0.23.3
Added
- Six more blocks for
oxframe add(oxframe-cli):feature-grid,
checklist,comparison,chat-messages,pull-requestand
countdown, eighteen in all, every one passingoxframe check. - The agent skill: a request to explain or show something means a scene,
not an answer in chat; hints for the compile errors seen most in the
0.23.2 agent eval. No SDK code changed.
v0.23.2: Merge pull request #30 from oxygenframe/release-0.23.2
Added
oxframe publish(oxframe-cli): renders the project, or takes an MP4,
uploads it to oxframe.dev and prints a link with a player that unfolds as
a video in Discord and Slack. Up to 30 s and 16 MB (a larger render is
re-encoded at 720p); kept for 30 days.--titlenames the page. No SDK
code changed; the agent skill knows the command.
v0.23.1: Merge pull request #29 from oxygenframe/release/0.23.1
Added
- Custom WGSL shaders (
Shader::source,Shader::file, and their
Input::frame()andInput::nodeinputs) paint in the browser
playground too: the CPU interpreter is built for wasm. A 1080p frame
takes about 0.3 s there; playback skips frames to keep time. The browser
bundle grows by about 360 KB gzipped.
v0.23.0
Added
- Components convert to
Node(From<X>andFrom<&X>):Axes,Callout,
CodeExplainer,FlowDiagram,LowerThird,ChapterMarker,Matrix,
Table,TitleCard,EndCard,BulletListgo wherever a node does, e.g.
caption.next_to(&end_card, Side::Bottom). Txt::font_size,Txt::weightandCode::font_sizetake integers too:
.font_size(64)..scale(..)on a builder takes one number, a pair or aVec2:
.scale(1.5),.scale((2.0, 0.5)),.scale(2).oxframe check:low_contrastreads the pixels behind text that lies
over a shader, an image, a video,Custom, particles or 3D. The frame is
drawn without text and the ratio is the median over the text's box; it
must last 0.5 s to count, so something moving past a label is not
reported. Text over plain fills is judged as before.- A custom WGSL
shade(Shader::source,Shader::file) is painted, not
only checked: an interpreter over naga's IR runs it on the CPU, a tile of
pixels at a time, with the same bytes on every OS (about 0.13 s for a
1080p frame in a release build). Textures, samplers and derivatives are
ashader_error. The playground does not paint it. - Inputs of a custom shader:
.input("photo", Input::file("photo.png"))
(orInput::image(include_bytes!(..))) is read in WGSL with
sample_photo(uv). With.input("scene", Input::frame())the shader
reads what was drawn before it and is painted over it inside its box,
e.g.sample_scene(i.screen / ox.resolution). Callingsample_xwith no
inputxis ashader_errorthat says how to add it. Shader::size(width, height), likewidthandheighttogether.- Example
magnifier: a lens written in WGSL that reads the frame. .offscreen()on any node: it is drawn only for a shader that reads it
withInput::node(handle)(sample_<name>(uv),uvacross the node's
box), never on screen, andcheckskips it.
Changed
lens_drops,node.effect(..)and a frame-reading shader work inside a
group with opacity below 1, a blur, a clip, a blend, a shadow or another
effect. The group is drawn in parts on its own, then faded or blurred as
a whole; a shader in it reads what the group drew before it.checkno
longer reportsinput_cycle.
Fixed
checkno longer reportscovers_textfor a custom shader that reads
the frame (Input::frame()): the text shows through it, as under
lens_drops.InspectNodehas areads_framefield.- A vector's label (
axes.vector(..).label("i")) sits off to the side of
the tip, so a vector along an axis no longer puts its label on the axis
line.
Breaking
Signal::settakesimpl Into<T>, likeSignal::to, so
text.set("Done")andfill.set(Accent)work. A value converted with a
bare.into()no longer infers its type: drop the.into().
Before:m.cell(0, 1).text().set("7".into());→ after:
m.cell(0, 1).text().set("7");Node::scale()returnsScaleSignal, aSignal<Vec2>(it derefs to one)
whosetoandsetalso take one number for both axes:
node.scale().to(1.2, 0.3). Code that names the type changes.
Before:let s: Signal<Vec2> = node.scale();→ after:
let s: Signal<Vec2> = node.scale().signal();(or.into()).lint::Samplehas acontrastfield (measured contrast per text node).
Before:Sample { time, nodes }→ after:
Sample { time, nodes, contrast: Vec::new() }.Inputis no longerCopy(it can hold an image);Input::nametakes
&self. Clone it where it was copied.InspectNodehas areads_framefield; addreads_frame: falsewhere
you build one.
v0.22.0
Added
oxframe check --against(a directory) compares this check's frames with an
earlieroxframe check --framesoutput: each frame that changed gets a
share of changed pixels anddiff/<time>.png, the frame dimmed with the
changed pixels in red;report.jsongets acomparison(changed, the
same, added, removed). Check whether an edit changed only what it meant to.oxframe checkreports where things move:report.jsongetsmotion,
each node that travels with itsfile:line, the stretches of time it
moves visibly (moves, its keyframes), where it starts and ends, and the
length of its path; a child that only rides with its parent is left out.
out/check/trajectories/<scene>.pngdraws the paths on the scene's last
frame, numbered as inmotion.- The storyboard shows both sides of a hard cut between scenes: the last
frame of a scene and the first of the next. Image::decode_png.- The quickstart example: install,
oxframe initandoxframe renderin a
terminal, then the rendered scene plays. It is the animation in the
README's quickstart (scripts/readme-gif.shmakes the GIF).
Tested
- CPU frames are byte-for-byte the same on Linux (x86_64 and arm64), macOS
(Apple Silicon) and Windows: CI renders ten examples on each and compares
the hashes.