<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://getopenscreen.com/blog/</id>
    <title>OpenScreen development journal</title>
    <updated>2026-10-17T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://getopenscreen.com/blog/"/>
    <subtitle>What I have shipped since picking OpenScreen up in June 2026, and what broke along the way.</subtitle>
    <icon>https://getopenscreen.com/img/logo-icon.png</icon>
    <entry>
        <title type="html"><![CDATA[Off-Menu video editing: the agent writes the functions the editor lacks]]></title>
        <id>https://getopenscreen.com/blog/off-menu-video-editing/</id>
        <link href="https://getopenscreen.com/blog/off-menu-video-editing/"/>
        <updated>2026-10-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenScreen 2.1 introduces Off-Menu. The built-in functions stay; next to them, a low-level layer where a coding agent writes the function the editor lacks, through MCP and inside guardrails. Visual effects come first. What it took, what it costs, and who got close before.]]></summary>
        <content type="html"><![CDATA[<p>Software has always stopped at its UI. A video editor is a fixed set of functions: a menu of effects, a list of transitions, a panel of settings. Someone chose them and shipped them. When the thing you have in mind is not among them, you do without.</p>
<p>OpenScreen 2.1 introduces Off-Menu. The built-in functions stay: they are the menu. Next to them sits a new layer: a low-level code interface on the video itself, where an AI agent writes the function you are missing. It has far more freedom than any menu allows, and it still works inside the editor's infrastructure: the timeline, the cursor and the clicks, the zooms and the 3D camera, one renderer for the preview and the export.</p>
<p>Our first implementation is visual effects. You describe an effect, the agent writes it as a GPU shader, OpenScreen compiles it, and it lands on the timeline with its own controls. The preview and the export show the same pixels, on Windows, macOS and Linux.</p>
<video src="/img/blog/off-menu/ripple.mp4" poster="/img/blog/off-menu/ripple-poster.jpg" autoplay="" muted="" loop="" playsinline="" controls="" style="width:100%;border-radius:8px"></video>
<p><em>A ripple on every click. The agent wrote it from one sentence, in two iterations.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="two-halves-of-one-release">Two halves of one release<a href="https://getopenscreen.com/blog/off-menu-video-editing/#two-halves-of-one-release" class="hash-link" aria-label="Direct link to Two halves of one release" title="Direct link to Two halves of one release" translate="no">​</a></h2>
<p>OpenScreen 2.1 is also the release where an agent drives the app end to end. Through its MCP server, an agent records the screen, cuts, zooms, captions, annotates, sets the format and exports, and you never open the app. Those are the editor's own functions, exposed as tools.</p>
<p>Off-Menu is the other half. The tools let the agent use every function the editor has. The code layer lets it write the ones the editor does not have. Together they move the limit of what the editor can do from its UI to what you can describe.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-off-menu-means">What Off-Menu means<a href="https://getopenscreen.com/blog/off-menu-video-editing/#what-off-menu-means" class="hash-link" aria-label="Direct link to What Off-Menu means" title="Direct link to What Off-Menu means" translate="no">​</a></h2>
<p>Ordering off the menu means asking the kitchen for a dish that isn't listed. The kitchen still cooks it, with its own tools and its own rules. That is the model. The menu is the editor's UI, a finite list of functions. The order goes to the agent. The kitchen is the editor's infrastructure, and its rules are the guardrails.</p>
<p>We learned quickly why the kitchen matters. An LLM writes a shader in seconds. What it cannot know is where the cursor sits in the final frame after an animated zoom, or how the recording is tilted under a moving camera. Only the editor knows that. So Off-Menu needs two things:</p>
<ul>
<li class=""><strong>A low-level surface</strong>, close to the pixels, where free code can do what no predefined function anticipated.</li>
<li class=""><strong>A contract</strong> that hands that code everything only the engine knows, so the code stays short and the result stays correct.</li>
</ul>
<p>And the layer is built for agents. Nobody writes code there by hand or pastes it in. The user's interface is the conversation: a coding agent writes the function through the editor's MCP tools, and only through them. That is what lets the editor put guardrails around it: every function is compiled before it is accepted, its loops are bounded, it runs on the GPU only, with no access to files or the network, and its cost is estimated from the code before it ever renders.</p>
<p>The idea is close to what Ink &amp; Switch call <a href="https://www.inkandswitch.com/essay/malleable-software/" target="_blank" rel="noopener noreferrer" class="">malleable software</a>: tools people reshape themselves, instead of waiting for their developers. The difference is in who touches the code. In malleable software, people change their tools by hand. Off-Menu keeps people out of the code: the agent is the only way in, and that is what makes the guardrails possible.</p>
<p>The built-in functions remain the quick path for the basics. The code layer covers the rest.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prior-art">Prior art<a href="https://getopenscreen.com/blog/off-menu-video-editing/#prior-art" class="hash-link" aria-label="Direct link to Prior art" title="Direct link to Prior art" translate="no">​</a></h2>
<p>The idea of letting an LLM write shaders instead of picking presets has been published. A <a href="https://www.tdcommons.org/dpubs_series/8647/" target="_blank" rel="noopener noreferrer" class="">defensive publication from September 2025</a> describes it for images and video. It describes no editor around the idea: no timeline, no preview, no export.</p>
<p>AI video editing today falls into three families:</p>
<table><thead><tr><th>Family</th><th>Examples</th><th>What the AI produces</th><th>Preview = export</th><th>What stays editable</th></tr></thead><tbody><tr><td>Pixel generation</td><td><a href="https://runway.com/research/introducing-runway-aleph" target="_blank" rel="noopener noreferrer" class="">Runway Aleph</a>, <a href="https://workspaceupdates.googleblog.com/2026/07/generate-higher-quality-ai-video-clips-and-edit-any-video-with-Gemini-Omni-in-Vids.html" target="_blank" rel="noopener noreferrer" class="">Google Vids with Gemini Omni</a></td><td>New, synthesized frames</td><td>Yes, the output is the render</td><td>Nothing but a new prompt</td></tr><tr><td>Operation catalog</td><td><a href="https://help.descript.com/hc/en-us/articles/36803785502221" target="_blank" rel="noopener noreferrer" class="">Descript Underlord</a>, <a href="https://www.kapwing.com/help/kapwing-release-notes-may-2026/" target="_blank" rel="noopener noreferrer" class="">Kapwing Kai</a>, <a href="https://help.opus.pro/api-reference/agent-setup" target="_blank" rel="noopener noreferrer" class="">OpusClip MCP</a>, <a href="https://mosaic.so/" target="_blank" rel="noopener noreferrer" class="">Mosaic</a></td><td>Calls to fixed operations</td><td>Yes, one engine renders both</td><td>Everything, within the catalog</td></tr><tr><td>Code</td><td><a href="https://www.remotion.dev/docs/create-effect" target="_blank" rel="noopener noreferrer" class="">Remotion</a>, <a href="https://github.com/heygen-com/hyperframes" target="_blank" rel="noopener noreferrer" class="">HyperFrames</a>, <a href="https://github.com/showlab/Code2Video" target="_blank" rel="noopener noreferrer" class="">Code2Video</a>, <a href="https://arxiv.org/abs/2602.00028" target="_blank" rel="noopener noreferrer" class="">ELLMPEG</a></td><td>Code that renders a whole video</td><td>Depends on the engine, never promised</td><td>The source, outside any editor</td></tr></tbody></table>
<p>Off-Menu sits between the last two: code, inside an editor, picking up where the catalog stops. Three products come close.</p>
<ul>
<li class=""><strong>invideo's <a href="https://invideo.io/news/introducing-agentic-effects-invideo-editor/" target="_blank" rel="noopener noreferrer" class="">Agentic Effects</a></strong>, announced on September 30, 2026. Its agent <a href="https://invideo.io/blog/how-to-create-custom-video-effects-with-ai/" target="_blank" rel="noopener noreferrer" class="">assembles an adjustable effect</a> on invideo's timeline from the editor's building blocks: layers, keyframes, rearranged footage, generated images, and, according to its <a href="https://invideo.io/faq/can-ai-create-custom-video-effects-without-me-writing-code/" target="_blank" rel="noopener noreferrer" class="">FAQ</a>, shader-based effects. The examples are editor-level treatments: a boomerang, a paper tear, a grid transition, highlight streaks. Its pages describe no layer below those blocks, only invideo's own agent builds them, and each job costs credits. It is a closed, cloud product.</li>
<li class=""><strong>Remotion</strong> <code>createEffect()</code>, since version 4.0.479, defines project-specific effects in 2D, WebGL2 or WebGPU, and a <a href="https://github.com/remotion-dev/remotion/pull/8543" target="_blank" rel="noopener noreferrer" class="">June 2026 change</a> teaches its agents to write them. Rendering goes through a browser, nothing promises the same pixels in preview and render, and Remotion's license is not an open-source one.</li>
<li class=""><strong>Mosaic</strong> lets you build editing agents on a canvas, each node configured in plain language. Each node is still one of the editor's predefined operations.</li>
</ul>
<p>Elsewhere, shaders extend a catalog as add-ons (<a href="https://github.com/CommandPost/ResolveCafe/blob/main/docs/developers/dctl.md" target="_blank" rel="noopener noreferrer" class="">DaVinci Resolve DCTLs</a>, <a href="https://github.com/exeldro/obs-shaderfilter" target="_blank" rel="noopener noreferrer" class="">obs-shaderfilter</a>), or agents write them for live video with the loop open: the MCP server of <a href="https://resolume.com/support/en/mcp-servers" target="_blank" rel="noopener noreferrer" class="">Resolume Wire</a> writes ISF shaders it can neither compile nor render, a <a href="https://github.com/johnsabath/touchdesigner-mcp" target="_blank" rel="noopener noreferrer" class="">TouchDesigner MCP</a> writes GLSL in a node graph with no timeline, and <a href="https://arxiv.org/abs/2602.17481" target="_blank" rel="noopener noreferrer" class="">ShadAR</a> has an LLM write HLSL for a headset's passthrough video.</p>
<p><strong>What OpenScreen puts together:</strong></p>
<ol>
<li class=""><strong>A layer below the catalog</strong>: free code on the video itself, where an agent writes what no built-in function anticipated.</li>
<li class=""><strong>Built for any coding agent</strong>, through MCP, inside guardrails: compiled before it is accepted, bounded loops, GPU only, cost known in advance.</li>
<li class=""><strong>A contract that carries what only the engine knows</strong>, down to the recording's surface under the 3D camera.</li>
<li class=""><strong>One native renderer</strong> for the preview and the export, with measured parity.</li>
<li class=""><strong>A closed loop</strong>: the agent looks at frames the editor rendered before it stops.</li>
<li class=""><strong>Open source, free and local</strong>, on three systems.</li>
</ol>
<p>As far as we could find on October 15, 2026, no other open-source video editor works this way. "Not found" is not "absent".</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-first-implementation-effects">The first implementation: effects<a href="https://getopenscreen.com/blog/off-menu-video-editing/#the-first-implementation-effects" class="hash-link" aria-label="Direct link to The first implementation: effects" title="Direct link to The first implementation: effects" translate="no">​</a></h2>
<p>An effect has no rendering path of its own. It is one more pass in OpenScreen's native compositor, which already composes the preview and encodes the export.</p>
<ul>
<li class=""><strong>One path for every pixel.</strong> The compositor is written in Rust, on D3D11 (Windows), Metal (macOS) and wgpu (Linux). The preview and the export call the same compose function with the same scene. The effect is inserted once, so it shows up everywhere, GIF export included.</li>
<li class=""><strong>A one-function contract.</strong> The agent writes <code>fn effect(uv: vec2&lt;f32&gt;) -&gt; vec4&lt;f32&gt;</code>, called for every output pixel. The compositor writes the rest (inputs, bindings, entry points) and places it after the agent's code. WGSL declarations can come in any order, so compiler errors point at the lines the agent wrote. The full contract, with worked examples, is served to agents as the MCP resource <code>openscreen://effects/contract</code>.</li>
<li class=""><strong>One language.</strong> The agent's WGSL is translated by naga to HLSL on Windows and to MSL on macOS; wgpu takes it as is on Linux. We ruled out three other routes:<!-- -->
<ul>
<li class="">Slang: its Metal and WGSL outputs were still experimental, it weighs 30 to 60 MB, and it has no maintained Rust bindings;</li>
<li class="">a bytecode interpreter inside a shader: no compilation, but several times slower per pixel;</li>
<li class="">linking precompiled functions (D3D11 function linking, Metal stitching): it only combines nodes written in advance, not free code.</li>
</ul>
</li>
<li class=""><strong>Nothing compiles while rendering.</strong> A 60-line effect compiles in 10 ms. It is compiled twice:<!-- -->
<ul>
<li class="">when it is written, for real, so that "accepted" means "will draw";</li>
<li class="">when the scene is set, on a background thread. The preview skips the effect while it compiles, then redraws. The export waits for it and never renders a frame without its effect.</li>
</ul>
</li>
<li class=""><strong>The project keeps the source.</strong> Code, name, description and declared parameters are stored, never a binary. An effect is a region on its own timeline row, anchored to clips like a zoom. Click it and the inspector shows a control for each parameter the agent declared, where the effect applies (the image, the text, or both), and its cost. Any change to the function itself goes through the agent.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Diagram: a prompt goes to the AI agent, which writes the WGSL. addEffect compiles it for real, with naga then FXC, and refuses broken code with an error at its line and column. Once accepted, the effect is stored in the project as source and a region anchored to a clip, described once in the scene, and drawn by the compositor in a pass compiled off-thread, so the preview and the export show the same pixels. With getFrames, the agent looks at the frames and loops back to the code." src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCA3NjAgMzYwJyByb2xlPSdpbWcnIGFyaWEtbGFiZWw9J0EgcHJvbXB0IGJlY29tZXMgb25lIGNvbXBvc2l0b3IgcGFzcywgdGhlIHNhbWUgZm9yIHByZXZpZXcgYW5kIGV4cG9ydCcgZm9udC1zaXplPScxMycgZm9udC1mYW1pbHk9J0ludGVyLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIFNlZ29lIFVJLCBzYW5zLXNlcmlmJz4KPHJlY3Qgd2lkdGg9Jzc2MCcgaGVpZ2h0PSczNjAnIGZpbGw9JyNmZmZmZmYnLz4KPGRlZnM+PG1hcmtlciBpZD0nYXJyb3cnIHZpZXdCb3g9JzAgMCAxMCAxMCcgcmVmWD0nOScgcmVmWT0nNScgbWFya2VyV2lkdGg9JzYnIG1hcmtlckhlaWdodD0nNicgb3JpZW50PSdhdXRvLXN0YXJ0LXJldmVyc2UnPjxwYXRoIGQ9J00wIDBMMTAgNUwwIDEweicgZmlsbD0nIzhjOTU5ZicvPjwvbWFya2VyPjwvZGVmcz4KPHRleHQgeD0nMjQnIHk9JzI4JyBmb250LXNpemU9JzE1JyBmb250LXdlaWdodD0nNjAwJyBmaWxsPScjMWYyMzI4Jz5BIHByb21wdCBiZWNvbWVzIG9uZSBjb21wb3NpdG9yIHBhc3MsIHRoZSBzYW1lIGZvciBwcmV2aWV3IGFuZCBleHBvcnQ8L3RleHQ+CjxnIGZpbGw9J25vbmUnIHN0cm9rZT0nIzhjOTU5Zicgc3Ryb2tlLXdpZHRoPScxLjI1Jz48cGF0aCBkPSdNMTc1IDEyMEgyMDUnIG1hcmtlci1lbmQ9J3VybCgjYXJyb3cpJy8+PHBhdGggZD0nTTM1NSAxMjBIMzg1JyBtYXJrZXItZW5kPSd1cmwoI2Fycm93KScvPjxwYXRoIGQ9J001MzUgMTIwSDU2NScgbWFya2VyLWVuZD0ndXJsKCNhcnJvdyknLz48cGF0aCBkPSdNNjQwIDE1OFYyNTInIG1hcmtlci1lbmQ9J3VybCgjYXJyb3cpJy8+PHBhdGggZD0nTTU2NSAyOTBINTM1JyBtYXJrZXItZW5kPSd1cmwoI2Fycm93KScvPjxwYXRoIGQ9J00zODUgMjkwSDM1NScgbWFya2VyLWVuZD0ndXJsKCNhcnJvdyknLz48cGF0aCBkPSdNMjgwIDI1MlYxNTgnIG1hcmtlci1lbmQ9J3VybCgjYXJyb3cpJy8+PHBhdGggZD0nTTQ2MCA4MlY2NEgyODBWODInIG1hcmtlci1lbmQ9J3VybCgjYXJyb3cpJy8+PC9nPgo8cmVjdCB4PScyNScgeT0nODInIHdpZHRoPScxNTAnIGhlaWdodD0nNzYnIHJ4PSc4JyBmaWxsPSdub25lJyBmaWxsLW9wYWNpdHk9JzEnIHN0cm9rZT0nIzhjOTU5Zicgc3Ryb2tlLXdpZHRoPScxLjI1Jy8+PHRleHQgeD0nMTAwJyB5PScxMTYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtd2VpZ2h0PSc2MDAnIGZpbGw9JyMxZjIzMjgnPlByb21wdDwvdGV4dD48dGV4dCB4PScxMDAnIHk9JzEzNCcgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC1zaXplPScxMS41JyBmaWxsPScjNTc2MDZhJz7igJxyaXBwbGUgb24gY2xpY2vigJ08L3RleHQ+CjxyZWN0IHg9JzIwNScgeT0nODInIHdpZHRoPScxNTAnIGhlaWdodD0nNzYnIHJ4PSc4JyBmaWxsPSdub25lJyBmaWxsLW9wYWNpdHk9JzEnIHN0cm9rZT0nIzhjOTU5Zicgc3Ryb2tlLXdpZHRoPScxLjI1Jy8+PHRleHQgeD0nMjgwJyB5PScxMTYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtd2VpZ2h0PSc2MDAnIGZpbGw9JyMxZjIzMjgnPkFJIGFnZW50PC90ZXh0Pjx0ZXh0IHg9JzI4MCcgeT0nMTM0JyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPndyaXRlcyB0aGUgV0dTTDwvdGV4dD4KPHJlY3QgeD0nMzg1JyB5PSc4Micgd2lkdGg9JzE1MCcgaGVpZ2h0PSc3Nicgcng9JzgnIGZpbGw9J25vbmUnIGZpbGwtb3BhY2l0eT0nMScgc3Ryb2tlPScjOGM5NTlmJyBzdHJva2Utd2lkdGg9JzEuMjUnLz48dGV4dCB4PSc0NjAnIHk9JzEwNicgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC13ZWlnaHQ9JzYwMCcgZmlsbD0nIzFmMjMyOCc+YWRkRWZmZWN0PC90ZXh0Pjx0ZXh0IHg9JzQ2MCcgeT0nMTI0JyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPnJlYWwgY29tcGlsYXRpb248L3RleHQ+PHRleHQgeD0nNDYwJyB5PScxNDAnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtc2l6ZT0nMTEuNScgZmlsbD0nIzU3NjA2YSc+bmFnYSwgdGhlbiBGWEM8L3RleHQ+CjxyZWN0IHg9JzU2NScgeT0nODInIHdpZHRoPScxNTAnIGhlaWdodD0nNzYnIHJ4PSc4JyBmaWxsPSdub25lJyBmaWxsLW9wYWNpdHk9JzEnIHN0cm9rZT0nIzhjOTU5Zicgc3Ryb2tlLXdpZHRoPScxLjI1Jy8+PHRleHQgeD0nNjQwJyB5PScxMDYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtd2VpZ2h0PSc2MDAnIGZpbGw9JyMxZjIzMjgnPlByb2plY3Q8L3RleHQ+PHRleHQgeD0nNjQwJyB5PScxMjQnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtc2l6ZT0nMTEuNScgZmlsbD0nIzU3NjA2YSc+c291cmNlICsgcmVnaW9uPC90ZXh0Pjx0ZXh0IHg9JzY0MCcgeT0nMTQwJyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPmFuY2hvcmVkIHRvIGEgY2xpcDwvdGV4dD4KPHJlY3QgeD0nNTY1JyB5PScyNTInIHdpZHRoPScxNTAnIGhlaWdodD0nNzYnIHJ4PSc4JyBmaWxsPSdub25lJyBmaWxsLW9wYWNpdHk9JzEnIHN0cm9rZT0nIzhjOTU5Zicgc3Ryb2tlLXdpZHRoPScxLjI1Jy8+PHRleHQgeD0nNjQwJyB5PScyNzYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZvbnQtd2VpZ2h0PSc2MDAnIGZpbGw9JyMxZjIzMjgnPlNjZW5lPC90ZXh0Pjx0ZXh0IHg9JzY0MCcgeT0nMjk0JyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPmRlc2NyaWJlZCBvbmNlPC90ZXh0Pjx0ZXh0IHg9JzY0MCcgeT0nMzEwJyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPmZvciBhbGwgcmVuZGVyaW5nPC90ZXh0Pgo8cmVjdCB4PSczODUnIHk9JzI1Micgd2lkdGg9JzE1MCcgaGVpZ2h0PSc3Nicgcng9JzgnIGZpbGw9J25vbmUnIGZpbGwtb3BhY2l0eT0nMScgc3Ryb2tlPScjOGM5NTlmJyBzdHJva2Utd2lkdGg9JzEuMjUnLz48dGV4dCB4PSc0NjAnIHk9JzI3NicgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC13ZWlnaHQ9JzYwMCcgZmlsbD0nIzFmMjMyOCc+Q29tcG9zaXRvcjwvdGV4dD48dGV4dCB4PSc0NjAnIHk9JzI5NCcgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC1zaXplPScxMS41JyBmaWxsPScjNTc2MDZhJz5lZmZlY3QgcGFzczwvdGV4dD48dGV4dCB4PSc0NjAnIHk9JzMxMCcgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC1zaXplPScxMS41JyBmaWxsPScjNTc2MDZhJz5jb21waWxlZCBvZmYtdGhyZWFkPC90ZXh0Pgo8cmVjdCB4PScyMDUnIHk9JzI1Micgd2lkdGg9JzE1MCcgaGVpZ2h0PSc3Nicgcng9JzgnIGZpbGw9JyMyZjZmZWInIGZpbGwtb3BhY2l0eT0nMC4xMicgc3Ryb2tlPScjMmY2ZmViJyBzdHJva2Utd2lkdGg9JzInLz48dGV4dCB4PScyODAnIHk9JzI4NicgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC13ZWlnaHQ9JzYwMCcgZmlsbD0nIzFmMjMyOCc+UHJldmlldyArIGV4cG9ydDwvdGV4dD48dGV4dCB4PScyODAnIHk9JzMwNCcgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC1zaXplPScxMS41JyBmaWxsPScjMWYyMzI4Jz5zYW1lIHBpeGVsczwvdGV4dD4KPHRleHQgeD0nMzcwJyB5PSc1NicgdGV4dC1hbmNob3I9J21pZGRsZScgZm9udC1zaXplPScxMS41JyBmaWxsPScjNTc2MDZhJz5yZWZ1c2VkOiBlcnJvciBhdCBsaW5lIGFuZCBjb2x1bW48L3RleHQ+Cjx0ZXh0IHg9JzI5MCcgeT0nMjAwJyBmb250LXNpemU9JzExLjUnIGZpbGw9JyM1NzYwNmEnPmdldEZyYW1lczogdGhlIGFnZW50PC90ZXh0Pgo8dGV4dCB4PScyOTAnIHk9JzIxNicgZm9udC1zaXplPScxMS41JyBmaWxsPScjNTc2MDZhJz5sb29rcyBhdCB0aGUgZnJhbWVzPC90ZXh0Pgo8L3N2Zz4K" width="760" height="360" class="img_ev3q"></p>
<p>The agent loops on the top row until the code compiles, then around the whole loop until the frames match the request. The bottom row is the path every frame in OpenScreen already takes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-measured">What we measured<a href="https://getopenscreen.com/blog/off-menu-video-editing/#what-we-measured" class="hash-link" aria-label="Direct link to What we measured" title="Direct link to What we measured" translate="no">​</a></h2>
<p>On an RTX 4070 Ti (Windows 11, D3D11), the heaviest effect we tried adds 0.04 ms to a 1080p frame, and export time does not move. That effect combines chromatic aberration, barrel distortion, grain, scanlines and a vignette.</p>
<table><thead><tr><th>Measure</th><th>Without effect</th><th>With effect</th></tr></thead><tbody><tr><td>Composing a 1080p frame (compositor bench, release build)</td><td>0.060 ms</td><td>0.100 ms</td></tr><tr><td>Composing a 4K frame</td><td>0.199 ms</td><td>0.314 ms</td></tr><tr><td>Exporting 180 frames at 1752×1080, mean of 3 runs</td><td>520 ms</td><td>523 ms</td></tr><tr><td>Preview playback, 30 fps source</td><td>29.7 fps</td><td>29.7 to 30 fps</td></tr><tr><td>Compiling a 60-line effect (naga + FXC), off the render thread</td><td>n/a</td><td>10 ms</td></tr></tbody></table>
<p><strong>Cost is predictable from the code.</strong> An effect pays a fixed 0.03 ms for the copy and the pass, then about 4 µs per <code>frame()</code> read at 1080p (17 µs at 4K). That is why the cost tiers count image reads, not lines of code.</p>
<p><img decoding="async" loading="lazy" alt="Chart, both axes on a log scale: extra time per composed frame against frame() reads per pixel, on an RTX 4070 Ti with D3D11. At 1080p it rises from +0.030 ms at 1 read and +0.061 ms at 8, both light, to +0.137 ms at 32, medium, +0.539 ms at 128, heavy, and +2.13 ms at 512, very heavy. In 4K, 512 reads cost +8.80 ms. Every point stays under the 16.7 ms budget of a 60 fps frame." src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCA3NjAgMzgwJyByb2xlPSdpbWcnIGFyaWEtbGFiZWw9J0VmZmVjdCBjb3N0IGdyb3dzIHdpdGggaW1hZ2UgcmVhZHMgYW5kIHN0YXlzIGZhciB1bmRlciBhIDYwIGZwcyBmcmFtZScgZm9udC1zaXplPScxMS41JyBmb250LWZhbWlseT0nSW50ZXIsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgU2Vnb2UgVUksIHNhbnMtc2VyaWYnPgo8cmVjdCB3aWR0aD0nNzYwJyBoZWlnaHQ9JzM4MCcgZmlsbD0nI2ZmZmZmZicvPgo8dGV4dCB4PScyNCcgeT0nMzAnIGZvbnQtc2l6ZT0nMTUnIGZvbnQtd2VpZ2h0PSc2MDAnIGZpbGw9JyMxZjIzMjgnPkVmZmVjdCBjb3N0IGdyb3dzIHdpdGggaW1hZ2UgcmVhZHMgYW5kIHN0YXlzIGZhciB1bmRlciBhIDYwIGZwcyBmcmFtZTwvdGV4dD4KPHRleHQgeD0nMjQnIHk9JzUwJyBmaWxsPScjNTc2MDZhJz5FeHRyYSB0aW1lIHBlciBjb21wb3NlZCBmcmFtZSwgYnkgZnJhbWUoKSByZWFkcyBwZXIgcGl4ZWwsIGJvdGggYXhlcyBsb2cgc2NhbGUuIFJUWCA0MDcwIFRpLCBEM0QxMS48L3RleHQ+CjxsaW5lIHgxPSc3MicgeDI9JzYyMCcgeTE9JzI0NS43JyB5Mj0nMjQ1LjcnIHN0cm9rZT0nI2Q4ZGVlNCcvPgo8dGV4dCB4PSc2NCcgeT0nMjQ5LjcnIHRleHQtYW5jaG9yPSdlbmQnIGZpbGw9JyM1NzYwNmEnPjAuMSBtczwvdGV4dD4KPGxpbmUgeDE9JzcyJyB4Mj0nNjIwJyB5MT0nMTc1LjQnIHkyPScxNzUuNCcgc3Ryb2tlPScjZDhkZWU0Jy8+Cjx0ZXh0IHg9JzY0JyB5PScxNzkuNCcgdGV4dC1hbmNob3I9J2VuZCcgZmlsbD0nIzU3NjA2YSc+MSBtczwvdGV4dD4KPGxpbmUgeDE9JzcyJyB4Mj0nNjIwJyB5MT0nMTA1LjInIHkyPScxMDUuMicgc3Ryb2tlPScjZDhkZWU0Jy8+Cjx0ZXh0IHg9JzY0JyB5PScxMDkuMicgdGV4dC1hbmNob3I9J2VuZCcgZmlsbD0nIzU3NjA2YSc+MTAgbXM8L3RleHQ+CjxsaW5lIHgxPSc3MicgeDI9JzYyMCcgeTE9JzMxNicgeTI9JzMxNicgc3Ryb2tlPScjOGM5NTlmJy8+CjxsaW5lIHgxPSc3Mi4wJyB4Mj0nNzIuMCcgeTE9JzMxNicgeTI9JzMyMScgc3Ryb2tlPScjOGM5NTlmJy8+Cjx0ZXh0IHg9JzcyLjAnIHk9JzMzNicgdGV4dC1hbmNob3I9J21pZGRsZScgZmlsbD0nIzFmMjMyOCc+MSByZWFkPC90ZXh0Pgo8dGV4dCB4PSc3Mi4wJyB5PSczNTInIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyM1NzYwNmEnPmxpZ2h0PC90ZXh0Pgo8bGluZSB4MT0nMjU0LjcnIHgyPScyNTQuNycgeTE9JzMxNicgeTI9JzMyMScgc3Ryb2tlPScjOGM5NTlmJy8+Cjx0ZXh0IHg9JzI1NC43JyB5PSczMzYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyMxZjIzMjgnPjggcmVhZHM8L3RleHQ+Cjx0ZXh0IHg9JzI1NC43JyB5PSczNTInIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyM1NzYwNmEnPmxpZ2h0PC90ZXh0Pgo8bGluZSB4MT0nMzc2LjQnIHgyPSczNzYuNCcgeTE9JzMxNicgeTI9JzMyMScgc3Ryb2tlPScjOGM5NTlmJy8+Cjx0ZXh0IHg9JzM3Ni40JyB5PSczMzYnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyMxZjIzMjgnPjMyIHJlYWRzPC90ZXh0Pgo8dGV4dCB4PSczNzYuNCcgeT0nMzUyJyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmaWxsPScjNTc2MDZhJz5tZWRpdW08L3RleHQ+CjxsaW5lIHgxPSc0OTguMicgeDI9JzQ5OC4yJyB5MT0nMzE2JyB5Mj0nMzIxJyBzdHJva2U9JyM4Yzk1OWYnLz4KPHRleHQgeD0nNDk4LjInIHk9JzMzNicgdGV4dC1hbmNob3I9J21pZGRsZScgZmlsbD0nIzFmMjMyOCc+MTI4IHJlYWRzPC90ZXh0Pgo8dGV4dCB4PSc0OTguMicgeT0nMzUyJyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmaWxsPScjNTc2MDZhJz5oZWF2eTwvdGV4dD4KPGxpbmUgeDE9JzYyMC4wJyB4Mj0nNjIwLjAnIHkxPSczMTYnIHkyPSczMjEnIHN0cm9rZT0nIzhjOTU5ZicvPgo8dGV4dCB4PSc2MjAuMCcgeT0nMzM2JyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmaWxsPScjMWYyMzI4Jz41MTIgcmVhZHM8L3RleHQ+Cjx0ZXh0IHg9JzYyMC4wJyB5PSczNTInIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyM1NzYwNmEnPnZlcnkgaGVhdnk8L3RleHQ+CjxsaW5lIHgxPSc3MicgeDI9JzYyMCcgeTE9Jzg5LjUnIHkyPSc4OS41JyBzdHJva2U9JyM4Yzk1OWYnIHN0cm9rZS1kYXNoYXJyYXk9JzQgNCcvPgo8dGV4dCB4PSc3OCcgeT0nODMuNScgZmlsbD0nIzU3NjA2YSc+NjAgZnBzIGZyYW1lIGJ1ZGdldCwgMTYuNyBtczwvdGV4dD4KPHBhdGggZD0nTTcyLjAgMjM1LjkgTDI1NC43IDIyMi45IEwzNzYuNCAxOTAuNyBMNDk4LjIgMTQ5LjIgTDYyMC4wIDEwOS4wJyBmaWxsPSdub25lJyBzdHJva2U9JyNhZmI4YzEnIHN0cm9rZS13aWR0aD0nMS41Jy8+CjxjaXJjbGUgY3g9JzcyLjAnIGN5PScyMzUuOScgcj0nMy41JyBmaWxsPScjYWZiOGMxJy8+CjxjaXJjbGUgY3g9JzI1NC43JyBjeT0nMjIyLjknIHI9JzMuNScgZmlsbD0nI2FmYjhjMScvPgo8Y2lyY2xlIGN4PSczNzYuNCcgY3k9JzE5MC43JyByPSczLjUnIGZpbGw9JyNhZmI4YzEnLz4KPGNpcmNsZSBjeD0nNDk4LjInIGN5PScxNDkuMicgcj0nMy41JyBmaWxsPScjYWZiOGMxJy8+CjxjaXJjbGUgY3g9JzYyMC4wJyBjeT0nMTA5LjAnIHI9JzMuNScgZmlsbD0nI2FmYjhjMScvPgo8dGV4dCB4PSc2MzAuMCcgeT0nMTEzLjAnIGZpbGw9JyM1NzYwNmEnPjRLICs4LjgwIG1zPC90ZXh0Pgo8cGF0aCBkPSdNNzIuMCAyODIuNSBMMjU0LjcgMjYwLjggTDM3Ni40IDIzNi4xIEw0OTguMiAxOTQuMyBMNjIwLjAgMTUyLjMnIGZpbGw9J25vbmUnIHN0cm9rZT0nIzJmNmZlYicgc3Ryb2tlLXdpZHRoPScyJy8+CjxjaXJjbGUgY3g9JzcyLjAnIGN5PScyODIuNScgcj0nNCcgZmlsbD0nIzJmNmZlYicvPgo8Y2lyY2xlIGN4PScyNTQuNycgY3k9JzI2MC44JyByPSc0JyBmaWxsPScjMmY2ZmViJy8+CjxjaXJjbGUgY3g9JzM3Ni40JyBjeT0nMjM2LjEnIHI9JzQnIGZpbGw9JyMyZjZmZWInLz4KPGNpcmNsZSBjeD0nNDk4LjInIGN5PScxOTQuMycgcj0nNCcgZmlsbD0nIzJmNmZlYicvPgo8Y2lyY2xlIGN4PSc2MjAuMCcgY3k9JzE1Mi4zJyByPSc0JyBmaWxsPScjMmY2ZmViJy8+Cjx0ZXh0IHg9JzcyLjAnIHk9JzMwMC41JyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmaWxsPScjMWYyMzI4Jz4rMC4wMzAgbXM8L3RleHQ+Cjx0ZXh0IHg9JzI1NC43JyB5PScyNzguOCcgdGV4dC1hbmNob3I9J21pZGRsZScgZmlsbD0nIzFmMjMyOCc+KzAuMDYxIG1zPC90ZXh0Pgo8dGV4dCB4PSczNzYuNCcgeT0nMjU0LjEnIHRleHQtYW5jaG9yPSdtaWRkbGUnIGZpbGw9JyMxZjIzMjgnPiswLjEzNyBtczwvdGV4dD4KPHRleHQgeD0nNDk4LjInIHk9JzIxMi4zJyB0ZXh0LWFuY2hvcj0nbWlkZGxlJyBmaWxsPScjMWYyMzI4Jz4rMC41MzkgbXM8L3RleHQ+Cjx0ZXh0IHg9JzYzMC4wJyB5PScxNTYuMycgZm9udC13ZWlnaHQ9JzYwMCcgZmlsbD0nIzFmMjMyOCc+MTA4MHAgKzIuMTMgbXM8L3RleHQ+Cjwvc3ZnPgo=" width="760" height="380" class="img_ev3q"></p>
<p><strong>The preview and the export show the same picture.</strong> We compared the live preview's frame with the exported MP4's frame at the same instant:</p>
<ul>
<li class=""><strong>inside the effect region,</strong> the mean difference is 2.2 to 2.7 out of 255 (32 to 34 dB), the same as outside it: that is H.264 codec noise;</li>
<li class=""><strong>against the export without the effect,</strong> it rises to 14 to 35 out of 255. So the effect is really drawn, and drawn the same on both sides.</li>
<li class=""><strong>A measurement trap.</strong> Decoded without stating the BT.709 matrix, the MP4 shows a false difference of 12 out of 255 that has nothing to do with the effect.</li>
</ul>
<p><strong>One agent iteration takes seconds.</strong> On the prompt "ripple effect when the mouse clicks":</p>
<ol>
<li class=""><strong>Broken code is refused in 7 ms,</strong> with naga's error at the agent's own line and column, here a typo in <code>strenght</code>.</li>
<li class=""><strong>The first version compiles on the first try,</strong> but draws a single glowing ring, closer to a halo.</li>
<li class=""><strong>The second version</strong> sends concentric waves out from the click, refracting the picture. It matches the prompt.</li>
</ol>
<p>The agent saw nothing but the tool's description. Each iteration chained writing, compiling, rendering and looking at a few frames.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-contract-learned">What the contract learned<a href="https://getopenscreen.com/blog/off-menu-video-editing/#what-the-contract-learned" class="hash-link" aria-label="Direct link to What the contract learned" title="Direct link to What the contract learned" translate="no">​</a></h2>
<p>The first real prompt exposed a hole in the contract: a ripple on click could not be written. The effect saw the picture and the time, but not where the mouse was in the final frame.</p>
<p>The agent cannot compute that position. Between the recorded mouse and the output pixel sit the animated zoom, the layout, the frame and the optional 3D tilt. Only the compositor knows all of them, at every frame. So the cursor tip and the latest clicks went into the contract, already placed in output coordinates. The ripple then took two iterations.</p>
<p>The second lesson came from a water drop. Under the orbit camera, the recording is a tilted plane, and a wave computed in output coordinates drew perfect circles floating over it. The contract now exposes the recording's surface itself, through the exact warp the compositor draws it with: bilinear under a fixed angle, the homography of its corners under the real camera. <code>fx_to_footage(uv)</code> and <code>fx_from_footage(p)</code> map between the picture and that surface. The contract decides nothing: the effect picks the space that fits it. The water drop now lies on the recording, in perspective, and a vignette still works on the whole frame.</p>
<p><strong>The rule that came out of it: what only the compositor knows goes into the contract, and the contract informs without deciding.</strong> Version 1 therefore provides, on top of the picture and the time:</p>
<ul>
<li class=""><strong>the cursor</strong> and the four latest clicks, in output coordinates;</li>
<li class=""><strong>where the recording and the webcam sit</strong> in the final frame, and the recording's own surface, through its warp;</li>
<li class=""><strong>the effect's progress</strong> across its whole region, even when a cut runs through it;</li>
<li class=""><strong>named, typed parameters</strong> (<code>params.radius</code> rather than an index), so an agent rereads an effect without decoding it, and the inspector knows which control to show;</li>
<li class=""><strong>deterministic randomness,</strong> identical on every GPU.</li>
</ul>
<p>That last point is a lesson of its own. The classic shader hash <code>fract(sin(x) * 43758.5453)</code> gives different values from one GPU to another, so a project opened on another machine would no longer have the same grain.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="limits-and-open-questions">Limits and open questions<a href="https://getopenscreen.com/blog/off-menu-video-editing/#limits-and-open-questions" class="hash-link" aria-label="Direct link to Limits and open questions" title="Direct link to Limits and open questions" translate="no">​</a></h2>
<p>The real risk of agent-written code is not its cost. It is a loop that never ends: it hangs the GPU until Windows resets it, and the app loses its device.</p>
<ul>
<li class=""><strong>GPU hangs.</strong> The guard is static: every loop needs a literal bound, with a ceiling of 4,096 iterations per pixel. Recovering a lost device is a separate project that concerns the whole app.</li>
<li class=""><strong>Cost is not capped.</strong> A budget measured on the machine that writes the effect would refuse a heavy effect on a modest laptop, even though the export would render it fine. So cost is estimated from the code: image reads per pixel, multiplied by loop bounds. That gives a tier, identical on every machine, which the agent receives with a recommendation.</li>
<li class=""><strong>Pixels across machines.</strong> Floating-point results can differ slightly between DXBC, MSL and SPIR-V, as for the rest of the rendering. Strict equality holds on one machine.</li>
<li class=""><strong>The translator's version.</strong> From naga 25 on, HLSL output declares samplers in a D3D12 heap, which FXC rejects for D3D11 (error X3721). We stay on naga 24, and a test guards that line.</li>
<li class=""><strong>The scope of version 1.</strong> An effect acts on the whole composed picture, on the text layer alone, or on both. Three things stay out of reach for now:<!-- -->
<ul>
<li class="">effects on one layer only, the screen or the webcam;</li>
<li class="">transitions, which need two pictures as input;</li>
<li class="">temporal effects (trails, persistence), which would need previous frames as explicit inputs, never kept state.</li>
</ul>
</li>
<li class=""><strong>Shared code.</strong> Opening someone else's project compiles code you did not write. It runs only on the GPU, with no access to files, the network or the app's memory, and the same guards apply when the project opens.</li>
<li class=""><strong>Measurements.</strong> The numbers above come from one Windows machine. The Metal and wgpu passes ship in the same release; we have not benchmarked them on comparable hardware yet.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-off-menu-goes-next">Where Off-Menu goes next<a href="https://getopenscreen.com/blog/off-menu-video-editing/#where-off-menu-goes-next" class="hash-link" aria-label="Direct link to Where Off-Menu goes next" title="Direct link to Where Off-Menu goes next" translate="no">​</a></h2>
<p>Effects are the first function we opened to code. A shader computes each pixel from pictures and time, so anything that can be described that way can move from the menu to a request, as long as the contract gives it the right inputs.</p>
<table><thead><tr><th>What you want</th><th>What the code must receive</th><th>In OpenScreen 2.1</th></tr></thead><tbody><tr><td>Grading, distortions, blurs, glitches, vignettes</td><td>The composed picture and the time</td><td>Ships</td></tr><tr><td>Mouse-driven effects: ripple, halo, magnifier</td><td>The cursor and the clicks in output coordinates</td><td>Ships</td></tr><tr><td>Effects that lie on the recording, under zoom and 3D camera</td><td>The recording's surface and its warp</td><td>Ships</td></tr><tr><td>Effects on the text alone, or under the text</td><td>The picture and the text layer separately</td><td>Ships</td></tr><tr><td>Transitions: dissolve, wipe, morph</td><td>Two pictures, before and after, and the progress</td><td>Next</td></tr><tr><td>Effects on the screen alone or the webcam alone</td><td>Each layer separately</td><td>Next</td></tr><tr><td>Trails, persistence, smoothed slow motion</td><td>Previous frames, as explicit inputs</td><td>Next</td></tr><tr><td>Effects that follow a subject</td><td>A mask computed elsewhere, like the webcam's</td><td>Next</td></tr></tbody></table>
<p><strong>Beyond pixels.</strong> Cuts, timing and the order of clips are functions too. Today the agent drives them through the editor's built-in tools, and they do the job. Opening them to free code the same way, with the timeline as the infrastructure, is where the idea goes next: an edit where any function, not only the look, can be written on demand.</p>
<p><strong>What stays out.</strong> Understanding the content (tracking a face, reading on-screen text) needs a model; the code consumes its result as a mask or coordinates. Inventing pictures that are not in the footage is the generative family's job, with its price: no determinism, and no source to edit.</p>
<p><strong>The model that comes out of it.</strong> An edit becomes the editor's built-in functions plus functions written on demand. Between the two, a contract supplies everything only the engine knows. The agent works on both through the same interface, and every edit stays an object you can reread, adjust or delete. The menu stays for the basics. It stops being the edge of what an edit can do.</p>
<p><strong>What would prove it better than a demo.</strong> A benchmark of effect prompts, scored on the rendered result like <a href="https://conf.researchr.org/details/icse-2025/llm4code-2025-papers/13/Evaluating-Language-Models-for-Computer-Graphics-Code-Completion" target="_blank" rel="noopener noreferrer" class="">ShaderMatch</a>, with two checks we already know how to run:</p>
<ul>
<li class="">parity between preview and export;</li>
<li class="">an agent that looks at its own frames before it stops.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it">Try it<a href="https://getopenscreen.com/blog/off-menu-video-editing/#try-it" class="hash-link" aria-label="Direct link to Try it" title="Direct link to Try it" translate="no">​</a></h2>
<p>OpenScreen 2.1 is free and open source, on Windows, macOS and Linux: <a href="https://getopenscreen.com/" target="_blank" rel="noopener noreferrer" class="">getopenscreen.com</a>.</p>
<ul>
<li class=""><strong>In the app</strong>, connect a provider in AI settings and ask the chat for an effect.</li>
<li class=""><strong>From Claude Code</strong>, paste: Install the OpenScreen demo skill with <code>npx skills add getopenscreen/openscreen --skill openscreen-demo -a claude-code</code>, then follow it to make a demo video of this feature.</li>
<li class=""><strong>Docs:</strong> <a class="" href="https://getopenscreen.com/docs/effects/">Custom effects</a> and <a class="" href="https://getopenscreen.com/docs/ai-editing/">AI editing</a>.</li>
<li class=""><strong>For agent authors:</strong> the contract is the MCP resource <code>openscreen://effects/contract</code>, and the design is in <a href="https://github.com/getopenscreen/openscreen/blob/main/docs/shader-effects.md" target="_blank" rel="noopener noreferrer" class=""><code>docs/shader-effects.md</code></a>.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sources">Sources<a href="https://getopenscreen.com/blog/off-menu-video-editing/#sources" class="hash-link" aria-label="Direct link to Sources" title="Direct link to Sources" translate="no">​</a></h2>
<p>Pages opened between October 13 and 15, 2026.</p>
<p><strong>The idea</strong></p>
<ul>
<li class=""><a href="https://www.inkandswitch.com/essay/malleable-software/" target="_blank" rel="noopener noreferrer" class="">Malleable software: restoring user agency in a world of locked-down apps</a>, Ink &amp; Switch, 2025</li>
<li class=""><a href="https://www.tdcommons.org/dpubs_series/8647/" target="_blank" rel="noopener noreferrer" class="">AI-driven Special Effects Generation and Application Framework for Visual Content</a>, Colvin Pitts, TDCommons, September 29, 2025</li>
</ul>
<p><strong>Research</strong></p>
<ul>
<li class=""><a href="https://arxiv.org/abs/2609.35143" target="_blank" rel="noopener noreferrer" class="">Timeline-Bench</a>, arXiv, September 28, 2026</li>
<li class=""><a href="https://conf.researchr.org/details/icse-2025/llm4code-2025-papers/13/Evaluating-Language-Models-for-Computer-Graphics-Code-Completion" target="_blank" rel="noopener noreferrer" class="">ShaderMatch</a>, LLM4Code @ ICSE, May 2025</li>
<li class=""><a href="https://arxiv.org/abs/2602.17481" target="_blank" rel="noopener noreferrer" class="">ShadAR</a>, arXiv, February 2026</li>
<li class=""><a href="https://github.com/showlab/Code2Video" target="_blank" rel="noopener noreferrer" class="">Code2Video</a>, October 2025</li>
<li class=""><a href="https://arxiv.org/abs/2602.00028" target="_blank" rel="noopener noreferrer" class="">ELLMPEG</a>, MMSys 2026</li>
<li class=""><a href="https://arxiv.org/abs/2509.10761v1" target="_blank" rel="noopener noreferrer" class="">EditDuet</a>, SIGGRAPH 2025</li>
<li class=""><a href="https://www.dgp.toronto.edu/~bryanw/lave/" target="_blank" rel="noopener noreferrer" class="">LAVE</a>, IUI 2024</li>
</ul>
<p><strong>Tools and products</strong></p>
<ul>
<li class=""><a href="https://invideo.io/news/introducing-agentic-effects-invideo-editor/" target="_blank" rel="noopener noreferrer" class="">invideo Agentic Effects</a>, September 30, 2026, its <a href="https://invideo.io/blog/how-to-create-custom-video-effects-with-ai/" target="_blank" rel="noopener noreferrer" class="">custom effects guide</a> and its <a href="https://invideo.io/faq/can-ai-create-custom-video-effects-without-me-writing-code/" target="_blank" rel="noopener noreferrer" class="">FAQ</a></li>
<li class=""><a href="https://www.remotion.dev/docs/create-effect" target="_blank" rel="noopener noreferrer" class="">Remotion <code>createEffect()</code></a>, and the <a href="https://github.com/remotion-dev/remotion/pull/8543" target="_blank" rel="noopener noreferrer" class="">change that opens it to agents</a></li>
<li class=""><a href="https://mosaic.so/" target="_blank" rel="noopener noreferrer" class="">Mosaic</a></li>
<li class=""><a href="https://github.com/heygen-com/hyperframes" target="_blank" rel="noopener noreferrer" class="">HyperFrames</a> and its <a href="https://hyperframes.heygen.com/packages/shader-transitions" target="_blank" rel="noopener noreferrer" class="">shader transitions</a></li>
<li class=""><a href="https://resolume.com/support/en/mcp-servers" target="_blank" rel="noopener noreferrer" class="">Resolume Wire MCP server</a></li>
<li class=""><a href="https://github.com/johnsabath/touchdesigner-mcp" target="_blank" rel="noopener noreferrer" class="">TouchDesigner MCP</a></li>
<li class=""><a href="https://github.com/CommandPost/ResolveCafe/blob/main/docs/developers/dctl.md" target="_blank" rel="noopener noreferrer" class="">DaVinci Resolve DCTL</a></li>
<li class=""><a href="https://github.com/exeldro/obs-shaderfilter" target="_blank" rel="noopener noreferrer" class="">obs-shaderfilter</a></li>
<li class=""><a href="https://runway.com/research/introducing-runway-aleph" target="_blank" rel="noopener noreferrer" class="">Runway Aleph</a></li>
<li class=""><a href="https://workspaceupdates.googleblog.com/2026/07/generate-higher-quality-ai-video-clips-and-edit-any-video-with-Gemini-Omni-in-Vids.html" target="_blank" rel="noopener noreferrer" class="">Google Vids and Gemini Omni</a></li>
<li class=""><a href="https://help.descript.com/hc/en-us/articles/36803785502221" target="_blank" rel="noopener noreferrer" class="">Descript Underlord</a></li>
<li class=""><a href="https://www.kapwing.com/help/kapwing-release-notes-may-2026/" target="_blank" rel="noopener noreferrer" class="">Kapwing Kai</a></li>
<li class=""><a href="https://help.opus.pro/api-reference/agent-setup" target="_blank" rel="noopener noreferrer" class="">OpusClip MCP</a></li>
</ul>
<p><strong>OpenScreen</strong></p>
<ul>
<li class="">The effects design: <a href="https://github.com/getopenscreen/openscreen/blob/main/docs/shader-effects.md" target="_blank" rel="noopener noreferrer" class=""><code>docs/shader-effects.md</code></a></li>
<li class="">The compositor and the WGSL contract: <a href="https://github.com/getopenscreen/openscreen/blob/main/crates/compositor/src/shader_fx.rs" target="_blank" rel="noopener noreferrer" class=""><code>crates/compositor/src/shader_fx.rs</code></a></li>
</ul>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="effects" term="effects"/>
        <category label="agents" term="agents"/>
        <category label="compositor" term="compositor"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Making of v2: a demo is never ugly]]></title>
        <id>https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/</id>
        <link href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/"/>
        <updated>2026-09-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How OpenScreen v2 came together. One rule, an audit against it, twenty-one pull requests merged into one branch, and a round of UI work that removed more than it added.]]></summary>
        <content type="html"><![CDATA[<p>v2 started from one sentence rather than a feature list: a demo looks good without touching anything, and touching the settings can't make it ugly. That is the promise the best commercial recorders make, and on September 24 I audited OpenScreen against it.</p>
<p>The result was two rules kept out of ten, and thirty findings. The fixes are gathered in one branch, <a href="https://github.com/getopenscreen/openscreen/pull/814" target="_blank" rel="noopener noreferrer" class="">#814</a>, which is what v2 will be.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-audit">The audit<a href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/#the-audit" class="hash-link" aria-label="Direct link to The audit" title="Direct link to The audit" translate="no">​</a></h2>
<p>Ten rules, each written as something a user should be able to rely on. Defaults that look good. Every value bounded, with a way back to its default. A format change or a cut that breaks nothing. What you see in the preview is what you export.</p>
<p>Measured on the build of that day, the defaults failed first:</p>
<ul>
<li class=""><strong>The default cursor</strong> was 82 px tall in a 1080p export, about four times the system arrow, and it could be pushed to 272 px.</li>
<li class=""><strong>The default shadow</strong> drew at 9% opacity, which on most wallpapers means no shadow at all.</li>
<li class=""><strong>A 16:9 recording exported as 9:16</strong> filled 20% of the frame.</li>
</ul>
<p>None of those is a bug in the usual sense. Each one is a setting that works as written and makes the video worse.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="twenty-one-pull-requests-one-branch">Twenty-one pull requests, one branch<a href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/#twenty-one-pull-requests-one-branch" class="hash-link" aria-label="Direct link to Twenty-one pull requests, one branch" title="Direct link to Twenty-one pull requests, one branch" translate="no">​</a></h2>
<p>The findings split into six workstreams, and each became a pull request against a shared integration branch instead of <code>main</code>. They touch the same panels and the same compositor, and landing them one by one would have meant a week of broken intermediate states on <code>main</code>. Merged into one branch in dependency order, they can be tested together and land together.</p>
<p><strong>Defaults.</strong> The cursor is half its old size, 41 px in 1080p. The shadow is at 27% opacity. New projects start from the look of your last one.</p>
<p><strong>Bounds in the model.</strong> One table clamps every appearance value, whoever writes it: the panel, the AI agent, a preset or a hand-edited project file. Every slider has a reset.</p>
<p><strong>The render tells the truth.</strong> Two findings were the kind you only see by measuring. Every text font exported as Segoe UI, pixel for pixel, because the picker offered fonts the app never shipped; five open-licensed families are embedded now. Gradients used only their first and last colour stops, so a red, green and blue gradient drew purple at its midpoint where green belonged.</p>
<p><strong>Export.</strong> The bitrate the app computed never reached the encoder, so every export ran at 8 Mb/s whatever the frame rate. It is 18.7 Mb/s at 1080p60 now. GIFs are dithered, and the dialog offers four destinations (Web / YouTube, Social, Studio, README GIF) with the codec details folded under Advanced.</p>
<p><strong>Audio.</strong> Voice is normalised to −16 LUFS with a soft limiter instead of a hard clip, and music ducks under it.</p>
<p><strong>Framing.</strong> A 16:9 take in a 9:16 export now fills 64% of the frame, in a window that follows the cursor. Zooms are capped at twice the source's own resolution, so a deep zoom no longer magnifies blur. Silence cuts keep 70 ms of breath on each side, so a cut doesn't clip the start of a word.</p>
<p>One thing went the other way. The 17 third-party cursor packs are gone: their terms don't allow redistribution. Five original themes replace them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="then-the-interface">Then the interface<a href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/#then-the-interface" class="hash-link" aria-label="Direct link to Then the interface" title="Direct link to Then the interface" translate="no">​</a></h2>
<p>With the rules holding, the panels were the next thing to make ugly by accident. The branch this post was written on carries about a hundred and twenty more commits, and most of them delete something.</p>
<p><strong>One click per choice.</strong> The selects and dropdowns in the right panel became rows of buttons, so every option is visible and picking one is a single click: format, frame style, the zoom's 3D camera, focus mode, cursor style, caption language and font. Only the fifteen translation targets stay a list.</p>
<p><strong>Names instead of numbers.</strong> A shadow is None, Light, Medium or Strong. Click bounce is None, Light or Strong. A slider stays where the amount is the point (padding, background blur, cursor size), and a slider with no unit shows no number.</p>
<p><strong>No explanations under settings.</strong> If the label needs a sentence to be understood, the label is wrong. An option that does nothing in the current context is hidden instead of greyed out with its reason.</p>
<p><strong>Fewer controls.</strong> The Fit button rewrote four settings without naming any, and padding at 0 already does its job, so it's gone. The seek bar under the transport repeated the ruler right below it, so that went too.</p>
<p><strong>A timeline you read by colour.</strong> The recording is the main object on the timeline, so it wears the brand's green. Zoom pills are blue, so the most common effect never reads as the clip under it. Every block is a solid card with dark text, because mint can't carry white: 2.3:1 contrast with white text, 8.2:1 with dark ink.</p>
<p>The walkthrough on the <a class="" href="https://getopenscreen.com/">home page</a> and this site's docs were redrawn to match.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-3d-camera">The 3D camera<a href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/#the-3d-camera" class="hash-link" aria-label="Direct link to The 3D camera" title="Direct link to The 3D camera" translate="no">​</a></h2>
<p>The 3D work followed the same rule. A camera that rolls during a zoom looks broken rather than cinematic, so a moving camera never rolls now. The fixed angles went through three versions in a day before landing back on the v1.13.0 angle, checked against a real v1.13.0 export rather than from memory. The follow camera became <strong>3D Orbit</strong>, which obeys the zoom's focus mode like the flat zoom does. The 3D cursor dives onto each click in depth, and the click impact that used to live on the zoom is a cursor setting for every camera.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="before-v2-ships">Before v2 ships<a href="https://getopenscreen.com/blog/2026/09/27/making-of-v2-a-demo-is-never-ugly/#before-v2-ships" class="hash-link" aria-label="Direct link to Before v2 ships" title="Direct link to Before v2 ships" translate="no">​</a></h2>
<p><a href="https://github.com/getopenscreen/openscreen/pull/814" target="_blank" rel="noopener noreferrer" class="">#814</a> is open, and green except for one compositor test on Linux and macOS that checks the 3D cursor's footprint. After that, it needs a manual pass on real Windows and macOS machines, then the usual release candidates.</p>
<p>It is still not production-grade, and rough edges are expected. If a default still makes your demo worse, that is exactly the bug this release is about: <a href="https://getopenscreen.com/discord/" target="_blank" rel="noopener noreferrer" class="">Discord</a> or an issue, either works.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[An export benchmark built to be hard to fake]]></title>
        <id>https://getopenscreen.com/blog/2026/09/09/an-export-benchmark-hard-to-fake/</id>
        <link href="https://getopenscreen.com/blog/2026/09/09/an-export-benchmark-hard-to-fake/"/>
        <updated>2026-09-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[An open, reproducible screen recorder export benchmark. Same clip, same edit, each result divided by ffmpeg on the same machine and verified in pixels.]]></summary>
        <content type="html"><![CDATA[<p>Every screen recorder claims a fast export. None of them says fast compared to what.</p>
<p>So the comparison is public now: <a href="https://etiennelescot.github.io/screen-recorder-benchmark/" target="_blank" rel="noopener noreferrer" class="">screen-recorder-benchmark</a>. Same clip, same edit, same machine, across the desktop apps built to turn a recording into a finished demo. OpenScreen is one of the tools in it, alongside Cap, FocuSee, Recordly and Screen Studio, and the standings are whatever the submissions say.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-current-standings">The current standings (lower is better)<a href="https://getopenscreen.com/blog/2026/09/09/an-export-benchmark-hard-to-fake/#the-current-standings" class="hash-link" aria-label="Direct link to The current standings (lower is better)" title="Direct link to The current standings (lower is better)" translate="no">​</a></h2>
<div class="panel_INAy"><p class="fallback_Ho1S">Loading the current standings…</p></div>
<p>Read the ratio, not seconds. Each figure is an export divided by what a plain ffmpeg transcode of the same clip needed on the same machine, measured minutes earlier. A tool at 1.5× did 50% more work than a bare re-encode, on whatever hardware you have. Seconds only ever compare a machine to itself.</p>
<p>The scenario is a finished demo rather than a transcode: a sampled wallpaper, padding, rounded corners, a drop shadow, three animated zooms, motion blur, a cursor redrawn from telemetry, a webcam inset with mask and shadow, and the recording's audio, all pinned to 1920x1080 at 60 fps in H.264. How the <a class="" href="https://getopenscreen.com/download/">current OpenScreen release</a> renders that is in the <a class="" href="https://getopenscreen.com/docs/export/">export docs</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="four-decisions-that-make-it-hard-to-fake">Four decisions that make it hard to fake<a href="https://getopenscreen.com/blog/2026/09/09/an-export-benchmark-hard-to-fake/#four-decisions-that-make-it-hard-to-fake" class="hash-link" aria-label="Direct link to Four decisions that make it hard to fake" title="Direct link to Four decisions that make it hard to fake" translate="no">​</a></h2>
<p><strong>ffmpeg is the 1x, and it is not a competitor.</strong> The reference is re-measured on your machine, under your load, immediately before each tool runs. Nothing is normalised against a number I recorded once on a laptop I own.</p>
<p><strong>No tool is required in a submission.</strong> Tools are nodes, every pair measured together on one machine is an edge, and the ranking is recovered by least squares across the whole graph. Two people who never measured the same app still contribute to the same ordering, as long as the submissions overlap somewhere.</p>
<p><strong>The verifier decides what happened, not the app.</strong> Every export is re-probed before it counts: resolution, frame rate, codec and duration against the target, then wallpaper, padding, corner radius, zooms, cursor and camera checked in the pixels, then audio by loudness, because a silent track passes any check that only asks whether audio exists. A tool reports what it configured. The verifier reports what came out, and the verifier wins.</p>
<p><strong>The disagreement is published above the ranking.</strong> Where one pair of tools was measured on more than one machine, the two ratios can differ by more than the gap the ranking puts between them, and that spread is printed at the top of the page rather than in a footnote. A single global order is not yet what this data supports, and the page says so before it shows you one.</p>
<p>Roster membership follows what a tool is for, not whether I managed to automate it. An app I cannot drive is an empty cell, and an empty cell is a result.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="add-a-machine">Add a machine<a href="https://getopenscreen.com/blog/2026/09/09/an-export-benchmark-hard-to-fake/#add-a-machine" class="hash-link" aria-label="Direct link to Add a machine" title="Direct link to Add a machine" translate="no">​</a></h2>
<p>The hardware coverage is thin, and it shows in the spread above. A run needs any two tools and takes one command:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">node bench.mjs run --bundle commons-upload --apps &lt;two or more tools&gt;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">node bench.mjs submit --run &lt;runId&gt; --as "your name" &gt; submissions/&lt;platform&gt;/&lt;chip&gt;-&lt;date&gt;.json</span><br></div></code></pre></div></div>
<p>Open a pull request. CI validates it against the schema and regenerates the site, so the table on this page moves as soon as it merges. The footage comes from permanent Wikimedia URLs with a hash, so two machines can prove they measured the same thing. It is MIT, and the results page is the repo's own output: <a href="https://github.com/EtienneLescot/screen-recorder-benchmark" target="_blank" rel="noopener noreferrer" class="">EtienneLescot/screen-recorder-benchmark</a>.</p>
<p>Building it this way meant accepting the answer before knowing it, on every machine anyone adds. A benchmark whose author always wins is a marketing page.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="benchmark" term="benchmark"/>
        <category label="performance" term="performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Crash-safe recordings, and an app you can install]]></title>
        <id>https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/</id>
        <link href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/"/>
        <updated>2026-08-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[By v1.10.0, OpenScreen was in the Microsoft Store and on Fedora, and Windows and macOS capture wrote fragmented MP4, so a crash leaves a playable file.]]></summary>
        <content type="html"><![CDATA[<p>Two things in this stretch matter more than the version numbers. Capture on Windows and macOS now writes fragmented MP4, so a recorder that dies halfway through leaves you a playable file instead of a corrupt one. And the app finally installs the way people on each platform expect it to.</p>
<p>That is <a href="https://github.com/getopenscreen/openscreen/releases/tag/v1.10.0" target="_blank" rel="noopener noreferrer" class="">v1.10.0</a>, August 24. Before it, v1.9.0 through v1.9.6 in under two weeks.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="losing-a-recording-used-to-be-possible">Losing a recording used to be possible<a href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/#losing-a-recording-used-to-be-possible" class="hash-link" aria-label="Direct link to Losing a recording used to be possible" title="Direct link to Losing a recording used to be possible" translate="no">​</a></h2>
<p>A screen recorder that can lose the take is not a screen recorder. The old capture path wrote a single MP4 whose index is finalised at the end, so a helper crash, a forced quit or a dead battery left a file no player could open. The recording had happened. It was just unreadable.</p>
<p>Capture on Windows and macOS writes fragmented MP4 now. The file is valid at every fragment boundary, so whatever was captured before the process died is still there and still plays. Linux still writes a plain MP4, so a crash there can still cost the file.</p>
<p>The same release stopped two other ways to lose work. The native webcam stream writes to disk while it records, so killing a recording can't take the camera track with it, and the Windows capture helper stopped hanging on stop, which used to require killing the process and losing the file.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-you-can-install-it-now">Where you can install it now<a href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/#where-you-can-install-it-now" class="hash-link" aria-label="Direct link to Where you can install it now" title="Direct link to Where you can install it now" translate="no">​</a></h2>
<p>Most of v1.10.0 was packaging. Distribution is where free desktop software quietly fails: the build works, and nobody can get it.</p>
<p><strong>Windows.</strong> The appx goes to the Microsoft Store from the release build, with branded tiles. That is the route I'd recommend on Windows now, and the <a class="" href="https://getopenscreen.com/docs/installation/">installation docs</a> walk through it. winget stopped skipping silently. There is no Visual C++ Redistributable dependency any more, and the OpenMP runtime the transcription backends actually import is bundled, so transcription works on a clean machine.</p>
<p><strong>Linux.</strong> Fedora RPM (<a href="https://github.com/getopenscreen/openscreen/pull/101" target="_blank" rel="noopener noreferrer" class="">@Mundo-Dev0ps</a>), a source build that completes on ARM64 machines (<a href="https://github.com/getopenscreen/openscreen/pull/293" target="_blank" rel="noopener noreferrer" class="">@zebster-cmd</a>), and DMA-BUF negotiation so capture works on niri and other wlroots compositors, which had no working screen recorder from this project at all. Packages now respect the glibc floor of the distros they claim to target, declared and proven on a clean machine, and AppStream metadata is in place for Flathub. The released packages, all x64, are on the <a class="" href="https://getopenscreen.com/download/">download page</a>.</p>
<p><strong>macOS.</strong> The Homebrew cask job now reports that it published nothing, instead of passing silently.</p>
<p>Capture is also DPI-aware and stops guessing which monitor you meant, and there is a GPU DXGI encode path behind a flag, opt-in until it earns the default.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="v190-three-weeks-earlier">v1.9.0, three weeks earlier<a href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/#v190-three-weeks-earlier" class="hash-link" aria-label="Direct link to v1.9.0, three weeks earlier" title="Direct link to v1.9.0, three weeks earlier" translate="no">​</a></h2>
<p>v1.9.0 shipped August 5, the day after v1.8.0 was promoted. That is a backed-up queue rather than speed: the 1.8.0 RC window ran through nine candidates while <code>main</code> kept moving. The frozen release branch is the only reason the two didn't tangle.</p>
<p>Two features in it:</p>
<ul>
<li class="">Teleprompter mode in the notes window. Your script scrolls next to the capture, mirrored so it reads right in a webcam (<a href="https://github.com/getopenscreen/openscreen/pull/152" target="_blank" rel="noopener noreferrer" class="">@My-Denia</a>).</li>
<li class="">A CLI with <code>record</code>, <code>export</code> and <code>info</code>, driving the same engine the app does, which makes OpenScreen usable from a script (<a href="https://github.com/getopenscreen/openscreen/pull/176" target="_blank" rel="noopener noreferrer" class="">@PeterTakahashi</a>). Recording still needs a real desktop session, as the <a class="" href="https://getopenscreen.com/docs/cli/">CLI docs</a> explain.</li>
</ul>
<p>It also removed a PID-file instance lock that could permanently brick startup, notarized macOS RCs like stable builds, and made the AppX package declare all 13 locales instead of one.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-changed-in-the-patch-releases">What changed in the patch releases<a href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/#what-changed-in-the-patch-releases" class="hash-link" aria-label="Direct link to What changed in the patch releases" title="Direct link to What changed in the patch releases" translate="no">​</a></h2>
<p>v1.9.1, v1.9.2, v1.9.5 and v1.9.6 went out over ten days. 1.9.3 and 1.9.4 never left RC and their fixes rolled forward.</p>
<p>Roundness, shadow and motion blur are on by default now, which is the look most people were assembling by hand on every project. The Windows cursor sampler became DPI-aware. The chat agent learned <code>addTrims</code> and <code>addZooms</code>, so asking it for a cut stopped costing a round trip through a slower path.</p>
<p>Every release's regression pass is written up in the repo's testing docs, including the ones that caught a candidate breaking something. This site was rebuilt in the same window, and gained its light theme.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="on-main-right-now">On <code>main</code> right now<a href="https://getopenscreen.com/blog/2026/08/24/store-and-crash-safe-recordings/#on-main-right-now" class="hash-link" aria-label="Direct link to on-main-right-now" title="Direct link to on-main-right-now" translate="no">​</a></h2>
<p>Webcam background effects have landed on all three compositor backends. Blur or replace what is behind you, including an AI cutout that doesn't need a green screen. The transcription helper reports its real timing and which compute backend it used, so "how long will this take" has an answer instead of a progress bar with no scale.</p>
<p>Still open: hardware encode on Linux, and measurements on discrete GPUs and QSV. It is still not production-grade, so rough edges are expected and bug reports are welcome.</p>
<p>Three months, ten releases. <a href="https://getopenscreen.com/discord/" target="_blank" rel="noopener noreferrer" class="">Discord</a> is open if you want to argue with any of it.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="release" term="release"/>
        <category label="distribution" term="distribution"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[v1.8.0, local whisper and a Rust compositor]]></title>
        <id>https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/</id>
        <link href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/"/>
        <updated>2026-08-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Export went from about 8 fps to about 126 fps on one laptop. Plus an opt-in AI layer: Whisper runs locally, chat goes to the LLM provider you connect.]]></summary>
        <content type="html"><![CDATA[<p>Exporting a 1080p60 project with full effects used to run at about 8 fps. The same project now exports at about 126 fps on the same laptop. The bottleneck was never the encoder, which is the part of this worth writing down.</p>
<p><a href="https://github.com/getopenscreen/openscreen/releases/tag/v1.8.0" target="_blank" rel="noopener noreferrer" class="">v1.8.0</a> shipped that on August 4, alongside an optional AI editing layer. It transcribes on your own machine, and chat edits go to the LLM provider you connect.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-ai-layer">The AI layer<a href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/#the-ai-layer" class="hash-link" aria-label="Direct link to The AI layer" title="Direct link to The AI layer" translate="no">​</a></h2>
<p>It is off by default. If you never turn it on, nothing downloads, no model is contacted, and you have exactly the 1.7.0 feature set. That was in the roadmap from week one and I don't intend to change it.</p>
<p>Turn it on and you get four things.</p>
<p><strong>Transcription on your machine.</strong> Whisper via whisper.cpp, with Metal on Apple Silicon, Vulkan on Windows and Linux, CPU everywhere else. DTW word timestamps. Nothing is uploaded, and after a one-time model download it works offline.</p>
<p><strong>Editing through the transcript.</strong> Select words, delete them, the span is cut from playback and export. Word boundaries get re-anchored against the audio so the cut lands where the word actually starts.</p>
<p><strong>Captions derived from the transcript</strong>, instead of generated once and then maintained by hand. Restyle or regroup them with no regeneration step. Translation into 15 languages if you want it, through the LLM provider you connect for chat. The <a class="" href="https://getopenscreen.com/docs/captions/">captions docs</a> cover styling and translation.</p>
<p><strong>Editing by chat.</strong> Describe an edit in plain language and an agent applies real timeline operations: cuts, zooms, speed ramps, annotations, camera framing. <code>Ctrl/Cmd + Z</code> undoes an agent edit the same way it undoes yours, with per-message rewind.</p>
<p>The chat uses your own LLM key. Anthropic, OpenAI, Google, Mistral, OpenRouter, MiniMax, or anything OpenAI-compatible. Keys are stored encrypted through your OS's credential protection, and requests go from your machine straight to the provider. There is no OpenScreen server in the middle, because there is no OpenScreen server. Setup is in the <a class="" href="https://getopenscreen.com/docs/ai-editing/">AI editing docs</a>.</p>
<p>1.8.0 also <em>removed</em> the ChatGPT and GitHub Copilot sign-in options the pre-fork codebase had. Using someone's existing subscription there meant shipping GitHub's and OpenAI's own client IDs against endpoints they reserve for their own clients, from inside a signed installer. I didn't want to be in that position. If those vendors open a sanctioned surface, the integrations come back.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-compositor">The compositor<a href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/#the-compositor" class="hash-link" aria-label="Direct link to The compositor" title="Direct link to The compositor" translate="no">​</a></h2>
<p>Export at 1080p60 with full effects ran at roughly 8 fps. The same project now runs at roughly 126 fps on the same laptop, an AMD Ryzen 5 7520U with its passive integrated Radeon. That machine is deliberately weak. Your number will be different. The order of magnitude is the point.</p>
<p>It is one GPU-resident chain with no CPU readback between stages:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">demux -&gt; hardware decode -&gt; GPU composite -&gt; RGB to NV12 -&gt; hardware encode -&gt; MP4 mux</span><br></div></code></pre></div></div>
<p>I didn't set out to rewrite it. I first rebuilt the Canvas2D compositor to cache by what invalidates a cache instead of by layer. That was worth about 2x, and I verified it byte-identical (SSIM 1.000000 across all 1418 frames of the reference export). What it really did was make the profile readable: compositing was 79% of the time, encoding was 4.5%. The bottleneck was the compositor, running on the CPU inside a browser.</p>
<p>Preview and export now both consume the same <code>SceneDescription</code> the app builds, so there is no second renderer to drift. The frame in the editor is the frame that gets written.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="three-backends">Three backends<a href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/#three-backends" class="hash-link" aria-label="Direct link to Three backends" title="Direct link to Three backends" translate="no">​</a></h2>
<table><thead><tr><th>Backend</th><th>Stack</th></tr></thead><tbody><tr><td>Windows</td><td>Direct3D 11, HLSL, D3D11VA decode, hardware encode</td></tr><tr><td>macOS</td><td>Metal (all nine shader entry points ported to MSL), VideoToolbox decode/encode, CoreText text rasterizer</td></tr><tr><td>Linux</td><td>wgpu/WGSL, software H.264 encode, MP4 mux with AAC audio</td></tr></tbody></table>
<p>There is a CPU backend too, software render and decode, picked automatically when there is no usable GPU. The UI tells you when you are on it, so a slow export has a visible reason.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-macos-decode-detour">The macOS decode detour<a href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/#the-macos-decode-detour" class="hash-link" aria-label="Direct link to The macOS decode detour" title="Direct link to The macOS decode detour" translate="no">​</a></h3>
<p>Profiling the first working Metal export showed 74% of wall time in decode. The compositor was at 0.2 ms/frame. The hardware decoder pays a fixed per-frame latency, and OpenScreen's own capture writes Constrained Baseline H.264, which software decodes in a few hundred microseconds.</p>
<p>So the decoder is picked by profile now. Baseline goes to software, which came out 2.4x faster end-to-end on the test export (182 fps against 76). High, HEVC and 4K go to VideoToolbox, where the arbitration flips the other way.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="still-open">Still open<a href="https://getopenscreen.com/blog/2026/08/04/local-whisper-and-a-rust-compositor/#still-open" class="hash-link" aria-label="Direct link to Still open" title="Direct link to Still open" translate="no">​</a></h2>
<p>Hardware encode on Linux. It is correct today and slower for being software. And every number above comes from one weak laptop, so discrete GPUs and Intel QSV still need real measurements. Update, September 2026: since v1.11.0, H.264 export on Linux uses VAAPI when the driver and GPU support it, and falls back to software otherwise. H.265 on Linux is still software. The <a class="" href="https://getopenscreen.com/docs/export/">export docs</a> cover the render path, and the <a class="" href="https://getopenscreen.com/download/">download page</a> has the current release.</p>
<p>Next: v1.9.0 through v1.9.6 in twelve days, and v1.10.0.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="release" term="release"/>
        <category label="ai" term="ai"/>
        <category label="performance" term="performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[v1.7.0 was mostly written by people I'd never met]]></title>
        <id>https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/</id>
        <link href="https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/"/>
        <updated>2026-07-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Eight first-time contributors shipped most of v1.7.0, including memory-safe long recordings. v1.6.0 built the release process that made merging safe.]]></summary>
        <content type="html"><![CDATA[<p>Two releases in the first month, <a href="https://github.com/getopenscreen/openscreen/releases/tag/v1.6.0" target="_blank" rel="noopener noreferrer" class="">v1.6.0</a> on July 4 and <a href="https://github.com/getopenscreen/openscreen/releases/tag/v1.7.0" target="_blank" rel="noopener noreferrer" class="">v1.7.0</a> on July 19. The second one is the one worth writing about. Eight people who had never touched the project shipped most of it, and several of those changes fix things that had been broken since before the archive.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="v160-so-that-merging-is-safe">v1.6.0, so that merging is safe<a href="https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/#v160-so-that-merging-is-safe" class="hash-link" aria-label="Direct link to v1.6.0, so that merging is safe" title="Direct link to v1.6.0, so that merging is safe" translate="no">​</a></h2>
<p>The fork inherited a codebase with no release candidate process. Merging a stranger's PR into a project with no RC step means the first person to find the regression is a user, so this came first: RC tags, a promote workflow, release notes generated from the PR history.</p>
<p>The Windows Graphics Capture helper, the native code that does the actual recording on Windows, got per-step stop timing and a diagnostic tool. "Recording fails on stop" is not a fixable bug report when all you know is that it failed, and it was the most common one.</p>
<p>The Linux HUD got its drag handle back. The overlay's pointer-events handling made the bar unmovable there, which nobody had noticed because nobody on the original team ran Linux.</p>
<p>Three PRs from outside landed in this one: the macOS cursor offset in single-window capture (<a href="https://github.com/getopenscreen/openscreen/pull/22" target="_blank" rel="noopener noreferrer" class="">@giulio333</a>), copy/paste for timeline region attributes (<a href="https://github.com/getopenscreen/openscreen/pull/33" target="_blank" rel="noopener noreferrer" class="">@446f6e6e79</a>), and a CI refactor (<a href="https://github.com/getopenscreen/openscreen/pull/40" target="_blank" rel="noopener noreferrer" class="">@psychosomat</a>).</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-release-branch-rule">The release branch rule<a href="https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/#the-release-branch-rule" class="hash-link" aria-label="Direct link to The release branch rule" title="Direct link to The release branch rule" translate="no">​</a></h3>
<p>If you maintain something with a promote step, this is the part to steal. One release branch per stable version, cut at the RC, frozen until promote. Only cherry-picked bugfixes land on it, and anything merged to <code>main</code> after the cut ships in the next cycle.</p>
<p>I wrote that rule after the promote workflow tagged the tip of <code>main</code> instead of the RC snapshot people had tested. The release went out containing commits nobody had signed off on, and I replayed it. The rule is in the repo docs now and every release since has followed it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="v170">v1.7.0<a href="https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/#v170" class="hash-link" aria-label="Direct link to v1.7.0" title="Direct link to v1.7.0" translate="no">​</a></h2>
<p>Eight first-time contributors:</p>
<ul>
<li class="">Large recordings stream instead of loading into memory. The editor and exporter used to run out of RAM on long captures, which made the app unusable for exactly the recordings people care most about (<a href="https://github.com/getopenscreen/openscreen/pull/74" target="_blank" rel="noopener noreferrer" class="">@rainyflash</a>).</li>
<li class="">A software H.264 fallback for Windows machines whose hardware encoder is missing or locked, which is a large share of corporate laptops (<a href="https://github.com/getopenscreen/openscreen/pull/73" target="_blank" rel="noopener noreferrer" class="">@My-Denia</a>).</li>
<li class="">The webcam recorder now starts after native macOS capture does, so the first seconds of camera footage stop vanishing (<a href="https://github.com/getopenscreen/openscreen/pull/85" target="_blank" rel="noopener noreferrer" class="">@josiahcoad</a>).</li>
<li class="">A fix for the cursor drifting out of place after a crop (<a href="https://github.com/getopenscreen/openscreen/pull/65" target="_blank" rel="noopener noreferrer" class="">@SakuraiSatoru</a>).</li>
<li class="">A notes window that capture ignores, so you can keep your script beside the recording without it showing up in the video (<a href="https://github.com/getopenscreen/openscreen/pull/43" target="_blank" rel="noopener noreferrer" class="">@Itzadetunji</a>).</li>
<li class="">Playback speed up to 100x, for finding the one moment you want in an hour of footage (<a href="https://github.com/getopenscreen/openscreen/pull/80" target="_blank" rel="noopener noreferrer" class="">@rainyflash</a>).</li>
<li class="">The Full Camera timeline effect. Press a key and the webcam PiP grows to fullscreen for a stretch, then eases back (<a href="https://github.com/getopenscreen/openscreen/pull/66" target="_blank" rel="noopener noreferrer" class="">@rodrvc</a>).</li>
<li class="">A custom gradient editor for backgrounds (<a href="https://github.com/getopenscreen/openscreen/pull/81" target="_blank" rel="noopener noreferrer" class="">@psychosomat</a>).</li>
</ul>
<p>The platform work in that release was mine. Preview recovery from WebGL context loss on Linux and Wayland. Vulkan off on Wayland so PipeWire capture can import DMA-BUF frames. webm duration patching rewritten so hour-long recordings stop killing the editor on load.</p>
<p>Full Camera and speed regions are covered in the <a class="" href="https://getopenscreen.com/docs/editing-timeline/">timeline docs</a>, and the <a class="" href="https://getopenscreen.com/download/">download page</a> has the current build.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-matters-more-than-the-feature-list">Why this matters more than the feature list<a href="https://getopenscreen.com/blog/2026/07/19/eight-first-time-contributors/#why-this-matters-more-than-the-feature-list" class="hash-link" aria-label="Direct link to Why this matters more than the feature list" title="Direct link to Why this matters more than the feature list" translate="no">​</a></h2>
<p>An archived repo with 39k stars has a lot of people sitting on fixes they wrote for themselves and never upstreamed, because there was nobody to merge them. Reopening the repo released about a month of accumulated work in two weeks, from people who had already done it.</p>
<p>That is the argument for continuing an archived project rather than starting a new one. The users are already there and some of them are already contributors.</p>
<p>Next: v1.8.0, where an AI layer and a whole new rendering engine shipped under one version number.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Picking up OpenScreen]]></title>
        <id>https://getopenscreen.com/blog/2026/06/15/picking-up-openscreen/</id>
        <link href="https://getopenscreen.com/blog/2026/06/15/picking-up-openscreen/"/>
        <updated>2026-06-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The original repo was archived after v1.5.0. I forked it, kept the name and the MIT license, and moved it to a new home.]]></summary>
        <content type="html"><![CDATA[<p>The last commit on <a href="https://github.com/siddharthvaddem/openscreen" target="_blank" rel="noopener noreferrer" class="">siddharthvaddem/openscreen</a> landed on June 6, 2026. It bumped the Nix package to v1.5.0. Then the repo went read-only, like the README had been warning it would for a while. 39k stars, and v1.5.0 as the final release.</p>
<p>I picked it up on June 15, with <a href="https://github.com/siddharthvaddem/openscreen#readme" target="_blank" rel="noopener noreferrer" class="">the original author's approval</a>. Same name, same MIT license, new URL. This post starts a journal of what happens next.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-it-lives-now">Where it lives now<a href="https://getopenscreen.com/blog/2026/06/15/picking-up-openscreen/#where-it-lives-now" class="hash-link" aria-label="Direct link to Where it lives now" title="Direct link to Where it lives now" translate="no">​</a></h2>
<p><a href="https://github.com/getopenscreen/openscreen" target="_blank" rel="noopener noreferrer" class="">github.com/getopenscreen/openscreen</a>. It started as a personal fork and moved under the <code>getopenscreen</code> org in the first week. It stays there. Installers are on the <a class="" href="https://getopenscreen.com/download/">download page</a>, and the <a class="" href="https://getopenscreen.com/docs/intro/">docs</a> cover installing, recording, editing and export.</p>
<p>The archived original is still online and still read-only. Every commit of it is in this repo's history.</p>
<p>I tagged v1.5.0 on day one with no code changes at all. Same code, same installer, same version number. It only exists to prove the release pipeline works on my infrastructure before anything real ships through it. v1.6.0 is the first release with new work in it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-im-committing-to">What I'm committing to<a href="https://getopenscreen.com/blog/2026/06/15/picking-up-openscreen/#what-im-committing-to" class="hash-link" aria-label="Direct link to What I'm committing to" title="Direct link to What I'm committing to" translate="no">​</a></h2>
<p>Forking a popular archived project is a good way to quietly turn it into something else. So, written down where you can hold me to it:</p>
<ul>
<li class="">Free forever, MIT. No paid tier, no premium features, no usage caps. Nothing is gated on who you are.</li>
<li class="">Stability before features. The recorder has to work on macOS, Windows and Linux. Bugs from real users go first.</li>
<li class="">It's not production-grade, and I'll keep saying so. Expect rough edges and breaking changes, including to the project format.</li>
</ul>
<p>The <a href="https://github.com/getopenscreen/openscreen/blob/main/ROADMAP.md" target="_blank" rel="noopener noreferrer" class="">roadmap</a> is public: record, edit, export, plus an optional AI editing layer that's off by default and never required. There's a <a href="https://getopenscreen.com/discord/" target="_blank" rel="noopener noreferrer" class="">Discord</a> with a roadmap channel if you want to argue about any of it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="it-already-had-contributors">It already had contributors<a href="https://getopenscreen.com/blog/2026/06/15/picking-up-openscreen/#it-already-had-contributors" class="hash-link" aria-label="Direct link to It already had contributors" title="Direct link to It already had contributors" translate="no">​</a></h2>
<p>Four days in, before I'd shipped anything, someone I'd never met opened <a href="https://github.com/getopenscreen/openscreen/pull/4" target="_blank" rel="noopener noreferrer" class="">a fix for exports stalling</a> when trim regions leave long decoder gaps. Real bug, correct diagnosis, regression test included.</p>
<p>That's roughly what the job turned out to be. Very little of it is features. Mostly it's release candidates that mean something, CI that fails loudly, and diagnostics for the parts that break on other people's machines. Native capture on Windows and macOS is as finicky as its reputation.</p>
<p>I'll write up what ships and what breaks here. Next: v1.6.0 and v1.7.0.</p>]]></content>
        <author>
            <name>Etienne Lescot</name>
            <uri>https://github.com/EtienneLescot</uri>
        </author>
        <category label="announcement" term="announcement"/>
    </entry>
</feed>