Skip to the content.

Themes — the .bftheme format

One JSON file = one complete look: visual mode + parameters, background, text/logo layers (assets embedded as data URLs), timeline scenes, post chain, motion masters, plus metadata. Import by dropping the file onto the app window — the same drop imports every sibling format the app writes: .bfpreset looks, .bfbuilder stacks, .bfshader shaders and .bfproj projects. Export via Visuals ▸ Looks & themes ▸ Save as theme…

Themes contain no code. A theme can only select and parameterize the app’s built-in visuals, so importing one is exactly as safe as clicking around the UI. Share them anywhere — Discord, a zip, a link. The sharing channel with a front door is the in-app Gallery: a public, curated collection of looks and themes backed by beatform-app/gallery, where every entry is pinned to an immutable version and checksum-verified before it is parsed. Submissions are reviewed there as pull requests; node scripts/gallery-submit.mjs turns your file into a ready PR body.

File layout

{
  "kind": "bftheme",
  "schemaVersion": 1, // .bftheme format version
  "projectSchemaVersion": 14, // embedded document schema (same as .bfproj)
  "appVersion": "2.108.0", // the app version that wrote it (informational)
  "meta": {
    "name": "Midnight Phonk", // required
    "author": "you", // defaults to "unknown"
    "license": "CC0-1.0", // defaults to "unspecified"
    "description": "…", // optional
    "bpmHint": [120, 165], // optional [lo, hi] — a hint, not a gate
    "thumbnail": "data:image/png;base64,…", // optional, inline images only
  },
  "document": {
    "presetId": "bass-circle",
    "paramsByPreset": { "bass-circle": { "hue": 20 } }, // partial: rest = defaults
    "syncByPreset": { "bass-circle": { "mode": "kick", "smooth": 0.35 } },
    "bg": { "mode": 0, "color": [0, 0, 0] },
    "overlayLayers": [],
    "assets": {},
    "aspect": "16:9",
    "modsByPreset": {},
    "smoothSpectrum": false,
    "timeline": { "enabled": false, "scenes": [], "lanes": [] },
    "post": {
      "bloom": 0.45,
      "bloomThreshold": 0.8,
      "exposure": 1,
      "tonemap": true,
      "vignette": 0.35,
      "grain": 0,
      "chromatic": 0,
    },
    "motion": { "rotation": 1, "pulse": 1, "detail": 1, "spectrumSmooth": 0 },
  },
}

Compatibility rules

Authoring tips