Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/betterspacx/app/llms.txt

Use this file to discover all available pages before exploring further.

Betterflow’s export system is entirely client-side — no files leave your browser unless you choose to download them. Image exports run through a layered compositing pipeline and an optional Sharp API pass for format-specific optimization. Video exports use the best available encoder for the chosen format, with automatic fallback to ensure broad browser compatibility.

Image Export

Static screenshots can be exported as PNG, JPEG, or WebP at up to 5× scale:

Format

PNG preserves transparency (useful when the background is set to transparent). JPEG produces smaller files at the cost of the alpha channel. WebP offers the smallest file size with good quality for web use.

Scale (1×–5×)

Export at 1×, 2×, 3×, 4×, or 5× the canvas pixel dimensions. CSS gradients and vector-like elements scale with no quality loss; raster images are upsampled with high-quality bicubic interpolation.

Quality Preset

Choose High, Medium, or Low quality. For JPEG: 85%, 75%, 60% respectively. For WebP: 82%, 72%, 55%. PNG is always lossless regardless of preset.

Copy to Clipboard

The Copy action runs the same compositing pipeline as a normal export but skips the Sharp API pass (skipSharp: true) for speed. The resulting image blob is written directly to the clipboard via the Clipboard API.

Video Export

Betterflow exports animations as MP4, WebM, or GIF by rendering the animation frame-by-frame and passing the frames through the appropriate encoder.

Encoder Selection

The encoder is chosen automatically based on the requested format and browser capabilities:
Format = GIF   →  FFmpeg WASM (only option for GIF)
Format = WebM  →  MediaRecorder (native browser API)
Format = MP4   →  WebCodecs H.264 (hardware-accelerated)
                    └── if unsupported → FFmpeg WASM (H.264 fallback)
The preferred encoder for MP4. Uses the browser’s VideoEncoder API, which routes to hardware acceleration on supported platforms (Apple Silicon, modern Intel/AMD GPUs). Produces MP4/H.264 output via mp4-muxer — no server required.
// From lib/export/webcodecs-encoder.ts
export function isWebCodecsSupported(): boolean {
  return (
    typeof VideoEncoder !== 'undefined' &&
    typeof VideoFrame !== 'undefined' &&
    typeof EncodedVideoChunk !== 'undefined'
  );
}

// H.264 codec profiles tried in order (highest to lowest)
const codecs = [
  'avc1.640032', // High Profile, Level 5.0 — up to 4K
  'avc1.64002A', // High Profile, Level 4.2 — up to 1080p
  'avc1.640028', // High Profile, Level 4.0
  'avc1.4d0032', // Main Profile, Level 5.0
  'avc1.4d0028', // Main Profile, Level 4.0
  'avc1.42001E', // Baseline Profile, Level 3.0
];
Key-frames are inserted every 2 seconds (frameIndex % (fps * 2) === 0). Backpressure handling yields to the browser if the encoder queue exceeds 8 pending frames.

Quality Presets

All encoders share the same three quality tiers:
PresetBitrate (MediaRecorder)CRF (FFmpeg/WebCodecs)Recommended Use
High25 Mbps18Final delivery, social media uploads
Medium10 Mbps23Web embeds, presentations
Low5 Mbps28Quick shares, messaging apps
CRF 18 is considered “visually lossless” for H.264. For GIF exports, quality is controlled by the palette size (fixed at 256 colors) and the Bayer dithering algorithm — the quality preset does not affect GIF output.

Compositing Pipeline

Every export — image or video frame — follows the same multi-step compositing pipeline:
1

Set Playhead (video only)

For each video frame, the playhead is moved to the corresponding timestamp and getClipInterpolatedProperties computes the animated property values for that moment in time.
2

Capture the Full Canvas

The HTML canvas container (which holds background, image, borders, shadows, and 3D transforms) is captured using domToCanvas from modern-screenshot. If a 3D transform is active, capture3DTransformWithModernScreenshot is used instead for correct perspective rendering.
3

Apply Blur Regions (post-process)

CSS backdrop-filter doesn’t render inside domToCanvas. Any active blur regions are applied as a post-processing step directly on the captured canvas using the Canvas 2D filter: blur() API with a clipping path.
4

Sharp Processing (images only)

The composited canvas is sent to the Sharp API for format-specific optimization: lossless PNG compression, JPEG quality control, and correct color profile embedding. Video frames skip this step — FFmpeg handles compression.
5

Download & Save

The final blob is triggered as a browser download. A copy is also saved to IndexedDB with metadata (format, quality, scale, timestamp, filename) for the export history.

IndexedDB Export Storage

All exports are automatically saved locally in IndexedDB under the exports object store:
// IndexedDB schema for exported files
{
  id: string;          // Unique export ID
  blob: Blob;          // The exported file data
  format: string;      // 'png' | 'jpeg' | 'webp' | 'mp4' | 'webm' | 'gif'
  quality: string;     // 'high' | 'medium' | 'low'
  scale: number;       // Export scale factor
  timestamp: number;   // Unix timestamp
  fileName: string;    // Suggested download filename
}
Export preferences (format, quality, scale) are persisted in a separate export-preferences store and restored automatically the next time you open the editor.
IndexedDB storage is browser-local and private — your exported files never leave your device unless you explicitly download or share them. There is no usage limit imposed by Betterflow, though browsers enforce their own storage quotas.

Progress Tracking

All export operations emit progress events through the useExportProgress hook. A progress bar in the export panel updates in real time:
StageProgress Range
DOM preparation0% → 10%
Canvas capture10% → 55%
Sharp / encoding55% → 90%
Finalization90% → 100%
For video exports, per-frame progress is reported as each frame is encoded, giving a smooth 0–100% indicator across the full encoding run.

Build docs developers (and LLMs) love