Hudini Stack Component

Row or Column layout with optional background, padding and border radius — the equivalent of a Tailwind flex div in canvas.

Stack Component

Layout primitive that arranges children in a 'row' or 'column'. When backgroundColor, padding or borderRadius is set, Stack also renders a Card behind the children — matching the Tailwind pattern <div class="flex flex-row bg-slate-800 p-4 rounded-lg">...</div>.

Features

  • đŸŽ¯ Direction: 'row' or 'column' — one component, two behaviors
  • 🎨 Optional background: pass backgroundColor to render a Card behind the children
  • 📏 Padding: inner spacing between children and the background's edge
  • 🔲 Border radius: rounded corners on the background
  • 🧩 Composes: measure via .width / .height so a parent Row/Column/Stack lays it out correctly

Props

  • direction - 'row' (default) or 'column'
  • gap - Space between children in pixels (default: 8)
  • align - Cross-axis alignment ('top'|'center'|'bottom' for row, 'left'|'center'|'right' for column)
  • children - GameObjects to stack
  • padding - Inner padding (SpacingKey or px). Only visible with a background
  • backgroundColor - Optional fill color (ColorKey or CSS)
  • borderRadius - Border radius on the background (RadiusKey or px)

Live Example

Loading game...

Usage Example

import Phaser from 'phaser';
import {
    createTheme,
    HUDINI_KEY,
    HudiniPlugin,
    withHudini,
    Stack,
    TextButton,
    Badge,
} from 'hudini';

const theme = createTheme({});
type Theme = typeof theme;

class StackDemoScene extends Phaser.Scene {
    create(): void {
        const hudini = withHudini<Theme>(this);
        const { pw } = hudini;
        this.cameras.main.setBackgroundColor(pw.color.slate(300));

        // 1. Pure layout — no background
        const row = new Stack({
            scene: this,
            x: 400,
            y: 100,
            direction: 'row',
            gap: 12,
            children: [
                new TextButton({ scene: this, x: 0, y: 0, text: 'A', color: 'blue-500' }),
                new TextButton({ scene: this, x: 0, y: 0, text: 'B', color: 'green-500' }),
                new TextButton({ scene: this, x: 0, y: 0, text: 'C', color: 'red-500' }),
            ],
        });
        this.add.existing(row);

        // 2. Layout + background (like <div class="flex bg-slate-800 p-4 rounded-lg">)
        const paddedRow = new Stack({
            scene: this,
            x: 400,
            y: 250,
            direction: 'row',
            gap: 12,
            padding: '4',
            backgroundColor: 'slate-800',
            borderRadius: 'lg',
            children: [
                new Badge({ scene: this, x: 0, y: 0, text: 'PRO', color: 'purple-600' }),
                new Badge({ scene: this, x: 0, y: 0, text: 'NEW', color: 'green-600' }),
                new Badge({ scene: this, x: 0, y: 0, text: 'HOT', color: 'red-600' }),
            ],
        });
        this.add.existing(paddedRow);

        // 3. Column direction
        const column = new Stack({
            scene: this,
            x: 400,
            y: 450,
            direction: 'column',
            gap: 8,
            padding: '4',
            backgroundColor: 'slate-700',
            borderRadius: 'md',
            children: [
                new TextButton({ scene: this, x: 0, y: 0, text: 'Save' }),
                new TextButton({ scene: this, x: 0, y: 0, text: 'Cancel', color: 'gray-500' }),
            ],
        });
        this.add.existing(column);
    }
}