beyond-simulator-web 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/public/app.js +18 -3
- package/dist/public/editor.js +34 -13
- package/dist/public/index.html +1 -1
- package/dist/public/play-renderer.js +108 -107
- package/dist/public/play.js +2 -2
- package/dist/public/styles.css +3 -2
- package/dist/server.js +20 -20
- package/dist/worker.js +12 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
单用户自托管 Web 编辑器和磁盘存档预览,无需 Harness。复用共享 Studio、Lua Runtime、固定步长试玩 Worker、Pixi 渲染器及 `editor-ui` 编辑界面。
|
|
4
4
|
|
|
5
|
-
## 0.5.
|
|
5
|
+
## 0.5.2 更新
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- 支持界面/全屏动效素材搜索、编辑画布预览及 Lua 试玩播放,资源加载失败仅影响对应动效。
|
|
8
|
+
- 支持单个客户端控件和勾选组合的 GIA 导出,导出前可预览并检查依赖。
|
|
9
|
+
- 改进快速点击、拖拽和输入事件顺序;AI 启动试玩默认静音,可手动开启声音。
|
|
10
|
+
|
|
11
|
+
完整公告见 [DSH 2.2.2 / Web 0.5.2 / MCP 0.5.2](../dsh-plugin/CHANGELOG.md#222--2026-10-30)。
|
|
10
12
|
|
|
11
13
|
更新或修改字体后,重启 Web 服务并刷新页面。
|
|
12
14
|
|
|
@@ -78,6 +80,8 @@ Web/MCP 0.3.0、共享宿主所在 DSH 2.0.3:修复空工作区启动后跳过
|
|
|
78
80
|
|
|
79
81
|
Lua `game.PlayAudio2D(id)` 触发白名单 MP3 按需缓存与播放,同源路由为 `/qxqy-audio/`,缓存目录可用 `QXQY_AUDIO_CACHE_DIR` 指定。首次自动播放被浏览器阻止时点击「开启声音」;支持停止、试玩暂停/继续和静音。参见 [音频说明](../studio/docs/audio-assets.md)。
|
|
80
82
|
|
|
83
|
+
界面动效和全屏动效通过 `/qxqy-vfx/ct-v1/` 按需缓存 C/T WebM、图标和声音。`/editor` 支持静音动态预览,两个试玩入口都支持 Lua 驱动的动效播放;`/` 编辑模式仍为静态 PNG。资源失败不停止编辑/试玩。参见 [动效播放、缓存与截图边界](../studio/docs/ui-vfx-playback.md)。
|
|
84
|
+
|
|
81
85
|
## 部署与访问控制
|
|
82
86
|
|
|
83
87
|
绑定非回环地址前,设置 `QXQY_WEB_PASSWORD`,登录用户名固定为 `simulator`。设置口令后,即使回环访问也要求认证。业务静态文件、API、SSE 与截图均受保护;写请求只接受 JSON 并校验浏览器 Origin。路径只能落在配置工作区内。
|
package/dist/public/app.js
CHANGED
|
@@ -33,6 +33,7 @@ const elements = {
|
|
|
33
33
|
stageShell: byId('stage-shell'),
|
|
34
34
|
stageImage: byId('stage-image'),
|
|
35
35
|
stageCanvas: byId('stage-canvas'),
|
|
36
|
+
stagePlay: byId('stage-play'),
|
|
36
37
|
stageEmpty: byId('stage-empty'),
|
|
37
38
|
stageLoading: byId('stage-loading'),
|
|
38
39
|
activePath: byId('active-path'),
|
|
@@ -218,6 +219,8 @@ function renderStage() {
|
|
|
218
219
|
const showPlay = hasArchive && mode === 'play' && Boolean(model?.play?.running)
|
|
219
220
|
elements.stageImage.hidden = !showEditor
|
|
220
221
|
elements.stageCanvas.hidden = !showPlay
|
|
222
|
+
elements.stagePlay.hidden = !showPlay
|
|
223
|
+
resizePlayStage()
|
|
221
224
|
elements.stageEmpty.hidden = showEditor || showPlay
|
|
222
225
|
elements.stageShell.classList.toggle('playing', mode === 'play' && Boolean(model?.play?.running))
|
|
223
226
|
if (!hasArchive) {
|
|
@@ -243,6 +246,17 @@ function renderStage() {
|
|
|
243
246
|
: t('编辑器静态预览 · 磁盘自动刷新')
|
|
244
247
|
}
|
|
245
248
|
|
|
249
|
+
// The video planes and transparent Pixi canvas share this exact viewport, not
|
|
250
|
+
// the padded workspace around it. Keep letterboxing and clipping in one place.
|
|
251
|
+
function resizePlayStage() {
|
|
252
|
+
const width = model?.play?.width || 1600, height = model?.play?.height || 900
|
|
253
|
+
const scale = Math.max(0.01, Math.min((elements.stageShell.clientWidth - 70) / width, (elements.stageShell.clientHeight - 80) / height))
|
|
254
|
+
elements.stagePlay.style.width = `${width * scale}px`
|
|
255
|
+
elements.stagePlay.style.height = `${height * scale}px`
|
|
256
|
+
}
|
|
257
|
+
const stageResize = new ResizeObserver(resizePlayStage)
|
|
258
|
+
stageResize.observe(elements.stageShell)
|
|
259
|
+
|
|
246
260
|
function refreshEditorImage() {
|
|
247
261
|
if (!model?.activePath) return
|
|
248
262
|
if (editorImageRefreshing) {
|
|
@@ -308,6 +322,7 @@ function syncPlayPolling() {
|
|
|
308
322
|
|
|
309
323
|
async function onPlaySnapshot(next) {
|
|
310
324
|
applyPlayStatus(next)
|
|
325
|
+
resizePlayStage()
|
|
311
326
|
updatePlayChrome()
|
|
312
327
|
}
|
|
313
328
|
|
|
@@ -391,8 +406,8 @@ const play = createPlaySession({
|
|
|
391
406
|
onStatus: (next) => { applyPlayStatus(next); updatePlayChrome() },
|
|
392
407
|
onError: (error) => notify(error.message, true),
|
|
393
408
|
onAudioStatus: status => {
|
|
394
|
-
elements.playAudio.textContent =
|
|
395
|
-
elements.playAudio.title = status.error || (
|
|
409
|
+
elements.playAudio.textContent = status.muted ? t('声音已关闭') : !status.unlocked ? t('开启声音') : t('声音已开启')
|
|
410
|
+
elements.playAudio.title = status.error || (status.muted || status.unlocked ? t('切换静音') : t('点击或在画布内操作以解锁音效'))
|
|
396
411
|
},
|
|
397
412
|
isActive: () => mode === 'play',
|
|
398
413
|
})
|
|
@@ -499,5 +514,5 @@ events.addEventListener('state', (event) => {
|
|
|
499
514
|
})
|
|
500
515
|
|
|
501
516
|
setInterval(() => { void refreshState({ quiet: true }) }, 5000)
|
|
502
|
-
addEventListener('pagehide', () => play.destroy())
|
|
517
|
+
addEventListener('pagehide', () => { stageResize.disconnect(); play.destroy() })
|
|
503
518
|
void refreshState()
|