Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/runtime-provider/v1/provider-module-v1.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ export interface RuntimeGamepadCursorV1 {
setEnabled(enabled: boolean): void;
}

/** Optional on-screen controls. The Host owns per-core preference persistence. */
export interface RuntimeTouchGamepadV1 {
getState(): {enabled: boolean};
/** Hiding releases all virtual input and does not change physical controllers. */
setEnabled(enabled: boolean): Promise<void>;
}

/** Optional, local-only input observation. No game input is generated by this API. */
export type RuntimeInputObservationV1 = {
sequence: number;
Expand Down Expand Up @@ -239,6 +246,7 @@ export interface PlayerRuntimeV1 {
getCheckpointAvailability(): RuntimeCheckpointAvailabilityV1;
getCanvas(): HTMLCanvasElement | null;
getGamepadCursor?(): RuntimeGamepadCursorV1 | null;
getTouchGamepad?(): RuntimeTouchGamepadV1 | null;
getFrameCount(): number | null;
/** Optional adapter observation capability; never pauses or resumes the game. */
startInputDiagnostics?(): RuntimeInputDiagnosticsV1;
Expand All @@ -258,6 +266,8 @@ export interface RuntimeHostV1 {
signal: AbortSignal;
/** Device preference for managed content; omitted means ON_DEMAND. */
contentLoading?: "ON_DEMAND" | "PRELOAD";
/** Initial on-screen control preference, applied before the game appears. Defaults to true. */
touchGamepadEnabled?: boolean;
mountFrame(target: HTMLElement, input: { resourceRole: string | null }): Promise<RuntimeFrameV1>;
loadRestore(descriptor: RestoreDescriptorV1 | null): Promise<Uint8Array | null>;
reportDiagnostic(input: { code: string; message: string }): void;
Expand Down
42 changes: 21 additions & 21 deletions data/runtime-inputs.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
{
"schemaVersion": 1,
"repository": "https://github.com/retrom-project/retrom-runtime",
"sourceTreeSha256": "0a49b62525448fce69f7099342f9b45d7099b97ebf314cb1e227967a52459864",
"sourceTreeSha256": "b329f292871f788307c07376fece44a0d7e9c6187441de2e8e315afcd48b9247",
"release": {
"repository": "https://github.com/retrom-project/retrom-runtime",
"tag": "v0.89.0",
"commit": "629c38f7e509d73459411c91ef1fbc78bcfb37af"
"tag": "v0.90.0",
"commit": "3d0f4867dbb1f2d1d5e706a4b00ad72fd1fd0b65"
},
"tool": {
"archive": "retrom-runtime-host-tool-0.89.0.tar.gz",
"sizeBytes": 11558495,
"sha256": "efc110036ece5753ed476d0ad33cd488063fb8b822d76e1932f49da7ce489c90"
"archive": "retrom-runtime-host-tool-0.90.0.tar.gz",
"sizeBytes": 11584396,
"sha256": "deb94eba855cd308a22ea18990fe7015c3a0a00f19dc8026d8f32c997e489f22"
},
"providers": [
{
"bundleSha256": "009a1b44b6930ec389bdafb44af7149fb3d3d5b821558e8d3a7eb45dc6d5cb88",
"bundleSha256": "51d3c8c9759c2d93da02d584f6541c436ed3855fef5d9807b2aeef04895c1a72",
"chunkManifest": {
"asset": "emulatorjs-chunks-0.89.0.json",
"sha256": "9b8230f340a6062fea5e1474ace4c6934342a9f9ff7288a5faddebe8dd08a593",
"asset": "emulatorjs-chunks-0.90.0.json",
"sha256": "f7e3e2ece8da662dbacd64d9cbb400a728919391a3d5df5089f81b744a9cac52",
"sizeBytes": 100793
},
"fileCount": 270,
"manifestSha256": "d59b076e54e558ee17276afa79c848dcd2feb5bf839b72c71d22ea6970fe0ba1",
"moduleSha256": "f606515680b7a7a3a78af9d45b1a80bbe9aaea61c00a156aaf134ba9dd27c1cf",
"manifestSha256": "8c34c06aa98061c12c8f3d4e4dbba29c3e92e96234e128508387857b049099d9",
"moduleSha256": "2fba604351578a1d2d6c2f8022a4c562e1572421a7efd5370ea9120d9e7732c3",
"providerId": "emulatorjs",
"providerVersion": "0.89.0",
"unpackedSizeBytes": 366789695
"providerVersion": "0.90.0",
"unpackedSizeBytes": 366790900
},
{
"bundleSha256": "d55c665912b10ba66f4cab768ae9cddbe469a1e9007f958fc57f524c255cb1e6",
"bundleSha256": "5fc7c7157b13037fa381e51a1cfa4d6fa0abc316988050efada39f0ff9cd43c3",
"chunkManifest": {
"asset": "retrom-runtime-chunks-0.89.0.json",
"sha256": "3a8aa2e15aaad0ccacf8ceef93fd636c6d8f7088745bbe270b459e665842ecbe",
"sizeBytes": 133539
"asset": "retrom-runtime-chunks-0.90.0.json",
"sha256": "94eb0fd7cb96732255bc6457d7e23fa9a043cfd260bcc96c69eeb259ec8446c7",
"sizeBytes": 133541
},
"fileCount": 549,
"manifestSha256": "ba9ec37030d3c611169b83b9829634feb847d6fcf47bb31eceabc62857f759fc",
"moduleSha256": "0d8593f956b4c522bfcdfadaa4cc18f44c7443ff45cc8b0a2e33c2f361da7779",
"manifestSha256": "6a2634ec5d077405fdf6b864c978ecf9726eaa6c85d1e059b13bcf99c77d9394",
"moduleSha256": "36c098be876e8f70b0188599c4c784e916cbf8970bed4bd2096d3c83feebd88d",
"providerId": "retrom-runtime",
"providerVersion": "0.89.0",
"unpackedSizeBytes": 928011427
"providerVersion": "0.90.0",
"unpackedSizeBytes": 928082578
}
]
}
24 changes: 21 additions & 3 deletions docs/design/retrom-ui-review.fragment.html
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@
#retrom-ui-review .rt-player-preview { position: relative; min-height: 580px; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-panel); background: var(--navy-950); }
#retrom-ui-review .rt-player-hud { min-height: 58px; padding: 0 var(--space-4); display: flex; align-items: center; gap: var(--space-3); background: var(--surface); border-bottom: 1px solid var(--line); }
#retrom-ui-review .rt-player-hud > span { margin-left: auto; color: var(--cyan); font-size: var(--text-caption); }
#retrom-ui-review .rt-player-scene { min-height: 470px; display: grid; place-items: center; color: var(--muted); }
#retrom-ui-review .rt-player-scene { position: relative; min-height: 470px; display: grid; place-items: center; color: var(--muted); }
#retrom-ui-review .rt-player-stick { position: absolute; left: 20px; bottom: 20px; width: clamp(100px, 30vmin, 160px); aspect-ratio: 1; display: grid; place-items: center; border-radius: 50%; background: rgb(255 0 0 / 50%); opacity: .5; pointer-events: none; }
#retrom-ui-review .rt-player-stick[hidden] { display: none; }
#retrom-ui-review .rt-player-stick::after { content: ''; width: 50%; height: 50%; border-radius: 50%; background: rgb(255 0 0 / 50%); }
#retrom-ui-review .rt-j2me-layout { display: grid; grid-template-columns: 132px minmax(100px, 1fr) 172px; align-items: center; gap: var(--space-4); padding: var(--space-4); background: var(--navy-950); }
#retrom-ui-review .rt-j2me-stick { position: relative; width: 132px; height: 132px; padding: 0; border-radius: 50%; }
#retrom-ui-review .rt-j2me-stick::after { content: ''; position: absolute; width: 60px; height: 60px; left: 35px; top: 35px; border: 1px solid var(--line); border-radius: 50%; background: var(--surface-raised); }
Expand Down Expand Up @@ -258,14 +261,15 @@
<p class="rt-muted">失败时沿用居中错误面板:先显示可读提示,再逐行显示核心原因与具体缺件;长文件名折行,版权提示与程序栈留在诊断层。工具栏与更多菜单优先显示真实运行状态:失败为“游戏运行失败”,退出中为“正在退出…”,结束为“游戏已结束”;旧存档提示或同步状态不得覆盖这些状态。</p>
<div class="rt-player-preview">
<section class="rt-player-dialog" data-player-state="portrait" hidden aria-label="横屏游玩提示"><p>↻ 横屏游玩</p><h2>请将手机横屏后开始游戏</h2><p>已先尝试自动横屏全屏;浏览器未能完成切换。</p><p>竖屏时游戏暂停并禁用操作。关闭手机的旋转锁定,再将手机横放即可继续。</p><button class="rt-button" data-player-panel="exit">返回并退出游戏</button></section>
<div class="rt-player-hud"><button class="rt-button" aria-label="返回并退出游戏" data-player-panel="exit"><i data-lucide="arrow-left"></i></button><span>可创建存档</span><button class="rt-button" data-player-panel="saved">创建存档</button><button class="rt-button" aria-label="暂停"><i data-lucide="pause"></i></button><button class="rt-button" data-player-panel="menu">更多操作</button><button class="rt-button" data-player-panel="portrait">手机竖屏提示</button></div>
<div class="rt-player-scene" data-player-surface="true"><p>游戏画面</p></div>
<div class="rt-player-hud"><button class="rt-button" aria-label="返回并退出游戏" data-player-panel="exit"><i data-lucide="arrow-left"></i></button><span>可创建存档</span><button class="rt-button" data-player-panel="saved">创建存档</button><button class="rt-button" aria-label="暂停"><i data-lucide="pause"></i></button><button class="rt-button player-control is-toggle" aria-label="隐藏虚拟手柄" aria-pressed="true" data-player-touch-gamepad><i data-lucide="gamepad-2"></i></button><button class="rt-button" data-player-panel="menu">更多操作</button><button class="rt-button" data-player-panel="portrait">手机竖屏提示</button></div>
<div class="rt-player-scene" data-player-surface="true"><p>游戏画面</p><span class="rt-player-stick" data-player-touch-stick aria-hidden="true"></span></div>
<nav class="rt-player-menu" data-player-state="menu" hidden aria-label="更多操作"><button class="rt-button" data-player-panel="editor">游戏修改</button><button class="rt-button" data-player-panel="settings">模拟器设置</button><button class="rt-button">全屏 / 退出全屏</button><button class="rt-button" data-player-panel="exit">退出游戏</button></nav>
<section class="rt-player-dialog rt-player-editor" data-player-state="editor" hidden><header class="rt-editor-head"><div><small class="rt-muted">当前游戏</small><h2>游戏修改</h2></div><button class="rt-button" data-player-panel="none">返回游戏</button></header><nav class="rt-editor-tabs" aria-label="修改类别"><button class="rt-button" aria-pressed="true">金币</button><button class="rt-button">道具</button><button class="rt-button">武器</button><button class="rt-button">护甲</button><button class="rt-button">变量</button><button class="rt-button">开关</button><button class="rt-button">角色</button><button class="rt-button">技能</button><button class="rt-button">状态</button><button class="rt-button">职业</button><button class="rt-button">队伍成员</button><button class="rt-button">事件独立开关</button></nav><div class="rt-editor-content"><p class="rt-muted">修改立即生效。离开前请创建存档,以保留修改后的进度。</p><header class="rt-editor-head"><h2>金币</h2><div class="rt-actions"><button class="rt-button">查找</button><button class="rt-button">刷新</button></div></header><div class="rt-editor-list"><div class="rt-editor-row"><div><strong>金币</strong><p class="rt-muted">当前:120</p></div><div class="rt-actions"><button class="rt-button" aria-label="金币减一">−</button><input aria-label="修改金币" type="number" value="120" min="0"><button class="rt-button" aria-label="金币加一">+</button><button class="rt-button">应用</button></div></div></div></div></section>
<div class="rt-player-settings" data-player-state="settings" hidden><label>画面<select><option>锐利像素</option><option>平滑增强</option></select></label><label>音量<input type="range" min="0" max="100" value="50"></label><button class="rt-button">静音</button><button class="rt-button">控制</button><button class="rt-button">显示</button><button class="rt-button">Core 设置</button><button class="rt-button" data-player-panel="none">收起</button></div>
<section class="rt-player-dialog" data-player-state="exit" hidden><h2>退出游戏?</h2><p>直接退出不会创建存档;如需保留当前位置,请先创建存档。</p><p class="rt-notice">只有点击“创建存档”才会保存当前位置;直接退出只结束本次游戏,未保存的进度不会保留。</p><div class="rt-actions"><button class="rt-button" data-player-panel="saved">创建存档</button><button class="rt-button" data-player-panel="none">取消</button><button class="rt-button rt-button-danger" data-open="detail">退出游戏</button></div></section>
<div class="rt-player-toast" data-player-state="saved" role="status" hidden>存档已同步。<button class="rt-button" data-player-panel="none" aria-label="关闭通知">×</button></div>
</div>
<p class="rt-muted">顶部手柄按钮默认开启,按核心保存显示偏好;隐藏后保留游戏自身触控,可随时重新开启。</p>
<section class="rt-section" aria-label="J2ME 触屏布局"><h2>J2ME 触屏操作</h2><div class="rt-j2me-layout"><button class="rt-button rt-j2me-stick" aria-label="圆形方向摇杆"></button><div class="rt-j2me-screen">J2ME 游戏画面</div><div class="rt-j2me-keypad" aria-label="手机键盘"><button class="rt-button">左软键</button><button class="rt-button rt-button-primary">确认</button><button class="rt-button">右软键</button><button class="rt-button">1</button><button class="rt-button">2</button><button class="rt-button">3</button><button class="rt-button">4</button><button class="rt-button">5</button><button class="rt-button">6</button><button class="rt-button">7</button><button class="rt-button">8</button><button class="rt-button">9</button><button class="rt-button">*</button><button class="rt-button">0</button><button class="rt-button">#</button></div></div><p class="rt-muted">摇杆拖动选方向、松手回中;支持斜向、摇杆与确认同时操作。确认和数字5独立,左右软键由游戏决定用途。暂停、存档导出或菜单拦截时释放触点;Retrom 手机仍需横屏游玩。</p></section>
<div class="rt-fields rt-section"><section class="rt-panel"><h2>游戏启动中</h2><p>游戏内容 [▪▪▪▪▪▪▪▪▪▪] ✓</p><p>核心资源 [··········] ◌</p><p class="rt-muted">真实启动任务与字节进度;未知进度使用不定动画。</p></section><section class="rt-panel"><h2>选择启动入口</h2><p class="rt-muted">请选择要启动的入口</p><div class="rt-actions"><button class="rt-button">主程序</button><button class="rt-button">说明</button><button class="rt-button">取消启动</button></div><p class="rt-muted">方向键 / 手柄选择 · Enter / A 确认 · Escape / B 取消。等待选择时保持启动中,长列表独立滚动。</p></section><section class="rt-panel"><p class="rt-muted">游戏已暂停</p><h2>游戏菜单</h2><p>沉浸运行不显示普通工具栏;M 或 Select + Start 双击打开菜单。</p><div class="rt-actions"><button class="rt-button">取消</button><button class="rt-button">创建存档</button><button class="rt-button">退出游戏</button></div><p class="rt-muted">A 确认 · B 取消 · 返回后保留原目录与选中游戏</p></section><section class="rt-panel"><p class="rt-muted">网络中断</p><h2>网络连接中断,正在重新连接…</h2><p>按需加载的游戏内容读取失败时不结束游戏:画面上方显示提示,后台按 1/2/4/8 秒重试,网络恢复后自动从中断处继续。提示不拦截输入,也可随时退出游戏。</p></section></div>
<p class="rt-notice">启动时默认请求全屏;浏览器未允许时可在更多操作菜单中手动切换。PC鼠标移入顶部整条边缘展开菜单,移开收起;悬停不暂停,点击菜单任意位置暂停,点击游戏画面继续。手机保留点击把手与暂停/继续按钮。创建存档用于保存进度;原生存档需在游戏内保存,再同步。失败可重试、导出或保留本地草稿。独立截图下载入口已移除。</p>
Expand Down Expand Up @@ -316,6 +320,20 @@
const tagOption = event.target.closest('.rt-tag-options [role="option"]');
if (tagOption) { const selected = tagOption.getAttribute("aria-selected") !== "true"; tagOption.setAttribute("aria-selected", String(selected)); tagOption.querySelector("span")?.remove(); if (selected) { const mark = document.createElement("span"); mark.setAttribute("aria-hidden", "true"); mark.textContent = "✓"; tagOption.append(mark); } }
if (event.target.closest("[data-player-surface]")) { root.querySelector('[data-player-state="menu"]').hidden = true; }
const touchToggle = event.target.closest("[data-player-touch-gamepad]");
if (touchToggle) {
const enabled = touchToggle.getAttribute("aria-pressed") !== "true";
touchToggle.setAttribute("aria-pressed", String(enabled));
touchToggle.setAttribute("aria-label", enabled ? "隐藏虚拟手柄" : "显示虚拟手柄");
const icon = touchToggle.querySelector("svg");
icon?.querySelector("[data-touch-off]")?.remove();
if (!enabled && icon) {
const slash = document.createElementNS("http://www.w3.org/2000/svg", "path");
slash.setAttribute("d", "M3 3 21 21"); slash.setAttribute("data-touch-off", ""); icon.append(slash);
}
root.querySelector("[data-player-touch-stick]").hidden = !enabled;
return;
}
const playerAction = event.target.closest("[data-player-panel]");
if (playerAction) { root.querySelectorAll("[data-player-state]").forEach(panel => { panel.hidden = panel.dataset.playerState !== playerAction.dataset.playerPanel; }); }
const button = event.target.closest("[data-view], [data-open]");
Expand Down
Loading
Loading