AboutCapabilitiesPortfolioExplore
Projects
3D Printed Drones
Upgrading Shop Air Compressor
Aluminum Mountains
Layered Backup Workflow
Bosswatt Prototype
Bronco Bumper
Machining a camera mount
Chuck Back Plates
Climbing Wall
CNC Surface Grinder Retrofit
5C Collet Box
Truck Crane Frame Fabrication
Leaf Spring Crossbow
Desktop Organizer
Engraving Tools
Festival Totem
Quick fix: Fixing household goods with a 3d printer
Fixture Table
Pirhana Plant
Building a Generator in Several Distinct Steps
Geodesic Treehouse
Hanging Plotter
Hardtail Mini Bike
Welding an Infinity Cube
Lavender Sculpture
Local LLM
Small part: Mouse Axle
Mr Fixums' Lathe Handwheel Repair
Company Logo Sulpture
Northwest Waxworks
Obsidian Remotion
Penny Fakething Freak Bike
Picture Framing
Building My Portfolio Into a Publishing System
DIY Press Brake
Building the Official Prusa Printer Enclosure out of Ikea Lack Tables
Scale License Plate
Metal Rose
Extending the Shop
Slip Roller
Staübli Reborn: Industrial Robot with a Modern Control System
Full Suspension Mini Bike
Protoyping with python by creating an email task digest
Machining a Tube Bender
Turbofurnace
First Welding Project: Making a Weld Cart
Weld Cart (for everlast)
Welding Positioner

Obsidian Remotion

Software Typescript Obsidian Remotion Developer Tools Project
2026-1-28

I built Obsidian Remotion because I wanted a Markdown note to behave like a Remotion sketchbook.

The practical goal was pretty simple: write prose, drop in ts or tsx blocks, and get live, type-checked Remotion previews in a side pane without cramming React and Remotion into the plugin bundle itself.

That separation ended up being the whole project.

I wanted the plugin to stay relatively small and handle editor integration, diagnostics, preview lifecycle, and UI. I wanted the vault to own node_modules, so the actual React and Remotion runtime stayed under the user’s control. In practice that felt much less cursed than trying to smuggle a whole frontend runtime into an Obsidian plugin and then hoping version skew would somehow be fine.

The repo moved fast. The first commit landed on 2026-01-29, and by 2026-03-06 I already had a standalone remotion-md package, an Obsidian plugin package, runtime packages, a test vault, typechecking, bundling, scroll sync, and a whole lot of churn in the preview and iframe code. Looking back at the history, the arc is pretty clear: first I had to make Markdown extraction and synthesis real, then I had to make previews actually render, and then I had to spend a lot of time on resolution, runtime boundaries, and scroll behavior so the whole thing did not feel fake.

What it does

The workflow I was aiming for is:

  1. extract TypeScript blocks from Markdown
  2. synthesize them into a virtual TSX module
  3. compile TypeScript to JavaScript
  4. bundle user code against the vault’s installed dependencies
  5. render the result in an iframe with the Remotion player

In practice that means a note becomes something closer to a literate animation document than a plain markdown file.

The contract I wrote down in obsidian-remotion/README.md made the intent pretty explicit:

  • Markdown is the host language
  • TypeScript is a guest
  • a .md file defines a sequence
  • top-level JSX can declare scenes
  • default-importing another Markdown file means importing its sequence, not just raw text

That is a pretty opinionated model, and that is why I think it is interesting. I was not trying to make a generic “preview some code fences” plugin. I was trying to define a coherent authoring environment for timeline-shaped documents.

Why I think this project is useful

I could have stopped at “find code fence, run code, show output.” That would have been much easier. It also would have missed the point.

What I actually wanted was a markdown-native environment with enough semantics to support:

  • typechecking against a virtual module
  • scene extraction from JSX entry blocks
  • semantic imports between Markdown files
  • bundling against the vault’s local dependency graph
  • editor diagnostics, hover, and autocomplete
  • synchronized preview navigation instead of a disconnected demo pane

That is the useful part to me: it turns a markdown vault into a place where motion studies can live next to explanation, notes, and composition structure.

Architecture

After many iterations I settled on splitting the concerns into a few bounded domains:

  • remotion-md: extraction, synthesis, compilation, bundling, and shared pipeline logic
  • obsidian-remotion: the actual Obsidian plugin, view wiring, editor integration, status UI, and preview orchestration
  • examples: a test vault with sample markdown notes and package setup

The top-level package.json also pins Remotion package versions across the workspace. That made sense for this project. Even though I wanted the vault to own the runtime, I still needed one stable view of what counted as a compatible toolchain while I was building the plugin and compiler pieces.

obsidian-remotion/src/main.ts is mostly coordination glue, which is exactly what I wanted the plugin layer to be:

  • register the preview pane
  • watch active leaf and editor changes
  • run typecheck and bundling in parallel
  • update status-bar state
  • wire diagnostics, autocomplete, and hover back into the editor

remotion-md/src/pipeline.ts keeps the core flow pretty blunt: extract, classify, synthesize, bundle. I liked ending up there. It meant the compiler-ish parts were not permanently welded to Obsidian APIs.

Development arc

The git history is compact but noisy in a very honest way. Reading through it now, I can see myself making the scary parts executable as quickly as possible and then discovering, one by one, which parts were actually going to be annoying.

Stage 1 — Make the basic model real

The first run of commits on 2026-01-29 is very direct:

  • Initial plugin stub
  • Running plugin
  • 1. Extracting blocks
  • 2: Extraction & 3: Synthesis
  • Implementing 4. Virtual filesystem host

That sequence is basically the initial thesis statement. Before I worried too much about polish, I needed to prove that Markdown could be treated as a source format at all. So I went straight at extraction, synthesis, and a virtual compiler host.

Stage 2 — Get something rendering, then survive the consequences

Once the basic pipeline existed, I moved immediately into previews and bundling:

  • WIP bundler
  • Working remotion example!
  • Using preview function to render previews
  • Basic scene abstraction
  • Rough hanky demo of remotion in obsidian

This is where the idea stopped being theoretical for me. It is also where I started running into the problems that were always lurking under the demo: preview isolation, iframe messaging, scene identity, and the difference between a thing that renders once and a thing that keeps up with editing.

Stage 3 — Scroll sync became its own little monster

A surprising amount of churn landed in scroll and iframe code. The commit subjects tell the story pretty well:

  • Improve scroll sync
  • Mapping preview() locations across the pane
  • Proposal for scroll-sync algorithm
  • Smooth scrolling
  • Fix bidirectional scroll echo prevention
  • Moving mapping to iframe
  • Fix vertical offset in previews

This did not feel decorative. If the promise is “write in the editor, understand the scene in the preview,” then navigation quality is part of the product. Bad sync would make the whole thing feel wonky immediately. I ended up pushing from rough positional behavior toward something more semantic and less fragile.

What got hard

A few recurring problems show up pretty clearly both in the code and in the history.

Module resolution and virtual filesystems

This was one of the main technical fights.

I kept coming back to compiler and resolver code in commits like:

  • WIP: Fixing typescript module resolution
  • WIP: Module resolution. Need cleanup
  • Unified module resolution. Why did this touch every file?
  • Unify module resolution
  • Simplify resolution context

That tracks with the design. Once Markdown files can import other Markdown files, and once bundling needs to work against the vault’s real node_modules, I am no longer doing a simple string transformation. I have to make TypeScript, esbuild, virtual files, and Obsidian editor state all agree on what a path means.

Runtime boundaries

I wrote down pretty early that the iframe should be controlled, sandboxed, and disposable. The later history is basically me paying off that design choice:

  • runtime packages get split out
  • iframe code gets reorganized several times
  • tests move toward postMessage and runtime command coverage
  • bundle injection and runtime handling get reworked more than once

That was the right place to spend effort. A preview system like this only feels trustworthy when runtime failures stay contained and reload behavior gets boring.

Editor-quality feedback

I did not want this to stop at just drawing players. I also wanted the note to feel enough like a real source document that editing it was not miserable.

That is where things like these commits came from:

  • Basic typescript diagnostics
  • WIP: language server
  • tsserver integration improvements

If a note is going to behave like a TSX source document, the editing experience has to meet that claim halfway.

Result

By the end of this burst of work, this was not a toy plugin anymore.

It supported a workflow I actually wanted:

  • write notes as mixed prose and code
  • treat top-level JSX as scene declarations
  • typecheck and bundle against local project dependencies
  • render multiple preview widgets from note content
  • keep preview behavior coordinated with the editor instead of off in its own world

I also still like the architectural constraint I landed on. The plugin is not trying to become the package manager, runtime, renderer, and user project all at once. It mostly coordinates. The vault owns the heavy dependencies. remotion-md owns the compiler-ish steps. That division felt practical then, and it still does.

Trade-offs

I bought flexibility here by accepting some complexity.

The trade looked like this:

  • lighter plugin bundle, but more responsibility pushed into vault setup
  • stronger semantics for markdown imports and scene blocks, but more resolver and compiler machinery
  • better preview isolation through iframes and runtime separation, but more messaging and lifecycle code
  • richer editor integration, but more surface area to test whenever the data flow changed

I do not think that is a bad trade. It is just the actual shape of the project.

What I think this shows

The main story, for me, is that I took a fuzzy but interesting idea — treating Markdown as a host language for timeline-oriented Remotion work inside Obsidian — and pushed it far enough that the hard parts had to become real infrastructure.

That includes:

  • compiler-style transformation of literate source documents
  • virtual filesystem and module resolution work
  • bundling and runtime isolation
  • editor diagnostics and language tooling
  • UI synchronization problems that look simple until they absolutely are not

That is the part I would point at in a portfolio. The project is opinionated about what the tool should feel like, and I kept following that idea into the messy parts instead of backing away once the demo worked.

Status

This history covers a fast burst from late January to early March 2026. It already looks capable to me, but it also still looks alive in the way good tool projects usually do: lots of refactors, lots of tests showing up around runtime boundaries, and several commits that basically amount to “this got weird, I am fixing it anyway.”

Honestly, that makes me trust the result more.

Related Projects:
3D Printed Drones Upgrading Shop Air Compressor Aluminum Mountains Layered Backup Workflow Bosswatt Prototype
Featured Work
Welding PositionerSurface Grinder Retrofit
Company Info
About UsContactAffiliate DisclosurePrivacy Policy
Specific Solutions LLC
Portland, OR