How the Convert Repository Performs File Conversions Entirely in the Browser

The convert repository performs file conversions entirely in the browser by chaining WebAssembly (WASM) wrappers for native tools like FFmpeg and ImageMagick, orchestrated through a client-side pathfinding engine that determines optimal conversion sequences without any server interaction.

The p2r3/convert project is an open-source file conversion tool that performs file conversions entirely in the browser, eliminating the need for server uploads or native software installations. By leveraging WebAssembly modules and a sophisticated graph-based routing system implemented in TypeScript, this browser-based converter chains multiple native tools client-side to transform files between dozens of formats.

Core Architecture of the Browser-Based Converter

UI and Orchestration Layer

In src/main.ts, the application handles file selection, format detection, and conversion orchestration. The fileSelectHandler function (lines 89-151) extracts MIME types from user files and populates the available format lists, while the convertButton.onclick handler (lines 311-360) triggers the conversion pipeline that performs file conversions entirely in the browser.

Format Definitions and Handlers

The src/FormatHandler.ts file defines the core interfaces: FileFormat describes MIME types and extensions, while FormatHandler specifies the contract that every conversion wrapper must implement. Each handler in src/handlers/ wraps a specific WASM library:

  • FFmpeg.ts: Wraps the FFmpeg WASM core for video and audio processing
  • ImageMagick.ts: Handles raster and vector image conversions via the Magick WASM module
  • libopenmpt: Supports tracker music formats (referenced in the handlers index)

The TraversionGraph Pathfinding Engine

The src/TraversionGraph.ts module constructs a directed graph where nodes represent MIME types and edges represent available conversions. When the convert repository performs file conversions entirely in the browser, this graph runs a Dijkstra-style search to find the optimal path, considering factors like lossiness, category changes, handler priority, and previously failed "dead-ends."

The attemptConvertPath function in src/main.ts (lines 171-247) walks the path returned by TraversionGraph.searchPath(), calling each handler's doConvert() method sequentially until the final format is reached.

How WASM Enables Serverless Conversion

WebAssembly Module Loading

Each handler initializes its WASM binary via fetch() requests. For example, the FFmpeg handler loads /convert/wasm/ffmpeg-core.js, while ImageMagick loads /convert/wasm/magick.wasm. These binaries execute inside sandboxed WebAssembly virtual machines, ensuring the convert repository can perform file conversions entirely in the browser without executing native code on the host OS.

Zero-Copy Byte Handling

The repository uses efficient binary handling throughout the pipeline:

  1. Input files are read using File.arrayBuffer() and converted to Uint8Array
  2. Handlers receive these buffers directly without string conversion overhead
  3. Output buffers return as Uint8Array and convert to downloadable Blobs via URL.createObjectURL()

Pure-Client Orchestration

All decision-making, graph construction, and error handling run as ordinary JavaScript/TypeScript on the main thread. The UI remains responsive during long conversions through requestAnimationFrame yields, ensuring smooth performance while the convert repository performs file conversions entirely in the browser.

Practical Implementation Examples

Standard UI Workflow

The typical user interaction flows through index.html elements controlled by src/main.ts:

<input id="file-input" type="file" multiple hidden />
<div id="file-area">Drop files here or click</div>
<div id="from-list" class="format-list"></div>
<div id="to-list" class="format-list"></div>
<button id="convert-button" class="disabled">Convert</button>

When a user drops a file, fileSelectHandler extracts the MIME type, auto-selects the matching input format, and populates the format lists. Pressing Convert triggers the pipeline that allows the convert repository to perform file conversions entirely in the browser.

Programmatic Conversion API

Developers can embed the conversion engine directly:

import handlers from "./src/handlers/index.js";
import { TraversionGraph } from "./src/TraversionGraph.js";
import { ConvertPathNode } from "./src/FormatHandler.js";

// Initialize all WASM handlers
await Promise.all(handlers.map(h => h.init()));
const cache = new Map<string, FileFormat[]>();
handlers.forEach(h => cache.set(h.name, h.supportedFormats ?? []));

// Build conversion graph
const graph = new TraversionGraph();
graph.init(cache, handlers);

// Define source and target formats (example: PNG to MP4)
const srcFormat = cache.get("ImageMagick")!.find(f => f.mime === "image/png")!;
const dstFormat = cache.get("FFmpeg")!.find(f => f.mime === "video/mp4")!;

// Create path nodes
const fromNode = new ConvertPathNode(handlers.find(h => h.name === "ImageMagick")!, srcFormat);
const toNode = new ConvertPathNode(handlers.find(h => h.name === "FFmpeg")!, dstFormat);

// Find optimal conversion path
const pathIter = graph.searchPath(fromNode, toNode, true);
const path = (await pathIter.next()).value;

// Execute conversion chain
let fileData = [{ name: "example.png", bytes: await pngFile.arrayBuffer() as Uint8Array }];
for (let i = 0; i < path.length - 1; ++i) {
  const handler = path[i + 1].handler;
  const inFmt = path[i].format;
  const outFmt = path[i + 1].format;
  fileData = await handler.doConvert(fileData, inFmt, outFmt);
}

This mirrors the attemptConvertPath logic in src/main.ts while exposing the underlying TraversionGraph API for custom workflows that perform file conversions entirely in the browser.

Summary

  • The convert repository performs file conversions entirely in the browser by chaining WebAssembly wrappers for native tools like FFmpeg and ImageMagick.
  • The TraversionGraph in src/TraversionGraph.ts implements a Dijkstra-style pathfinding algorithm to determine optimal conversion sequences across multiple handlers.
  • Zero-copy byte handling ensures efficient data flow from File.arrayBuffer() through WASM handlers to downloadable output Blobs without server interaction.
  • Each FormatHandler in src/handlers/ initializes its WASM module via fetch() and executes conversions through sandboxed WebAssembly virtual machines.
  • The UI layer in src/main.ts orchestrates the entire pipeline from file selection through path execution to final download, all within the browser context.

Frequently Asked Questions

How does the convert repository determine which conversion path to use?

The repository uses the TraversionGraph class in src/TraversionGraph.ts to construct a directed graph where nodes represent MIME types and edges represent possible conversions provided by handlers. When processing a request, it runs a Dijkstra-style search that considers factors like lossiness, category changes, handler priority, and previously failed "dead-ends" to find the optimal sequence. The searchPath() method returns an iterator of possible paths, allowing the system to attempt alternatives if intermediate conversions fail.

What WebAssembly libraries power the browser-based conversions?

According to the handler implementations in src/handlers/, the repository wraps several industry-standard native tools compiled to WebAssembly. These include FFmpeg (src/handlers/FFmpeg.ts) for video and audio processing, ImageMagick (src/handlers/ImageMagick.ts) for image format conversions, and libopenmpt for tracker music formats. Each handler fetches its respective WASM binary—such as /convert/wasm/ffmpeg-core.js or /convert/wasm/magick.wasm—and executes conversions inside sandboxed WebAssembly virtual machines.

How does the convert repository handle large files without freezing the browser?

The repository maintains UI responsiveness through several mechanisms. All conversion orchestration in src/main.ts uses pure JavaScript on the main thread with requestAnimationFrame yields to prevent blocking during long operations. The system employs zero-copy byte handling, using File.arrayBuffer() and Uint8Array buffers to stream data directly into WASM handlers without string conversion overhead. Additionally, the TraversionGraph pathfinding runs client-side, allowing the browser to manage memory and processing without server round-trips that could introduce latency.

Can developers add support for new file formats to the convert repository?

Yes, developers can extend the system by implementing the FormatHandler interface defined in src/FormatHandler.ts. A new handler must expose a name property, a supportedFormats array describing MIME types and extensions, an init() method that loads the WebAssembly module via fetch(), and a doConvert() method that accepts Uint8Array input and returns converted Uint8Array output. After implementation, the handler must be exported from src/handlers/index.ts to be automatically registered with the TraversionGraph during initialization, immediately making its conversion capabilities available to the pathfinding engine.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →