game-world
Coordinates an HTML/CSS perspective world. Pattern banks supply tilemaps and sprites. The screen contains ordered stages, layer tilemaps and the player sprite. CSS owns 3D projection, palette changes, scrolling, transitions and sprite animation. Native inputs support course motion, steering, targeting and sector choice without JavaScript. Upgrade adds fixed-step movement, aimed projectiles, collisions and controller input. The simulation pauses on blur or hidden tabs.
Examples
Fly the training course
Launch, steer, and fire. With scripting disabled, use Run course, the native direction controls, and the target checkbox. The training sector uses the same projection and collision rules as Aether Wing. Pause and resume to inspect the scene, or restart to reset score and health.
<game-world aria-label="Flight demonstration">
<game-tileset id="training-pilot" tile-width="32" tile-height="32"><img src="/games/aether-wing/pilot.png" alt=""></game-tileset>
<game-tileset id="training-moth" tile-width="32" tile-height="32"><img src="/games/aether-wing/moth.png" alt=""></game-tileset>
<game-tileset id="training-pine" tile-width="32" tile-height="48"><img src="/games/aether-wing/pine.png" alt=""></game-tileset>
<game-tileset id="training-ground" tile-width="8" tile-height="8">
<game-tile index="0">3 3 3 3 3 3 3 3
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0</game-tile>
<game-tile index="1">3 3 3 3 3 3 3 3
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1</game-tile>
</game-tileset>
<game-input deadzone="0.18" fire-button="0">
<form>
<fieldset data-native-controls><legend>Course controls</legend>
<label><input type="checkbox" data-native-run>Run course</label>
<label><input type="checkbox" data-native-pause>Pause motion</label>
</fieldset>
<fieldset data-native-controls><legend>Move horizontally</legend>
<label><input type="radio" name="training-x" data-axis="x" value="-1">Left</label>
<label><input type="radio" name="training-x" data-axis="x" value="0" checked>Center</label>
<label><input type="radio" name="training-x" data-axis="x" value="1">Right</label>
</fieldset>
<fieldset data-native-controls><legend>Move vertically</legend>
<label><input type="radio" name="training-y" data-axis="y" value="1">Up</label>
<label><input type="radio" name="training-y" data-axis="y" value="0" checked>Middle</label>
<label><input type="radio" name="training-y" data-axis="y" value="-1">Down</label>
</fieldset>
<fieldset data-native-controls><legend>Sector</legend>
<label><input type="radio" name="training-stage" data-stage-choice="0" checked>Training range</label>
</fieldset>
<game-screen data-world-viewport width="320" height="200" tabindex="0" role="group" aria-label="Training world viewport">
<game-stage id="training-sector" data-stage-index="0" name="Training range" length="120" speed="12" sky="#213959" haze="#b0d5ce">
<game-tileset id="training-reach-mountains" tile-width="16" tile-height="16"><img src="/games/aether-wing/reach-mountains-tiles.png" alt=""></game-tileset>
<game-layer factor="0.18" drift="0.04">
<game-tilemap tileset="training-reach-mountains" columns="12" rows="5" style="--sheet-columns:16;--sheet-rows:3">
<game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="6" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="7" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="8" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="10" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="11" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="12" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile>
<game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="0" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="6" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="14" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="15" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="16" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="17" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile>
<game-tile index="25" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="26" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="27" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="28" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="29" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="30" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile>
<game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="36" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="37" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="38" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile>
<game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile><game-tile index="9" style="background-image:url('/games/aether-wing/reach-mountains-tiles.png')"></game-tile>
</game-tilemap>
</game-layer>
<game-palette id="training-palette-1" colors="#296b72 #48a99a #81cfb3 #b8e8c5" cycle-start="2" cycle-rate="5"></game-palette>
<game-layer mode="perspective" cell-size="4" style="--palette-0:#296b72;--palette-1:#48a99a;--palette-2:#81cfb3;--palette-3:#b8e8c5;--cycle-rate:5">
<game-tilemap palette="training-palette-1" tileset="training-ground" columns="2" rows="2">
<game-tile index="0"></game-tile><game-tile index="1"></game-tile><game-tile index="1"></game-tile><game-tile index="0"></game-tile>
</game-tilemap>
</game-layer>
<game-sprite actor="scenery" aspect="0.666667" tileset="training-pine" x="-4" size="4" spacing="16"><img src="/games/aether-wing/pine.png" alt=""></game-sprite>
<game-sprite actor="scenery" aspect="0.666667" tileset="training-pine" x="4" size="4" spacing="16" offset="8"><img src="/games/aether-wing/pine.png" alt=""></game-sprite>
<game-sprite actor="enemy" frames="8" fps="10" tileset="training-moth" at="8" interval="30" count="4" x="0" y="1.1" z="32" behavior="straight"
health="1" score="100" fire-rate="1.1" fire-delay="0.2" shot-speed="24"><label data-native-target><input type="checkbox" aria-label="Shoot moth"><span><img src="/games/aether-wing/moth.png" alt=""></span></label></game-sprite>
<div data-native-cleared>Sector cleared. Choose the next sector.</div></game-stage>
<game-sprite actor="player" tileset="training-pilot" frames="5" fps="0" max-health="3" speed="3.2" radius="0.18"
size="0.8" fire-rate="0.14" shot-speed="75" recovery="1.2" start-x="0" start-y="1.1"><img src="/games/aether-wing/pilot.png" alt=""></game-sprite>
</game-screen>
<p data-native-controls>Run the course, steer with the radio controls, and select an approaching enemy to shoot. Clear the targets in each sector.</p>
<button type="reset" data-native-controls>Reset course</button>
<p data-native-victory role="status">All sectors cleared.</p>
<div data-world-hud aria-label="Flight instruments">
<label>Shield <output data-world-shield aria-label="Shield" aria-live="off">3</output></label>
<label>Score <output data-world-score aria-label="Score" aria-live="off">000000</output></label>
<label>Sector <output data-world-sector aria-label="Sector" aria-live="off">Training range</output></label>
<label>Route <output data-world-progress aria-label="Route progress" aria-live="off">0%</output></label>
</div>
<p role="status" aria-label="Flight status" data-world-status>Run the course and select an approaching target to shoot.</p>
<div data-world-controls role="group" aria-label="Game controls">
<button type="button" data-action="start" disabled>Launch</button>
<button type="button" data-action="pause" disabled>Pause</button>
<button type="button" data-action="restart" disabled>Restart flight</button>
</div>
<div data-world-controls role="group" aria-label="Flight controls">
<button type="button" data-action="left" aria-label="Fly left" disabled>←</button>
<button type="button" data-action="up" aria-label="Fly up" disabled>↑</button>
<button type="button" data-action="down" aria-label="Fly down" disabled>↓</button>
<button type="button" data-action="right" aria-label="Fly right" disabled>→</button>
<button type="button" data-action="fire" disabled>Fire</button>
</div>
<p data-world-controller>Keyboard / touch</p>
</form>
</game-input>
</game-world>



API
| Name | Type or default | Behavior |
|---|---|---|
state |
string
|
Reflected runtime state: loading, ready, playing, paused, won, lost, or error. |
score |
number
|
Reflected total score, reset when restarting. |
stage |
string
|
Reflected ID of the current stage. |
| Name | Type or default | Behavior |
|---|---|---|
game-world-change |
CustomEvent<{ state: string, score: number, health: number, stage: string }>
|
Bubbles and is composed. Emitted on state changes. |
game-world-error |
CustomEvent<{ reason: "assets-or-definitions" }>
|
Bubbles and is composed. Reports an incomplete world, failed image, invalid sheet or unknown sprite reference. |
| Name | Type or default | Behavior |
|---|---|---|
game-input |
CustomEvent<{ x: number, y: number, fire: boolean, source: string, command?: string }>
|
Listens to descendant input. Valid finite axes and a boolean fire are required. Controls in nested worlds retain ownership. |
| Name | Type or default | Behavior |
|---|---|---|
--distance-blur |
Default 0px |
Optional sprite blur per depth unit beyond 80, applied by CSS. |
| Name | Type or default | Behavior |
|---|---|---|
data-world-controls |
Wrap launch, pause, and movement buttons in this container. The stylesheet shows it after the world is ready. | |
data-world-status |
Text updated for loading failure, stage changes, pause, victory, and defeat. Use role="status" to announce changes. | |
data-world-hud |
Contains the instrument outputs. The native stylesheet displays only score before upgrade. | |
data-world-shield, data-world-score, data-world-sector, data-world-progress |
Optional output hooks for health, points, stage name, and percent of the current stage completed. | |
data-world-controller |
Optional text hook for the active controller or keyboard/touch. | |
data-world-poster |
Marks an image the world can skip while decoding gameplay artwork. | |
data-native-controls |
Marks the native controls and instructions that remain visible until full controls are ready. | |
data-native-run, data-native-pause |
Mark checkboxes for running the course and pausing its CSS animations. | |
data-axis |
Use x or y on a radio input with value -1, 0, or 1 to move the native player in that direction. | |
data-stage-choice |
On a radio input, selects the stage with the same data-stage-index while native controls are active. | |
data-native-cleared, data-native-victory |
Mark text shown when all targets are cleared in the stage or course, respectively. |