assetyardby Binary Helix

PLAYABLE · PHASER 3 · 33 GENERATED ASSETS

It all has to
work together.

A gallery shows one asset at a time. A game shows whether they fit. Here is a turn-based crawler built from the free pack, running in Phaser, with nothing drawn, recorded or licensed from anywhere else.

Click the merchant, the barrel, then the gate. Pick a difficulty on the title screen. In a fight, press 1 to 4 or click an action. Press Space or click as the needle crosses the gold to strike, and while the rune ring is inside the glowing band to parry. Sound is part of the point, so turn it up. Speech is captioned.

What is running

In the gameAssetsThe command that made them
Town, rooms, figures, props, and the meter and rings of the timed prompts19assetyard generate image
Score, with crossfades3assetyard generate music
Effects6assetyard generate sfx
Spoken lines5assetyard generate tts

The music crossfades when the warden wakes, the effects fire on the same clicks that drive the state machine, and each voice line carries its own caption. None of that needed a second vendor, a second subscription, or a licence check.

One voice, two performances

The calm narration on floor one and the warden's battle cry are the same catalog voice. The only difference is one number.

assetyard generate tts --voice VOICE_KEY --expressiveness 0.05 --text "Three floors down, the water stops moving."
assetyard generate tts --voice VOICE_KEY --expressiveness 0.95 --text "You should not have come down here!"

--expressiveness runs from 0.0 to 1.0. 0.0 is flat and even, and 1.0 is a line delivered under real strain. The number is ours, not the speech model's, so a script written today keeps its meaning after we change the model underneath.

Figures arrive on a black field

Asking an image model for a transparent background is unreliable. Asking for a figure on a plain black field is not. The game floods the black out from the border in a few milliseconds, which keeps dark armour inside the figure intact. That cutout pass is about forty lines of the demo source. The warden's field is pure black and his armour has near-black gaps, so his entry sets a lower key threshold.

Still pictures, moving fights

Every figure in the pack is one still image. The game gives it motion in code: it breathes, leans back before a blow, lunges when the blow lands, recoils when struck, and breaks into pieces or thins to mist when it dies. The painted torches, the light shaft and the fire pit flicker where the images put them. The player's shield is a generated painted face, cut to a heater outline.

The fight is data as well. Each enemy lists its moves in the block below: a damage number, a wind-up time, and a kind such as a guard, a fade or a charged cleave. The game shows the next move before you choose, so every turn is a decision.

Use it as a template

The game names no asset of its own. Everything it knows arrives in one block the page writes, so a different set of names is a different game: a dinosaur one, a space one, whatever you generated this week. Nothing in crawler.js changes.

curl -O https://assetyard.dev/demo/crawler.js

This is the block driving the game above. Edit the file names, the lines, and the floors; keep the keys.

window.HOLLOWREACH_2D = {
  "title": "HOLLOWREACH",
  "subtitle": "THREE FLOORS DOWN",
  "scenery": {
    "keyart": "hollowreach-key-art.png",
    "town": "town-square.png",
    "corridor": "room-corridor.png",
    "chamber": "room-chamber.png",
    "vault": "room-vault.png",
    "shield": "shield-face.png",
    "meter": "ui-meter-frame.png",
    "rune": "ui-rune-ring.png",
    "ward": "ui-ward-ring.png"
  },
  "ui": {
    "meterSlot": [
      0.14,
      0.441,
      0.86,
      0.553
    ],
    "runeRadius": 0.368,
    "wardRadius": 0.343
  },
  "figures": {
    "merchant": "npc-merchant.png",
    "barrel": "prop-barrel.png",
    "gate": "prop-gate.png",
    "sentry": "enemy-bone-sentry.png",
    "wraith": "enemy-marsh-wraith.png",
    "warden": "enemy-hollow-warden.png"
  },
  "audio": {
    "music_theme": "hollowreach-theme.mp3",
    "music_explore": "marshlight.mp3",
    "music_fight": "warden-wakes.mp3",
    "sfx_ui": "ui-confirm.wav",
    "sfx_sword": "sword-impact.wav",
    "sfx_roar": "warden-roar.wav",
    "sfx_potion": "potion-drink.wav",
    "sfx_chest": "chest-open.wav",
    "sfx_gate": "gate-rise.wav",
    "vo_open": "opening-narration.flac",
    "vo_merchant": "gate-merchant.flac",
    "vo_calm": "narration-level.flac",
    "vo_cry": "warden-battle-cry.flac"
  },
  "lines": {
    "vo_open": "The reach swallowed the old road, and everyone who walked it. You are going anyway.",
    "vo_merchant": "Rope, oil, and a dry blanket. Everything else out there is already spoken for.",
    "vo_calm": "Three floors down, the water stops moving. That is how you know you are close.",
    "vo_cry": "You should not have come down here. Put it down and run!"
  },
  "performance": {
    "vo_calm": 0.05,
    "vo_cry": 0.95
  },
  "hero": {
    "hp": 30,
    "strike": 4,
    "potion": 12,
    "counter": 2,
    "focus": 1,
    "focusMax": 3,
    "bashCost": 2,
    "bashDamage": 3,
    "sweep": 0.9
  },
  "difficulties": [
    {
      "id": "squire",
      "label": "Squire",
      "blurb": "Wide timing windows. Blows land softer.",
      "crit": 0.07,
      "hit": 0.3,
      "parry": 0.13,
      "lateGrace": 0.05,
      "damage": 0.75
    },
    {
      "id": "knight",
      "label": "Knight",
      "blurb": "The fight as it was meant to be played.",
      "crit": 0.05,
      "hit": 0.23,
      "parry": 0.09,
      "lateGrace": 0.04,
      "damage": 1
    },
    {
      "id": "champion",
      "label": "Champion",
      "blurb": "Tight windows. Blows land harder.",
      "crit": 0.03,
      "hit": 0.15,
      "parry": 0.05,
      "lateGrace": 0.03,
      "damage": 1.5
    }
  ],
  "defaultDifficulty": "knight",
  "townLights": [
    {
      "x": 0.084,
      "y": 0.29,
      "radius": 90,
      "color": "#ffb35c",
      "alpha": 0.55,
      "kind": "torch"
    },
    {
      "x": 0.941,
      "y": 0.458,
      "radius": 80,
      "color": "#ffb35c",
      "alpha": 0.5,
      "kind": "torch"
    }
  ],
  "floors": [
    {
      "room": "corridor",
      "enemy": "sentry",
      "name": "Bone Sentry",
      "title": "FLOOR ONE · THE LONG CORRIDOR",
      "hp": 22,
      "height": 400,
      "ground": 532,
      "death": "shatter",
      "spark": "#f0e2c0",
      "barrel": false,
      "lights": [
        {
          "x": 0.24,
          "y": 0.31,
          "radius": 170,
          "color": "#ffa04a",
          "alpha": 0.75,
          "kind": "torch"
        },
        {
          "x": 0.754,
          "y": 0.31,
          "radius": 170,
          "color": "#ffa04a",
          "alpha": 0.75,
          "kind": "torch"
        },
        {
          "x": 0.418,
          "y": 0.43,
          "radius": 55,
          "color": "#ffa04a",
          "alpha": 0.4,
          "kind": "torch"
        },
        {
          "x": 0.578,
          "y": 0.43,
          "radius": 55,
          "color": "#ffa04a",
          "alpha": 0.4,
          "kind": "torch"
        }
      ],
      "moves": [
        {
          "id": "cut",
          "label": "Rusted cut",
          "kind": "attack",
          "damage": 4,
          "windup": 0.8,
          "weight": 3
        },
        {
          "id": "double",
          "label": "Two quick cuts",
          "kind": "attack",
          "damage": 2,
          "hits": 2,
          "windup": 0.6,
          "weight": 2
        },
        {
          "id": "brace",
          "label": "Shield up",
          "kind": "brace",
          "weight": 2
        }
      ]
    },
    {
      "room": "chamber",
      "enemy": "wraith",
      "name": "Marsh Wraith",
      "title": "FLOOR TWO · THE FLOODED CHAMBER",
      "hp": 28,
      "height": 400,
      "ground": 505,
      "float": true,
      "death": "dissolve",
      "spark": "#7dffb0",
      "barrel": true,
      "lights": [
        {
          "x": 0.5,
          "y": 0.11,
          "radius": 240,
          "color": "#bfe6ff",
          "alpha": 0.4,
          "kind": "shaft"
        }
      ],
      "moves": [
        {
          "id": "claw",
          "label": "Grave claw",
          "kind": "attack",
          "damage": 5,
          "windup": 0.62,
          "weight": 3
        },
        {
          "id": "drain",
          "label": "Drain",
          "kind": "attack",
          "damage": 4,
          "heal": true,
          "windup": 0.75,
          "weight": 2
        },
        {
          "id": "fade",
          "label": "Fade",
          "kind": "fade",
          "weight": 2
        }
      ]
    },
    {
      "room": "vault",
      "enemy": "warden",
      "name": "The Hollow Warden",
      "title": "FLOOR THREE · THE WARDEN’S VAULT",
      "hp": 56,
      "height": 520,
      "frame": "bust",
      "boss": true,
      "death": "shatter",
      "spark": "#ffb070",
      "barrel": false,
      "cut": 8,
      "lights": [
        {
          "x": 0.5,
          "y": 0.62,
          "radius": 230,
          "color": "#ff8a3a",
          "alpha": 0.6,
          "kind": "fire"
        },
        {
          "x": 0.83,
          "y": 0.44,
          "radius": 70,
          "color": "#ffa04a",
          "alpha": 0.45,
          "kind": "torch"
        }
      ],
      "enrage": {
        "at": 0.5,
        "damage": 1,
        "pace": 0.8
      },
      "moves": [
        {
          "id": "blow",
          "label": "Iron blow",
          "kind": "attack",
          "damage": 7,
          "windup": 0.85,
          "weight": 3
        },
        {
          "id": "flurry",
          "label": "Flurry",
          "kind": "attack",
          "damage": 3,
          "hits": 3,
          "windup": 0.5,
          "weight": 2
        },
        {
          "id": "lift",
          "label": "Lifts the greatsword",
          "kind": "charge",
          "then": "cleave",
          "weight": 2
        },
        {
          "id": "cleave",
          "label": "Cleave",
          "kind": "attack",
          "damage": 12,
          "windup": 1,
          "feint": true,
          "followUp": true
        },
        {
          "id": "guard",
          "label": "Iron guard",
          "kind": "brace",
          "weight": 1
        }
      ]
    }
  ]
}

The assets it loads are the same files on the showcase, served from /pack/files/. Download the pack and the game runs against your local copy unchanged.

The other half

Phaser is a 2D engine, so this build uses the flat assets. The rigged characters in the pack are glTF and belong in a 3D engine. The real-time build loads them in Three.js, skeletons and clips intact.