Skip to main content
Boofstream automatically detects which characters and costumes players are using by reading data directly from Slippi. This includes special handling for Sheik/Zelda transformations that occur mid-game.

Character and Costume Detection

When a game starts, boofstream captures character and costume information from both players:
realtime.game.start$.subscribe(e => {
    state.slippi = {
        port1: e.players[0].port,
        port2: e.players[1].port,
        character1: e.players[0].characterId,
        character2: e.players[1].characterId,
        characterColor1: parseCharacterColor(e.players[0]),
        characterColor2: parseCharacterColor(e.players[1]),
        // ...
    };
});
Character detection happens automatically at the start of each game. You don’t need to manually select characters in the UI.

Costume Color Parsing

Boofstream converts Slippi’s costume color data into a standardized format:
function parseCharacterColor(player: PlayerType) {
    if (!player.characterColor) {
        return CharacterColor.DEFAULT;
    }
    return CHARACTER_COLORS[player.characterId][player.characterColor - 1];
}

Sheik/Zelda Transform Handling

One of the unique challenges in Melee is handling Sheik and Zelda transformations. Boofstream monitors every frame to detect when a player transforms:

Real-Time Monitoring

Checks every player frame for character changes

Instant Updates

Updates character displays immediately when transforms occur

Bidirectional Support

Handles both Zelda → Sheik and Sheik → Zelda

Port-Aware

Correctly tracks transformations for both players independently

Transform Detection Code

The system uses internal character IDs to detect transforms:
livestream.playerFrame$.subscribe(frame => {
    const internalCharacterId1 = frame.players[slippi.port1 - 1].post.internalCharacterId;
    const internalCharacterId2 = frame.players[slippi.port2 - 1].post.internalCharacterId;

    let updated = false;

    // Zelda (19) transforming to Sheik (7)
    if (internalCharacterId1 == 7 && slippi.character1 === Character.ZELDA) {
        state.slippi.character1 = Character.SHEIK;
        updated = true;
    } else if (internalCharacterId1 == 19 && slippi.character1 === Character.SHEIK) {
        state.slippi.character1 = Character.ZELDA;
        updated = true;
    }

    // Same logic for port 2...
});
Internal character ID 7 represents Sheik, while ID 19 represents Zelda. The system checks for these specific IDs to detect transformations.

Port Matching

Before character data can be displayed correctly, boofstream needs to know which in-game port corresponds to which player:

Port Assignment Flow

  1. Game Starts: Boofstream detects two ports are active
  2. User Assigns Ports: You specify “Player 1 is Port X”
  3. Character Mapping: Characters are mapped to correct players
  4. Display Updates: Character icons appear on correct player cards
if (slippi.player1IsPort1 !== undefined) {
    state.player1.character = slippi.player1IsPort1
        ? slippi.character1
        : slippi.character2;
    state.player1.characterColor = slippi.player1IsPort1
        ? slippi.characterColor1
        : slippi.characterColor2;

    state.player2.character = slippi.player1IsPort1
        ? slippi.character2
        : slippi.character1;
    state.player2.characterColor = slippi.player1IsPort1
        ? slippi.characterColor2
        : slippi.characterColor1;
}
Port assignment must be set correctly before starting a set. If ports are swapped, character icons and scores will be attributed to the wrong players.

Character Icon Output

Detected characters are exported as PNG icons for use in OBS:
function charpng(player: number, character?: Character, characterColor?: CharacterColor) {
    const color = characterColor == CharacterColor.DEFAULT
        ? 0
        : CHARACTER_COLORS[character].indexOf(characterColor) + 1;

    const colorNumber = color < 10 ? "0" + color : "" + color;
    
    const assetPath = `./assets/characters/chara_2_${Character[character].toLowerCase()}_${colorNumber}.png`;
    fs.copyFileSync(assetPath, `out/p${player}/char.png`);
}

Output Files

  • out/p1/char.png - Player 1’s current character icon
  • out/p2/char.png - Player 2’s current character icon
  • out/program_state.json - Includes character data in structured format
Character icons update in real-time, so Sheik/Zelda transforms will immediately reflect in your stream overlay.

User Workflow

  1. Connect to Slippi: Start your Slippi connection
  2. Game Begins: Characters are auto-detected from game data
  3. Assign Ports: Specify which player is which port (one-time setup per set)
  4. Characters Display: Icons appear automatically on stream overlay
  5. Transforms Update: If Sheik/Zelda transform, icons update live
Character detection works with all 26 Melee characters and all costume colors. No manual configuration needed.

Build docs developers (and LLMs) love