Put ESKEES works on your site
Alpha (September 2026). Details may change without notice.
Works made with ESKEES (.eskx / .emg) can be played outside the showcase, in three ways:
- Embed a showcase work — paste one iframe. Official samples and posted works both work.
- Host your own
.eskx— load ESKEES Player from the CDN and point an<eskees-player>tag at your file. Works you have not posted to the showcase work too. - Export a web page from Studio — one HTML file with the work inside. Upload it and it plays.
All three run on the same engine as the showcase: scripts, UI, masks, stages, physics, sound and camera all work.
Demo
This is “Kasanete 2048” placed on this page with <eskees-player>. Click to start (arrow keys or swipe).
1. Embed a showcase work
Press Embed on a work’s showcase page to get the code. For a work at https://showcase.eskees.com/w/ID:
<iframe src="https://showcase.eskees.com/embed/ID"
style="width: 100%; aspect-ratio: 16 / 9; border: 0"
allow="autoplay; fullscreen; gamepad" loading="lazy"></iframe>
- Nothing is downloaded until the player is clicked.
- Scores can be added to the ranking right there (only when the player presses the button).
- Works that are no longer public show “This work is not available.”
2. Host your own .eskx (ESKEES Player)
Export a .eskx from ESKEES (“Export ▾”), put it on your server, and write:
<script type="module" src="https://showcase.eskees.com/player/1/eskees-player.js"></script>
<eskees-player src="/games/my-game.eskx" style="width: 800px; aspect-ratio: 16 / 9"></eskees-player>
Attributes
src | URL of the work (.eskx / .emg). Required |
|---|---|
autoplay | Start without a click. Sound starts at the first click (browser rule) |
lang | Language of the button text (ja / en). Defaults to the browser language |
saves | Save data: local (default; kept in the visitor’s browser for your site) or memory (cleared on close) |
transparent | Transparent background. The “Click to play” cover isn't shown either, so use it with autoplay (for stream overlays; see OBS) |
fit | How to match when the element and the work have different aspect ratios: contain (default) / cover / stretch |
twitch | A Twitch channel name. Connects to its chat without logging in; chat, Bits, subs and raids trigger the work's reactions and on live (see React to chat) |
relay | URL of the relay (eskees live), e.g. ws://127.0.0.1:7357. Receives YouTube chat and more (see React to YouTube chat) |
fps | Maximum frames drawn per second (e.g. 30). Defaults to the display's refresh rate. Lower it for always-on decorations or inside apps, to save battery |
scale | Rendering resolution (0.25–2, default 1). 0.5 draws at half the pixels and stretches (lighter, but softer) |
virtual-pad | On-screen D-pad and buttons (shown on touch screens). auto (default; touch screens only) / on (always) / off (never). In every mode they appear only when the work uses the pad. Use off when embedding a work without pad controls in an app. In mount, use virtualPad |
Your page decides the size. Without one, it fills the width at 16:9. Match the work’s canvas ratio with aspect-ratio to avoid margins.
Events
eskees-ready | The work opened |
|---|---|
eskees-error | It could not be opened (detail.message) |
eskees-score | The script produced a score (detail is { board, value, lower }). Not sent to the showcase ranking |
eskees-live | A stream event arrived (detail is { kind, source, user, text, amount, … }) |
eskees-live-status | The Twitch connection changed (detail.via is twitch / relay; detail.state is connecting / joined / remote (reported by the relay) / retrying / closed) |
document.querySelector('eskees-player').addEventListener('eskees-score', (e) => {
console.log(e.detail.board, e.detail.value);
});
From JavaScript
<script type="module">
import { mount } from 'https://showcase.eskees.com/player/1/eskees-player.js';
const game = await mount(document.getElementById('game'), '/games/my-game.eskx', { autoplay: true });
// game.restart(), game.togglePause(), game.destroy()
// Connect to Twitch chat with { twitch: 'channel' }; send your own events with game.live({ kind: 'chat', source: 'test', user: 'Taro', text: 'lol', amount: 0 })
</script>
Pass values into the work
Your page or app can pass values it holds (voice level, app state…) into the work. Both the <eskees-player> element and the object returned by mount have these methods.
set(name, value) | Sets a variable in the work. A variable declared as var level = 0 to 1 is converted to a number and clamped; other names become global variables as-is (numbers or strings; true / false become 1 / 0). Only when the value changes, on change name runs on the next frame. Cheap enough to call every frame (sending a voice level 20 times a second is fine). You may call it before the work opens; the last values are applied again after restart() |
|---|---|
get(name) | Reads a variable (a number for var, otherwise a string or number; undefined if missing). A value you set is readable from the next frame |
live(event) | Sends a stream event (runs on live and reactions) |
restart() / togglePause() | Start over / pause |
const orb = await mount(el, '/orb.eskx', { autoplay: true, transparent: true, fps: 30, scale: 0.75 });
orb.set('state', 2); // the work reacts with on change state
orb.set('level', 0.8); // declare var level = 0 to 1 in the script
Bundle the Player with your app or site
For offline use (for example, inside a mobile app), you can host the Player files yourself.
- Files:
eskees-player.jsand thechunks/folder next to it, as-is. The same files are inengine/play/where the ESKEES CLI is installed. Files inchunks/load only for works that use physics (planck.js) or text effects (JIZURA) - Passing the work:
mount(el, ArrayBuffer, …)takes the bytes of the.eskxdirectly (no fetch) - It does not run from
file://(browsers block ES modules andimport()there). Serve it overhttps://or your app's built-in server (such as Capacitor'shttps://localhost) - WebGL2 is required (there is no fallback renderer)
- It only goes online for works that use Google Fonts, for JIZURA fonts, and when
twitch/relayis set. No score submission or analytics - Drawing and scripts stop while the page is hidden.
live()calls made while paused or before the work opens are dropped; when you come back to the foreground, send the state again withset(values passed withsetare never dropped) - The ESKEES Player does not keep resume data.
savesonly decides where the script'ssavedata goes - When you distribute it bundled, include
LICENSE.mdandNOTICE.md(found where the ESKEES CLI is installed)
3. Export a web page from Studio
In ESKEES Studio, Export ▾ → Export as a web page (HTML) produces one HTML file with the work inside.
- Upload that HTML and it plays. No separate
.eskxand no CORS setup. - It runs on ESKEES Player (CDN); visitors’ browsers load the player from
showcase.eskees.com. - The work is embedded, so the file is about 4/3 the size of the work. For large works, method 2 (host the
.eskxand use<eskees-player src>) is lighter.
Where it works
- Works: anywhere you can write your own HTML and JavaScript (your server, shared hosting, GitHub Pages, Netlify, Vercel, Cloudflare Pages…). On self-hosted WordPress, use a Custom HTML block.
- Does not work: services that strip
<script>from posts (most blog and article platforms). If they allow iframes, use embed method 1. - Sites with a Content-Security-Policy need
https://showcase.eskees.cominscript-src.
Notes
- If the
.eskxis on another domain, that server must allow CORS (ESKEES Player fetches it). No setup is needed on the same site. - You can place several players on one page. Only the last one clicked receives key presses.
- Works that use physics also load the physics library (planck.js), only when needed.
- Under
/player/1/, attributes, events andmount()stay the same. Fixes ship without notice; breaking changes get/player/2/. - If you only need the EMG part (images and animation), the public EMG CDN player also works. It does not run
.eskxextensions such as scripts.