Vagibond

Follow Vagibond

Stay connected with us on social media for updates on new ventures.

Thanks for subscribing!
Try Beat Off

BeatOff API

An embeddable A/B elimination bracket widget. Display two content cards side by side, let users pick a winner, replace the loser with a new challenger. The loop never ends.

🥊
New Release
BeatOff is freshly launched. Perfect for music battles, quote comparisons, image face-offs, and anything else that needs endless user engagement with zero purpose.

What you can build

Live Demo

See what you can build with the BeatOff API.

BeatOff Demo

Quickstart

Get up and running with BeatOff in under a minute.

1. Add the widget container

html
<div id="beatoff-widget"
     data-source="beatkids-music"
     data-content-type="audio"
     data-show-leaderboard="true"
     data-show-stats="true">
</div>

2. Include the scripts

html
<!-- BeatKids core for music playback (only needed for audio content) -->
<script src="https://beatkids.vagibond.com/beatkids-core.js"></script>

<!-- BeatOff widget -->
<script src="https://beatkids.vagibond.com/beatoff-core.js" async></script>

That's it! The widget auto-initializes when the page loads.

Configuration

Configure the widget via data attributes or the JavaScript API:

Attribute Type Default Description
data-sourcestring'beatkids-music'Content source identifier from beatoff.json
data-content-typestring'audio'Content type: 'audio', 'text', 'image', or custom
data-data-urlstring'/data/beatoff.json'URL to fetch content data from
data-show-leaderboardbooleantrueShow the fake leaderboard
data-show-statsbooleantrueShow session stats (time wasted, votes)
data-bg-colorcolor'#0a0a0f'Widget background color
data-primary-colorcolor'#ff00ff'Primary accent color
data-accent-colorcolor'#00ffff'Secondary accent color

init(options)

Manually initialize widgets with custom options:

javascript
BeatOff.init({
  source: 'beatkids-music',
  contentType: 'audio',
  dataUrl: '/data/beatoff.json',
  primaryColor: '#ff00ff',
  onVote: function(winner, loser) {
    console.log('User picked:', winner.title, 'over', loser.title);
  }
});

registerAdapter(type, adapter)

Register a custom content adapter for any content type:

javascript
BeatOff.registerAdapter('grunt', {
  render: function(item, container, config, side) {
    // Render the card HTML
    container.innerHTML = `
      <div class="beatoff-card" data-side="${side}">
        <div class="grunt-text">${item.grunt}</div>
        <button class="beatoff-vote-btn">This One</button>
      </div>
    `;

    // Set up vote handler
    container.querySelector('.beatoff-vote-btn').onclick = () => {
      window.onBeatOffVote(item, side);
    };
  },
  play: function(item) {
    // Optional: play audio/video
    Gruntslate.speak(item.grunt);
  },
  stop: function() {
    // Optional: stop playback
    Gruntslate.stopSpeaking();
  }
});

getStats()

Get current session statistics:

javascript
const stats = BeatOff.getStats();
console.log(stats.votes);      // 42
console.log(stats.timeWasted); // "47m 23s"
console.log(stats.topWinner);  // "bo-003"

getLeaderboard()

Get the user's voting history (merged with fake leaderboard):

javascript
const leaderboard = BeatOff.getLeaderboard();
// { "bo-003": 5, "bo-007": 3, ... }

Audio Content Type

The audio adapter uses BeatKids for live music playback. Each item needs:

json
{
  "id": "bo-001",
  "title": "Dumpster Serenade",
  "artist": "DJ Boxcar",
  "style": "lofi",
  "seed": "dumpster-serenade"
}

Text Content Type

For quotes, verses, or any text content:

json
{
  "id": "quote-001",
  "text": "Life is like a box of chocolates...",
  "author": "Forrest Gump"
}

Image Content Type

For image face-offs:

json
{
  "id": "img-001",
  "url": "https://example.com/image.jpg",
  "title": "A beautiful sunset"
}

Data Structure

The beatoff.json file structure:

json
{
  "sources": {
    "my-source": {
      "type": "audio",
      "label": "My BeatOff",
      "description": "Pick your favorite...",
      "items": [ ... ]
    }
  },
  "leaderboard": {
    "my-source": [
      { "title": "Top Track", "wins": 14847 },
      ...
    ]
  }
}
🎉
Ready to Beat Off?