RPG
GPT 5.6 terra · typescript

Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 18,182 bytes · SHA-256 42d4aeea006d
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ashenwild: Relicbound</title>
<style>
/* ── css: base ── */
*{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#101b1d;color:#f7e9c9;font-family:Georgia,'Times New Roman',serif}#game-shell{width:100%;height:100%;display:grid;place-items:center;background:radial-gradient(circle at 50% 35%,#294242 0,#132326 50%,#091316 100%)}#game{width:min(100vw,calc(100vh * 1.777));height:min(100vh,calc(100vw / 1.777));image-rendering:auto;box-shadow:0 0 0 1px #42685f,0 25px 80px #000;cursor:crosshair}#hud{position:fixed;inset:0;pointer-events:none;text-shadow:0 2px 3px #000}.brand{position:absolute;top:24px;left:30px;display:flex;align-items:center;gap:10px;color:#fae5a5}.brand-mark{font-size:30px;color:#e8a94d}.brand b{letter-spacing:3px;font-size:15px}.brand small{display:block;font-size:9px;letter-spacing:4px;color:#a4c7b0;margin-top:3px}.brand div{display:block}#hearts{position:absolute;top:28px;left:50%;transform:translateX(-50%);display:flex;gap:7px}.heart{font-size:25px;color:#e85f58;filter:drop-shadow(0 2px 2px #000)}.heart.empty{color:#445b58}#resource{position:absolute;right:32px;top:29px;display:flex;gap:7px;align-items:center;font-family:Arial,sans-serif;font-size:15px}.coin{color:#f6c555}.shard{color:#8be2df;margin-left:13px}#quest{position:absolute;left:30px;bottom:45px;border-left:2px solid #d4a150;padding:5px 0 5px 10px;max-width:280px}#quest span{font:bold 9px Arial,sans-serif;letter-spacing:2px;color:#dfa957;display:block}#quest b{font-size:14px;display:block;margin:3px 0}#quest em{font:11px Arial,sans-serif;color:#a2c7b0;font-style:normal}#controls{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);display:flex;gap:13px;color:#c3d3be;font:10px Arial,sans-serif;letter-spacing:.5px;pointer-events:none}kbd{border:1px solid #78948a;border-bottom-width:2px;border-radius:3px;padding:2px 4px;color:#fff;background:#213536;font:9px Arial}#toast{position:fixed;top:105px;left:50%;transform:translateX(-50%);font:bold 13px Arial,sans-serif;letter-spacing:1px;color:#fff0bd;text-shadow:0 2px 3px #000;transition:.25s;opacity:0;pointer-events:none}.panel{position:fixed;right:30px;top:85px;width:290px;background:linear-gradient(145deg,#1a3030,#102122);border:1px solid #7b9a82;box-shadow:0 12px 35px #000b;padding:17px;z-index:4;color:#e8e3c9}.panel.hidden{display:none}.panel header{display:flex;justify-content:space-between;border-bottom:1px solid #42665f;padding-bottom:10px;letter-spacing:2px;font-size:13px;color:#f4d387}.panel button{border:0;background:transparent;color:#fff;font-size:22px;cursor:pointer}.panel p{font:12px Arial;color:#b8c9bb}.item-row{display:flex;align-items:center;gap:10px;border-bottom:1px solid #38504d;padding:9px 0;font:12px Arial}.item-icon{font-size:22px;width:28px;text-align:center}.item-row b{display:block;color:#f1dfad;font-family:Georgia}.item-row small{color:#98b6a6}.buy{margin-left:auto;border:1px solid #c79348;background:#45361e;color:#ffe9aa;padding:5px 7px;font:bold 10px Arial;cursor:pointer}.buy:disabled{opacity:.35}.start-card{width:420px;text-align:center;padding:34px;background:linear-gradient(145deg,#173032ee,#0c181bfa);border:1px solid #829b82;box-shadow:0 18px 70px #000}.sigil{font-size:55px;color:#e6ac55;text-shadow:0 0 18px #e6ac55}.start-card h1{letter-spacing:7px;font-size:28px;margin:5px 0 0}.start-card h2{letter-spacing:5px;font-size:12px;color:#9bc6ae;margin:7px}.start-card p{font-size:14px;line-height:1.5;color:#ccd6bd;margin:23px}.start-tags{display:flex;justify-content:center;gap:18px;font:10px Arial;letter-spacing:2px;color:#d9a85c}.start-card button{margin:27px 0 12px;padding:12px 24px;background:#bd7840;border:1px solid #ffdb83;color:#21170d;font:bold 12px Arial;letter-spacing:1px;cursor:pointer}.start-card small{display:block;font:10px Arial;color:#8da99b}.hidden{display:none!important}
</style>
</head>
<body>
<div id="game-shell"><canvas id="game" width="960" height="540" aria-label="Ashenwild action adventure"></canvas><div id="hud"><div class="brand"><span class="brand-mark">✦</span><div><b>ASHENWILD</b><small>RELICBOUND</small></div></div><div id="hearts" aria-label="Health"></div><div id="resource"><span class="coin">◈</span><b id="gold">0</b><span class="shard">✧</span><b id="shards">0</b></div><div id="quest"><span>QUEST</span><b id="quest-text">Awaken at the Ember Shrine</b><em id="progress-text">0 / 3 seals</em></div></div><div id="controls"><span><kbd>WASD</kbd> MOVE</span><span><kbd>J</kbd> STRIKE</span><span><kbd>K</kbd> INTERACT</span><span><kbd>I</kbd> PACK</span><span><kbd>SPACE</kbd> ROLL</span></div><div id="toast"></div><section id="inventory" class="panel hidden"><header><span>PACK</span><button id="close-pack">×</button></header><div id="inventory-content"></div></section><section id="shop" class="panel hidden"><header><span>WAYFARER'S CACHE</span><button id="close-shop">×</button></header><p>Spend <span class="coin">◈</span> sigils on field essentials.</p><div id="shop-content"></div></section><div id="start"><div class="start-card"><div class="sigil">✦</div><h1>ASHENWILD</h1><h2>RELICBOUND</h2><p>Explore the fractured wilds. Restore three ember seals, grow from a lost wayfarer into a relicbearer.</p><div class="start-tags"><span>EXPLORE</span><span>FIGHT</span><span>DISCOVER</span></div><button id="begin">BEGIN THE JOURNEY</button><small>WASD / ARROWS · J strike · K interact · I pack</small></div></div></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {};
function __require(id) {
if (__cache[id]) return __cache[id].exports;
var module = __cache[id] = { exports: {} };
var factory = __mods[id];
if (!factory) throw new Error("Module not found: " + id);
factory(module.exports, function (spec) {
var target = (__map[id] && __map[id][spec]) || spec;
return __require(target);
}, module);
return module.exports;
}
// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const canvas = document.querySelector('#game');
const c = canvas.getContext('2d');
const W = 960, H = 540;
const P = { x: 210, y: 310, hp: 6, max: 6, gold: 12, weapon: 0, bow: false, seals: 0, shards: 0, atk: 0, roll: 0, items: ['Traveler Cloak'] };
let room = 0, run = false, t = 0;
let keys = new Set();
let foes = [];
let loot = [];
let bits = [];
const lands = [['Ember Shrine', '#294744', '#d7974d'], ['Mossveil Crossing', '#355044', '#9bc965'], ['Sunken Archive', '#253f52', '#72b9d0'], ['Glasswind Rise', '#51445b', '#dda1d6']];
function sound(f, d = .08) { try {
let a = new AudioContext(), o = a.createOscillator(), g = a.createGain();
o.frequency.value = f;
g.gain.setValueAtTime(.05, a.currentTime);
g.gain.exponentialRampToValueAtTime(.001, a.currentTime + d);
o.connect(g);
g.connect(a.destination);
o.start();
o.stop(a.currentTime + d);
}
catch (e) { } }
function say(s) { let e = document.querySelector('#toast'); e.textContent = s; e.style.opacity = '1'; setTimeout(() => e.style.opacity = '0', 1800); }
function burst(x, y, color, n = 12) { for (let i = 0; i < n; i++) {
let a = Math.random() * 7, v = 1 + Math.random() * 3;
bits.push({ x, y, vx: Math.cos(a) * v, vy: Math.sin(a) * v, life: .7, color });
} }
function populate() { foes = []; loot = []; if (room === 0)
loot = [{ x: 356, y: 245, kind: 'save', label: 'Ember Shrine' }, { x: 595, y: 328, kind: 'gold', label: '8 Sigils', value: 8 }, { x: 660, y: 190, kind: 'item', label: 'Moonleaf Tonic' }]; if (room === 1) {
foes = [{ x: 450, y: 210, hp: 3, max: 3, kind: 'Thornling' }, { x: 650, y: 360, hp: 3, max: 3, kind: 'Thornling' }];
loot = [{ x: 700, y: 170, kind: 'item', label: 'Iron Band' }, { x: 265, y: 415, kind: 'gold', label: '12 Sigils', value: 12 }, { x: 750, y: 400, kind: 'seal', label: 'Moss Seal' }];
} if (room === 2) {
foes = [{ x: 430, y: 190, hp: 5, max: 5, kind: 'Wisp' }, { x: 640, y: 270, hp: 5, max: 5, kind: 'Wisp' }];
loot = [{ x: 445, y: 350, kind: 'bow', label: 'Whisper Bow' }, { x: 730, y: 175, kind: 'item', label: 'Archivist Key' }, { x: 770, y: 390, kind: 'seal', label: 'Archive Seal' }];
} if (room === 3) {
foes = [{ x: 455, y: 220, hp: 8, max: 8, kind: 'Glass Warden' }, { x: 660, y: 330, hp: 7, max: 7, kind: 'Glass Warden' }];
loot = [{ x: 500, y: 400, kind: 'upgrade', label: 'Starforged Edge' }, { x: 760, y: 190, kind: 'seal', label: 'Sky Seal' }];
} }
populate();
function near(a, b, d = 42) { return Math.hypot(a.x - b.x, a.y - b.y) < d; }
function item(x) { if (!P.items.includes(x))
P.items.push(x); say('FOUND · ' + x); sound(700, .12); burst(P.x, P.y, '#f8d36b', 18); panel(); }
function hud() { document.querySelector('#gold').textContent = '' + P.gold; document.querySelector('#shards').textContent = '' + P.shards; document.querySelector('#hearts').innerHTML = Array.from({ length: 5 }, (_, i) => `<span class="heart ${i * 2 >= P.hp ? 'empty' : ''}">♥</span>`).join(''); let q = P.seals < 1 ? 'Restore the Moss Seal' : P.seals < 2 ? 'Seek the sunken Archive' : P.seals < 3 ? 'Climb to Glasswind Rise' : 'The wilds remember your name'; document.querySelector('#quest-text').textContent = q; document.querySelector('#progress-text').textContent = P.seals + ' / 3 seals'; }
function panel() { let inv = document.querySelector('#inventory-content'); let wn = ['Worn Blade', 'Embersteel Blade', 'Starforged Edge'][P.weapon]; inv.innerHTML = `<div class="item-row"><span class="item-icon">⚔</span><div><b>${wn}</b><small>Main weapon · tier ${P.weapon + 1}/3</small></div></div>` + P.items.map((x, i) => `<div class="item-row"><span class="item-icon">${['◈', '✦', '☘', '⌁', '⚿', '➹'][i % 6]}</span><div><b>${x}</b><small>Field discovery</small></div></div>`).join(''); let sh = document.querySelector('#shop-content'); let rows = [['Embersteel Edge', 25, 'Upgrade I · faster and stronger'], ['Heart Vessel', 35, '+1 heart container'], ['Lantern Charm', 15, 'Reveals secret paths']]; sh.innerHTML = rows.map((a, i) => `<div class="item-row"><span class="item-icon">${i === 0 ? '⚔' : i === 1 ? '♥' : '✧'}</span><div><b>${a[0]}</b><small>${a[2]}</small></div><button class="buy" data-n="${i}" ${P.gold < Number(a[1]) ? 'disabled' : ''}>${a[1]} ◈</button></div>`).join(''); sh.querySelectorAll('button').forEach(b => b.addEventListener('click', () => buy(Number(b.dataset.n)))); }
function buy(n) { let cost = [25, 35, 15][n], name = ['Embersteel Edge', 'Heart Vessel', 'Lantern Charm'][n]; if (P.gold < cost)
return; P.gold -= cost; if (n === 0)
P.weapon = Math.max(1, P.weapon); if (n === 1 && P.max < 10) {
P.max += 2;
P.hp = P.max;
} item(name); sound(780, .15); hud(); panel(); }
function interact() { let q = loot.find(z => !z.got && near(P, z)); if (!q)
return; q.got = true; if (q.kind === 'gold') {
P.gold += q.value || 0;
say('+' + q.value + ' SIGILS');
sound(820);
}
else if (q.kind === 'save') {
say('CHECKPOINT MARKED');
sound(440, .2);
}
else if (q.kind === 'item')
item(q.label);
else if (q.kind === 'bow') {
P.bow = true;
item('Whisper Bow');
say('MIDWAY DISCOVERY · PRESS L TO FIRE');
}
else if (q.kind === 'seal') {
P.seals++;
P.shards++;
say('EMBER SEAL RESTORED');
sound(520, .25);
}
else if (q.kind === 'upgrade') {
P.weapon = 2;
item('Starforged Edge');
say('FINAL UPGRADE · STARFORGED EDGE');
} hud(); }
function attack(range = 0) { if (P.atk > 0)
return; P.atk = .24; sound(range ? 650 : 240); let d = range ? 3 : P.weapon + 2, dist = range ? 230 : 48 + P.weapon * 20; foes.forEach(e => { if (!e.dead && near(P, e, dist)) {
e.hp -= d;
burst(e.x, e.y, range ? '#9de5e2' : '#f4a65b');
if (e.hp <= 0) {
e.dead = true;
P.gold += 5;
say('FOE VANQUISHED · +5 SIGILS');
burst(e.x, e.y, '#f5ce69', 20);
}
} }); }
function draw() {
let l = lands[room];
c.fillStyle = l[1];
c.fillRect(0, 0, W, H);
c.globalAlpha = .18;
c.strokeStyle = '#b8d0a6';
for (let x = 0; x < W; x += 48) {
c.beginPath();
c.moveTo(x, 0);
c.lineTo(x + 90, H);
c.stroke();
}
c.globalAlpha = 1;
for (let i = 0; i < 55; i++) {
let x = (i * 137 + room * 41) % W, y = (i * 83) % H;
c.fillStyle = i % 3 ? '#244039' : '#547052';
c.beginPath();
c.arc(x, y, 8 + i % 4 * 4, 0, 7);
c.fill();
}
c.fillStyle = '#7e744e66';
c.fillRect(0, 265, W, 70);
c.fillStyle = '#e8d290';
c.textAlign = 'center';
c.font = 'bold 17px Georgia';
c.fillText(l[0], W / 2, 45);
c.fillStyle = '#bad0ba';
c.font = '12px Georgia';
c.fillText('A fragment of the old wilds', W / 2, 64);
c.fillStyle = '#e4bd6b';
c.font = '11px Arial';
c.fillText('EAST', 940, 355);
loot.forEach(o => { if (o.got)
return; let col = o.kind === 'save' ? '#e7a957' : o.kind === 'seal' ? '#9ff0e7' : o.kind === 'gold' ? '#f4c55b' : o.kind === 'bow' ? '#83d3df' : '#e9a8d0'; c.shadowBlur = 16; c.shadowColor = col; c.fillStyle = col; c.beginPath(); c.arc(o.x, o.y, 12 + Math.sin(t * 3) * 2, 0, 7); c.fill(); c.shadowBlur = 0; c.fillStyle = '#fff4c4'; c.font = '10px Arial'; c.fillText(o.kind === 'save' ? 'SAVE' : o.kind === 'seal' ? 'SEAL' : '✦', o.x, o.y + 3); if (near(P, o, 55)) {
c.fillStyle = '#fff';
c.fillText('[K] ' + o.label, o.x, o.y - 22);
} });
foes.forEach(e => { if (e.dead)
return; c.fillStyle = e.kind === 'Wisp' ? '#76c6de' : e.kind === 'Glass Warden' ? '#d399cf' : '#91b95d'; c.beginPath(); c.arc(e.x, e.y, 16, 0, 7); c.fill(); c.fillStyle = '#172323'; c.fillRect(e.x - 17, e.y - 27, 34, 5); c.fillStyle = '#dd6260'; c.fillRect(e.x - 17, e.y - 27, 34 * e.hp / e.max, 5); c.fillStyle = '#fff'; c.font = '9px Arial'; c.fillText(e.kind, e.x, e.y - 35); });
c.fillStyle = '#101b1bbb';
c.beginPath();
c.ellipse(P.x, P.y + 16, 18, 7, 0, 0, 7);
c.fill();
c.fillStyle = P.atk > 0 ? '#fff0b5' : '#e7c08b';
c.beginPath();
c.arc(P.x, P.y - 5, 12, 0, 7);
c.fill();
c.fillStyle = '#375a61';
c.fillRect(P.x - 11, P.y + 4, 22, 18);
c.fillStyle = '#9ac9c1';
c.fillRect(P.x - 8, P.y + 9, 16, 14);
c.strokeStyle = P.weapon === 2 ? '#e7dcff' : P.weapon === 1 ? '#ffbd5e' : '#b9d3d0';
c.lineWidth = P.weapon === 2 ? 6 : 4;
c.beginPath();
c.moveTo(P.x + 8, P.y + 5);
c.lineTo(P.x + 27 + P.atk * 55, P.y - 13);
c.stroke();
if (P.atk > 0) {
c.strokeStyle = '#f4db99aa';
c.lineWidth = 3;
c.beginPath();
c.arc(P.x, P.y, 46 + P.weapon * 12, -.8, .7);
c.stroke();
}
bits.forEach(b => { c.globalAlpha = b.life; c.fillStyle = b.color; c.fillRect(b.x, b.y, 4, 4); });
c.globalAlpha = 1;
c.fillStyle = '#d8e4c9';
c.font = '11px Arial';
c.textAlign = 'left';
c.fillText('Find the shrine light. The road east opens as seals are restored.', 28, 505);
if (room === 0) {
c.fillStyle = '#d8ab64';
c.fillText('Wayfarer Cache [K]', 110, 155);
c.strokeStyle = '#d8ab64';
c.strokeRect(80, 165, 105, 48);
}
}
function loop() { if (run) {
t += .016;
let dx = (keys.has('d') || keys.has('arrowright') ? 1 : 0) - (keys.has('a') || keys.has('arrowleft') ? 1 : 0), dy = (keys.has('s') || keys.has('arrowdown') ? 1 : 0) - (keys.has('w') || keys.has('arrowup') ? 1 : 0);
if (dx || dy) {
let z = Math.hypot(dx, dy), s = P.roll > 0 ? 4.7 : 2.25;
P.x = Math.max(18, Math.min(942, P.x + dx / z * s));
P.y = Math.max(85, Math.min(510, P.y + dy / z * s));
}
P.roll = Math.max(0, P.roll - .016);
P.atk = Math.max(0, P.atk - .016);
foes.forEach(e => { if (e.dead)
return; let d = Math.hypot(e.x - P.x, e.y - P.y); if (d < 170) {
e.x += (P.x - e.x) / d * .35;
e.y += (P.y - e.y) / d * .35;
} if (d < 27 && Math.random() < .009) {
P.hp = Math.max(0, P.hp - 1);
burst(P.x, P.y, '#e65c57');
sound(100, .15);
hud();
if (P.hp === 0) {
P.hp = P.max;
P.x = 210;
P.y = 310;
room = 0;
populate();
say('THE SHRINE CALLS YOU BACK');
}
} });
bits.forEach(b => { b.x += b.vx; b.y += b.vy; b.life -= .02; });
bits = bits.filter(b => b.life > 0);
if (P.x > 930 && room < 3 && P.seals >= room) {
room++;
P.x = 35;
populate();
say('ENTERED · ' + lands[room][0]);
}
draw();
} requestAnimationFrame(loop); }
hud();
panel();
loop();
document.querySelector('#begin').onclick = () => { run = true; document.querySelector('#start').classList.add('hidden'); say('THE WILDS ARE WAITING'); };
document.addEventListener('keydown', e => { keys.add(e.key.toLowerCase()); let k = e.key.toLowerCase(); if (k === 'j')
attack(); if (k === 'l' && P.bow)
attack(1); if (k === 'k') {
if (room === 0 && near(P, { x: 130, y: 185 }, 70))
document.querySelector('#shop').classList.toggle('hidden');
else
interact();
} if (k === 'i') {
document.querySelector('#inventory').classList.toggle('hidden');
panel();
} if (e.code === 'Space') {
P.roll = .28;
sound(170, .05);
} });
document.addEventListener('keyup', e => keys.delete(e.key.toLowerCase()));
document.querySelector('#close-pack').onclick = () => document.querySelector('#inventory')?.classList.add('hidden');
document.querySelector('#close-shop').onclick = () => document.querySelector('#shop')?.classList.add('hidden');
};
// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"openai/gpt-5.6-terra","provider":"openrouter","persona":"typescript","sessionId":"dc62316a-02ff-4f72-94ae-c1cfd54dcce2","tokensIn":122633,"tokensOut":10109,"tokensTotal":132742,"turns":13,"toolCalls":13,"failedToolCalls":1,"timestamp":"2026-07-31T18:19:04.305Z"} -->