Skip to main content

Getting Started

Alpha Version: This is the v2 engine documentation. Features and APIs may change.

Most of the functions in Floaty closely resemble functions in Pico-8. The main difference is that instead of global functions, Floaty uses a scope() method that provides all engine functions. This works better in a web context where multiple things can exist on the same page.

The quickest way to get started is to use the following snippet as a starting point:

import Engine from 'https://floaty.dev/engine-v2.js';

const engine = new Engine();

engine.scope(({ start, cls, spr }) => {
    const sprites = {
        player: [
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 7, 7, 7, 7, 0, 0,
            0, 7, 7, 7, 7, 7, 7, 0,
            7, 7, 0, 7, 7, 0, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7,
            0, 7, 7, 7, 7, 7, 7, 0,
            0, 0, 7, 7, 7, 7, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
        ],
    };

    const sounds = {};

    function draw() {
        cls(1);
        spr('player', 60, 60);
    }

    start({
        target: document.querySelector('.game'),
        sprites,
        sounds,
        draw,
    });
});

The scope() Method

In Pico-8, functions like cls(), spr(), and btn() are always available. In Floaty, you access these same functions through the scope() method:

engine.scope(({ start, cls, spr, btn, text }) => {
    // All engine functions are available in this closure
    // No global pollution, no this.engine references needed

    start({
        target: document.querySelector('.game'),
        draw() {
            cls();
            text('hello world', 40, 60, 7);
        }
    });
});

You list the functions you want to use in the parentheses, and they become available inside your code. This approach works well for JavaScript running in a web browser where many different scripts might be running on the same page.

Multiple Games

Unlike Pico-8 where you run one game at a time, you can run multiple Floaty games on the same web page simultaneously:

// First game
const engine1 = new Engine();
engine1.scope(({ start, cls }) => {
    start({
        target: document.querySelector('.game1'),
        draw() { cls(8); }
    });
});

// Second game - no conflicts!
const engine2 = new Engine();
engine2.scope(({ start, cls }) => {
    start({
        target: document.querySelector('.game2'),
        draw() { cls(12); }
    });
});

Audio System

Like Pico-8, you can create sounds using arrays of frequencies. Unlike Pico-8, you can also load audio files directly (wav/ogg/mp3). The sfx() function supports three formats:

engine.scope(({ sfx }) => {
    // Synthesized sound (array format)
    const sounds = {
        jump: [523, 587, 659],
    };

    // Audio file (wav/ogg/mp3)
    sfx('/sounds/explosion.wav');

    // Data URI
    sfx('data:audio/wav;base64,UklGRiQAAABXQVZFZm10...');
});

You can play background music with the music() function:

engine.scope(({ music }) => {
    // Play background music at 50% volume
    music('/music/theme.mp3', { volume: 0.5 });

    // Stop the music
    music(false);
});

Loading Remote Assets

Use queue() to mark sprites or sounds for deferred loading, then call await load() inside an async init() to fetch them all before gameplay starts:

engine.scope(({ start, queue, load, cls, text }) => {
    const sprites = {
        player: queue('https://example.com/player-sprite.json'),
    };

    const sounds = {
        jump: queue('https://example.com/jump-sound.json'),
    };

    start({
        target: document.querySelector('.game'),
        sprites,
        sounds,
        async init() {
            await load();
        },
        draw() { /* ... */ },
    });
});

Defaults

Like Pico-8, Floaty has some sensible defaults to get you started quickly:

Screen size

The screen is 128 pixels wide and 128 pixels high. If the container is larger, the canvas will scale to fit while maintaining a square aspect ratio. Your game will always look pixelated, even if each pixel is actually a square block of pixels.

The rest of the screen around the game canvas will be the same as color 0. If you want to override this, you can provide a different background color to the start() function:

engine.scope(({ start }) => {
    start({
        target: document.querySelector('.game'),
        background: '#FF77A8', // any CSS color
        draw() { /* ... */ }
    });
});

It can be tricky to get the container to stretch, especially if you're not overly familiar with CSS or HTML. Try something like this:

<div style="width: 100vw; height: 100vh">
    <div class="game" style="width: 100%; height: 100%"></div>
</div>

Sprites

Sprites are 8x8 pixels or a multiple thereof. Larger sprites are drawn using optional parameters on the spr function. Use this pattern to define sprites:

const sprites = {
    player: [
        0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 7, 7, 7, 7, 0, 0,
        0, 7, 7, 7, 7, 7, 7, 0,
        7, 7, 0, 7, 7, 0, 7, 7,
        7, 7, 7, 7, 7, 7, 7, 7,
        0, 7, 7, 7, 7, 7, 7, 0,
        0, 0, 7, 7, 7, 7, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
    ],
};

In sprite arrays, -1 means no color is drawn on that pixel (transparent). All other numbers (0-15) correspond to palette colors.

Colors

Like Pico-8, Floaty uses a 16-color palette:

Click a color to copy its hex code.

Copied!