From 2b1129c10ee502df4a873fc1bafa83ec74398384 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 11:31:53 +0000 Subject: [PATCH 1/6] Rename the Scenes panel to Authoring and lay it out in steps The panel reads AUTHORING and groups its controls under SCENE, SHOTS, PREVIEW and SAVE & SHARE headings, with the EDIT DETAILS / SHARE SCENE row moved beside EXPORT / IMPORT. Text is larger with more contrast, shots are numbered, every action has a tooltip and the status line is a live region. Outside playback, buttons that would do nothing are disabled. New labels are translated in every shipped language; PLAY uses its own catalog context apart from the radio's PLAY. --- docs/CURRENT-STATE.md | 32 +++++--- docs/DIRECTOR-SHARING.md | 2 +- docs/SCENE-DOCUMENT.md | 2 +- src/i18n/locales/es.json | 31 +++++-- src/i18n/locales/ru.json | 31 +++++-- src/i18n/locales/zh-CN.json | 31 +++++-- src/i18n/locales/zh-Hant.json | 31 +++++-- src/ui/sceneControls.js | 41 +++++++-- src/ui/sceneControls.test.mjs | 31 +++++++ src/ui/scenePresentation.js | 21 ++++- src/ui/sceneSharing.js | 17 ++-- src/ui/styles/scenes.css | 128 +++++++++++++++++++++++------ src/ui/templates/layer-panels.html | 33 ++++---- 13 files changed, 336 insertions(+), 95 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 146e157d8..0e98ce774 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -535,7 +535,7 @@ Native ` - - + + + +

SHOTS

- - + +
+

Click a shot to select it, double-click to rename.

+

PREVIEW

- - - + + +
-
- - - +

SAVE & SHARE

+
+ + +
0%
-
Ready
+
Ready
From 452292001ad0d3b5a060be3ee87ee65aa33dde10 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 11:32:27 +0000 Subject: [PATCH 2/6] Add the changelog fragment for the Authoring panel --- changelog.d/1472-authoring-panel.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/1472-authoring-panel.md diff --git a/changelog.d/1472-authoring-panel.md b/changelog.d/1472-authoring-panel.md new file mode 100644 index 000000000..cec54b18e --- /dev/null +++ b/changelog.d/1472-authoring-panel.md @@ -0,0 +1,4 @@ +- Rename the Scenes panel to Authoring and lay it out in steps (Scene, Shots, + Preview, Save & share) with larger, higher-contrast text, numbered shots, a + tooltip on every action and buttons that are disabled when they would do + nothing (asturksever, #1472). From 4192a6f87d965b6b96395250543bf7396178d7c1 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 11:48:52 +0000 Subject: [PATCH 3/6] Keep Authoring within its stack and theme, and cover its wiring - Keep the documented 72px / flex-grow 1 action sizing and the 360px panel width; the larger type applies to the Authoring panel only, so CCTV and Street Level buttons are unchanged. - Scope the primary and file-row styles to the panel so Cyber's shared button surface no longer overrides them. - Shorten the scene PLAY in Spanish and Russian so it does not break mid-word, and fix two translation inconsistencies. - Map the spoken name "authoring" to the panel. - Clear the has-shots marker when the controls are destroyed. - Test the idle button states through published changes, the PLAY translation context, and where the sharing row is placed. --- docs/CURRENT-STATE.md | 3 +- src/i18n/locales/es.json | 4 +- src/i18n/locales/ru.json | 2 +- src/i18n/locales/zh-Hant.json | 2 +- src/ui/sceneControls.js | 1 + src/ui/sceneControls.test.mjs | 141 ++++++++++++++++++++++++++++++++++ src/ui/styles/scenes.css | 18 ++--- src/voice/gevActions.js | 1 + 8 files changed, 157 insertions(+), 15 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 0e98ce774..42865a09d 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1176,7 +1176,8 @@ The panel is titled Authoring and is laid out in four labelled steps: SCENE (picker on its own row, NEW SCENE, DELETE), SHOTS (+ CAPTURE SHOT, UPDATE SHOT, the numbered shot list and a select/rename hint), PREVIEW (PLAY, STOP, NEXT) and SAVE & SHARE (EXPORT, IMPORT, RUN LOG, then the EDIT DETAILS / SHARE SCENE row). -Every action has a tooltip, and the status line is a polite live region. Outside +Every button in the panel's step rows has a tooltip, and the status line is a +polite live region. Outside playback a button that would do nothing is disabled: DELETE and CAPTURE SHOT without a scene, UPDATE SHOT without a selected shot, PLAY and NEXT on a scene with no shots. During playback everything but STOP stays disabled as before. diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 6fd845182..e9ec5a1c6 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -3012,9 +3012,9 @@ "Add the current view, style and layers as the next shot": "Añade la vista, el estilo y las capas actuales como el siguiente plano", "Replace the selected shot with the current view": "Sustituye el plano seleccionado por la vista actual", "Click a shot to select it, double-click to rename.": "Haz clic en un plano para seleccionarlo y doble clic para cambiarle el nombre.", - "scene|PLAY": "REPRODUCIR", + "scene|PLAY": "REPROD.", "Play the whole scene from its first shot": "Reproduce toda la escena desde su primer plano", - "Stop playback (Esc)": "Detiene la reproducción (Esc)", + "Stop playback (Esc)": "Detén la reproducción (Esc)", "Play only the shot after the selected one": "Reproduce solo el plano posterior al seleccionado", "SAVE & SHARE": "GUARDAR Y COMPARTIR", "Download every scene as a JSON file you can import later": "Descarga todas las escenas como un archivo JSON que puedes importar más tarde", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index eacad5511..8d0ed1f24 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -3081,7 +3081,7 @@ "Add the current view, style and layers as the next shot": "Добавить текущий вид, стиль и слои следующим кадром", "Replace the selected shot with the current view": "Заменить выбранный кадр текущим видом", "Click a shot to select it, double-click to rename.": "Щёлкните кадр, чтобы выбрать его, дважды — чтобы переименовать.", - "scene|PLAY": "ВОСПРОИЗВЕСТИ", + "scene|PLAY": "ПУСК", "Play the whole scene from its first shot": "Воспроизвести всю сцену с первого кадра", "Stop playback (Esc)": "Остановить воспроизведение (Esc)", "Play only the shot after the selected one": "Воспроизвести только кадр после выбранного", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 17a98338d..33316d6ed 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -2862,7 +2862,7 @@ "routing busy — too many routes at once": "路線服務繁忙:同時請求的路線過多", "route proxy error": "路線代理出錯", "AUTHORING": "創作", - "Create and edit scenes": "建立和編輯場景", + "Create and edit scenes": "創建和編輯場景", "SCENE": "場景", "Scene": "場景", "NEW SCENE": "新建場景", diff --git a/src/ui/sceneControls.js b/src/ui/sceneControls.js index 3be960b9d..5976c2c05 100644 --- a/src/ui/sceneControls.js +++ b/src/ui/sceneControls.js @@ -272,6 +272,7 @@ export class SceneControls { ]) remove(); if (this.elements.shots) this.elements.shots.textContent = ''; + this.elements.panel?.classList.toggle('has-shots', false); presentSceneRuntime(this.elements.runtime, ''); this.setPlaybackActive(false); } diff --git a/src/ui/sceneControls.test.mjs b/src/ui/sceneControls.test.mjs index b150d36ed..b31a1a681 100644 --- a/src/ui/sceneControls.test.mjs +++ b/src/ui/sceneControls.test.mjs @@ -3,6 +3,8 @@ import assert from 'node:assert/strict'; import { createStateChannel } from '../app/stateChannel.js'; import { SceneControls } from './sceneControls.js'; import { SceneDirector } from '../scenes/director.js'; +import { mountSceneSharing } from './sceneSharing.js'; +import { setLocale } from '../i18n/index.js'; function fixture() { class Element extends EventTarget { @@ -466,3 +468,142 @@ test('Scene controls consume current state, preserve rows on progress, and unsub f.restore(); } }); + +test('Authoring refreshes idle buttons from published changes', () => { + const f = fixture(); + try { + f.owner.destroy(); + const channel = createStateChannel(() => f.state); + const owner = new SceneControls({ + read: () => f.state, + actions: f.actions, + elements: f.elements, + subscribe: (listener) => channel.subscribe(listener), + }); + const disabled = (name) => f.elements[name].disabled; + assert.equal(disabled('start'), false); + assert.equal(f.elements.panel.classList.contains('has-shots'), true); + + f.state.selectedShotId = null; + channel.publish({ type: 'selection-changed' }); + assert.equal(disabled('update'), true); + + f.state.scenes[0].shots = []; + channel.publish({ type: 'shot-deleted' }); + assert.equal(disabled('start'), true); + assert.equal(disabled('next'), true); + assert.equal(f.elements.panel.classList.contains('has-shots'), false); + + // A run that ends hands the buttons back with the idle rules applied. + f.state.running = true; + channel.publish({ type: 'buttons-changed' }); + assert.equal(disabled('capture'), true); + assert.equal(disabled('stop'), false); + f.state.running = false; + channel.publish({ type: 'buttons-changed' }); + assert.equal(disabled('capture'), false); + assert.equal(disabled('start'), true); + + f.state.scenes = []; + f.state.selectedSceneId = null; + channel.publish({ type: 'scene-deleted' }); + assert.equal(disabled('delete'), true); + assert.equal(disabled('capture'), true); + assert.equal(disabled('new'), false); + + f.state.scenes = [{ id: 'scene-b', title: 'B', shots: [{ id: 's' }] }]; + f.state.selectedSceneId = 'scene-b'; + f.state.selectedShotId = 's'; + channel.publish({ type: 'project-imported' }); + assert.equal(disabled('start'), false); + assert.equal(f.elements.panel.classList.contains('has-shots'), true); + + owner.destroy(); + assert.equal(f.elements.panel.classList.contains('has-shots'), false); + channel.destroy(); + } finally { + f.restore(); + } +}); + +test('Authoring PLAY uses the scene context, not the radio PLAY', (context) => { + context.after(() => setLocale('en')); + setLocale('es'); + const f = fixture(); + try { + assert.equal(f.elements.start.textContent, 'REPROD.'); + } finally { + f.restore(); + } +}); + +test('The sharing row sits under SAVE & SHARE, after the file row', () => { + const saved = globalThis.document; + const node = (className = '') => { + const element = { + className, + children: [], + dataset: {}, + parent: null, + addEventListener() {}, + removeEventListener() {}, + append(...items) { + for (const item of items) { + item.parent = element; + element.children.push(item); + } + }, + appendChild(item) { + element.append(item); + }, + after(item) { + const siblings = element.parent.children; + item.parent = element.parent; + siblings.splice(siblings.indexOf(element) + 1, 0, item); + }, + remove() { + const siblings = element.parent?.children; + if (siblings) siblings.splice(siblings.indexOf(element), 1); + }, + querySelector(selector) { + const name = selector.slice(1); + const walk = (at) => { + for (const child of at.children) { + if (child.className.split(' ').includes(name)) return child; + const found = walk(child); + if (found) return found; + } + return null; + }; + return walk(element); + }, + }; + return element; + }; + globalThis.document = { createElement: () => node() }; + try { + const panel = node(); + const inner = node('scene-panel-inner'); + const fileRow = node('scene-controls scene-file-controls'); + const status = node('scene-status'); + panel.append(inner); + inner.append(fileRow, status); + const dispose = mountSceneSharing({ edit() {}, share() {} }, panel); + const bar = inner.children[1]; + assert.equal(bar.className, 'scene-controls'); + assert.equal(inner.children[2], status); + assert.ok(bar.children.every((button) => button.title)); + dispose(); + assert.deepEqual(inner.children, [fileRow, status]); + + // Without the file row, the bar still lands inside the panel. + const plain = node(); + const plainInner = node('scene-panel-inner'); + plain.append(plainInner); + mountSceneSharing({ edit() {}, share() {} }, plain)(); + mountSceneSharing({ edit() {}, share() {} }, plain); + assert.equal(plainInner.children.length, 1); + } finally { + globalThis.document = saved; + } +}); diff --git a/src/ui/styles/scenes.css b/src/ui/styles/scenes.css index 975f37a57..f2bec04d9 100644 --- a/src/ui/styles/scenes.css +++ b/src/ui/styles/scenes.css @@ -1,6 +1,6 @@ /* ── Scene Director Panel ───────────────────── */ #scene-panel { - --panel-expanded-width: 372px; + --panel-expanded-width: 360px; /* Secondary text in Authoring: dimmer than labels, but legible on the globe. */ --scene-quiet: rgba(232, 234, 237, 0.62); position: fixed; @@ -179,6 +179,9 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { .scene-btn { flex: 1; min-width: 72px; +} + +#scene-panel .scene-btn { font-size: 10px; padding: 8px 10px; } @@ -206,21 +209,16 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { margin-top: 2px; } -/* One primary action per step: CAPTURE SHOT and PLAY. */ -.scene-btn-primary:not(:disabled) { +/* One primary action per step: CAPTURE SHOT and PLAY. The panel id keeps + this above Cyber's shared button surface. */ +#scene-panel .scene-btn-primary:not(:disabled) { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); } -#scene-capture-btn { - flex: 2 1 0; -} - /* The file row is housekeeping; it stays quieter than the steps above. */ -.scene-file-controls .scene-btn { - flex: 1 1 0; - min-width: 0; +#scene-panel .scene-file-controls .scene-btn { font-size: 9px; background: transparent; } diff --git a/src/voice/gevActions.js b/src/voice/gevActions.js index 0a43f02f1..f0afc9527 100644 --- a/src/voice/gevActions.js +++ b/src/voice/gevActions.js @@ -98,6 +98,7 @@ const PANEL_ALIASES = new Map([ ['global context', 'global-context-panel'], ['right context', 'global-context-panel'], ['context right panel', 'global-context-panel'], + ['authoring', 'scene-panel'], ['scenes', 'scene-panel'], ['scene', 'scene-panel'], ['post processing', 'pp-toggles'], From 8de75b172a941825413cb99441e66b124fe7b2bd Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 12:29:11 +0000 Subject: [PATCH 4/6] Keep two shot rows visible in Authoring on shorter windows The step headings make the panel taller, so the left stack squeezed the shot list down to one row at about 1000px of window height. Its minimum now holds two rows; the panel scrolls when space is short. --- src/ui/styles/scenes.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/styles/scenes.css b/src/ui/styles/scenes.css index f2bec04d9..9893061e1 100644 --- a/src/ui/styles/scenes.css +++ b/src/ui/styles/scenes.css @@ -245,7 +245,8 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { flex-direction: column; gap: 6px; max-height: 260px; - min-height: 72px; + /* Two shot rows stay visible; the panel scrolls when space is short. */ + min-height: 128px; flex: 1; overflow-y: auto; padding: 4px 2px 6px; From 5a80facf8d4254079bc7601bd299a8f0ad325897 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 18:39:53 +0000 Subject: [PATCH 5/6] Address review: playable PLAY/NEXT, visible rename editor, accurate copy - PLAY and NEXT continue into the following scenes, so they stay enabled while any scene in the project has a shot, not only the selected one. - Renaming a shot drops the number and ellipsis so the editor is no longer hidden; qa-scene-controls checks a long rename stays visible. - PLAY, NEXT, EDIT DETAILS and SHARE SCENE tooltips describe what the buttons do, translated in every shipped language. - The primary actions and the file row keep a hover state. - Docs: the EXPORT rename in DIRECTOR-SHARING and the playback button states in CURRENT-STATE are accurate. - Test the voice "authoring" alias through set_panel_open. --- docs/CURRENT-STATE.md | 14 +++++++------ docs/DIRECTOR-SHARING.md | 2 +- scripts/qa-scene-controls.mjs | 33 ++++++++++++++++++++++++++++++ src/i18n/locales/es.json | 8 ++++---- src/i18n/locales/ru.json | 8 ++++---- src/i18n/locales/zh-CN.json | 8 ++++---- src/i18n/locales/zh-Hant.json | 8 ++++---- src/ui/sceneControls.js | 6 +++++- src/ui/sceneControls.test.mjs | 9 ++++++++ src/ui/scenePresentation.js | 14 +++++++------ src/ui/sceneSharing.js | 8 ++++++-- src/ui/styles/scenes.css | 18 ++++++++++++++++ src/ui/templates/layer-panels.html | 4 ++-- src/voice/gevActions.test.mjs | 23 +++++++++++++++++++++ 14 files changed, 129 insertions(+), 34 deletions(-) diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 42865a09d..330249ec9 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1176,12 +1176,14 @@ The panel is titled Authoring and is laid out in four labelled steps: SCENE (picker on its own row, NEW SCENE, DELETE), SHOTS (+ CAPTURE SHOT, UPDATE SHOT, the numbered shot list and a select/rename hint), PREVIEW (PLAY, STOP, NEXT) and SAVE & SHARE (EXPORT, IMPORT, RUN LOG, then the EDIT DETAILS / SHARE SCENE row). -Every button in the panel's step rows has a tooltip, and the status line is a -polite live region. Outside -playback a button that would do nothing is disabled: DELETE and CAPTURE SHOT -without a scene, UPDATE SHOT without a selected shot, PLAY and NEXT on a scene -with no shots. During playback everything but STOP stays disabled as before. -PLAY uses the `scene|PLAY` catalog entry, apart from the radio's PLAY. +Every button in the step rows has a tooltip, and the status line is a polite +live region. Outside playback a button that would do nothing is disabled: +DELETE and CAPTURE SHOT without a scene, UPDATE SHOT without a selected shot, +PLAY and NEXT when no scene in the project has a shot (both continue into the +following scenes). During playback the authoring and file actions stay disabled +and STOP is enabled, as before; RUN LOG follows the last run, and EDIT DETAILS / +SHARE SCENE keep their own checks. PLAY uses the `scene|PLAY` catalog entry, +apart from the radio's PLAY. Director clock listeners, interaction observers and scene release failures no longer leave the director inconsistent, and a phase error is kept when cleanup diff --git a/docs/DIRECTOR-SHARING.md b/docs/DIRECTOR-SHARING.md index 4e3c5a85e..84e9d514a 100644 --- a/docs/DIRECTOR-SHARING.md +++ b/docs/DIRECTOR-SHARING.md @@ -42,7 +42,7 @@ field definitions. This is a basic draft editor, not a node graph or path editor SHARE SCENE exports only the selected scene. Download scene JSON preserves its camera, timing, layers, anchors, manifests, interactions and attribution, but contains no asset bytes. The recipient needs the referenced source registrations -and files. Existing EXPORT PRESETS continues to export the entire project. +and files. EXPORT (formerly EXPORT PRESETS) continues to export the entire project. For a bundle, select the declared pack files or a folder, then Download asset bundle. Folder paths match a manifest path either directly or after removing the diff --git a/scripts/qa-scene-controls.mjs b/scripts/qa-scene-controls.mjs index ab92c128d..223202221 100644 --- a/scripts/qa-scene-controls.mjs +++ b/scripts/qa-scene-controls.mjs @@ -106,6 +106,39 @@ try { ), ), ); + // A long rename keeps its editor visible inside the shot row. + await page.click('.scene-shot-label', { count: 2 }); + await page.waitForSelector('.scene-shot-rename', { visible: true }); + await page.type( + '.scene-shot-rename', + ' with a much longer title that runs well past the shot row', + ); + await page.keyboard.press('End'); + check( + 'A long rename keeps the editor visible inside its shot row', + await page.evaluate(() => { + // The label clips with an ellipsis, which hides an editor that + // overflows it, so its content must fit its width. + const input = document.querySelector('.scene-shot-rename'); + const label = input?.closest('.scene-shot-label'); + const box = input?.getBoundingClientRect(); + const style = input && getComputedStyle(input); + return ( + !!box && + box.width > 120 && + box.height > 10 && + label.scrollWidth <= label.clientWidth + 1 && + style.visibility === 'visible' && + style.borderTopWidth !== '0px' && + document.activeElement === input + ); + }), + ); + await page.keyboard.press('Escape'); + await page.waitForFunction( + () => !document.querySelector('.scene-shot-rename'), + ); + await page.click('#scene-capture-btn'); await page.waitForFunction( () => document.querySelectorAll('.scene-shot-row').length === 2, diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index e9ec5a1c6..759db7117 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -3013,13 +3013,13 @@ "Replace the selected shot with the current view": "Sustituye el plano seleccionado por la vista actual", "Click a shot to select it, double-click to rename.": "Haz clic en un plano para seleccionarlo y doble clic para cambiarle el nombre.", "scene|PLAY": "REPROD.", - "Play the whole scene from its first shot": "Reproduce toda la escena desde su primer plano", "Stop playback (Esc)": "Detén la reproducción (Esc)", - "Play only the shot after the selected one": "Reproduce solo el plano posterior al seleccionado", "SAVE & SHARE": "GUARDAR Y COMPARTIR", "Download every scene as a JSON file you can import later": "Descarga todas las escenas como un archivo JSON que puedes importar más tarde", "Load scenes from an exported JSON file": "Carga escenas desde un archivo JSON exportado", "Download the timing log of the last play": "Descarga el registro de tiempos de la última reproducción", - "Edit the scene title and description": "Edita el título y la descripción de la escena", - "Share this scene as a link or file": "Comparte esta escena como enlace o archivo" + "Play from this scene through the rest of the project": "Reproduce desde esta escena hasta el resto del proyecto", + "Play the shot after the selected one, moving on to the next scene when needed": "Reproduce el plano posterior al seleccionado y pasa a la siguiente escena si hace falta", + "Edit anchors, data packs and shot details": "Edita anclas, paquetes de datos y detalles de los planos", + "Download this scene as JSON or an asset bundle": "Descarga esta escena como JSON o como paquete de recursos" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 8d0ed1f24..c65265d5e 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -3082,13 +3082,13 @@ "Replace the selected shot with the current view": "Заменить выбранный кадр текущим видом", "Click a shot to select it, double-click to rename.": "Щёлкните кадр, чтобы выбрать его, дважды — чтобы переименовать.", "scene|PLAY": "ПУСК", - "Play the whole scene from its first shot": "Воспроизвести всю сцену с первого кадра", "Stop playback (Esc)": "Остановить воспроизведение (Esc)", - "Play only the shot after the selected one": "Воспроизвести только кадр после выбранного", "SAVE & SHARE": "СОХРАНИТЬ И ПОДЕЛИТЬСЯ", "Download every scene as a JSON file you can import later": "Скачать все сцены файлом JSON для последующего импорта", "Load scenes from an exported JSON file": "Загрузить сцены из экспортированного файла JSON", "Download the timing log of the last play": "Скачать журнал таймингов последнего воспроизведения", - "Edit the scene title and description": "Изменить название и описание сцены", - "Share this scene as a link or file": "Поделиться сценой ссылкой или файлом" + "Play from this scene through the rest of the project": "Воспроизвести с этой сцены и далее по всему проекту", + "Play the shot after the selected one, moving on to the next scene when needed": "Воспроизвести кадр после выбранного, при необходимости перейдя к следующей сцене", + "Edit anchors, data packs and shot details": "Изменить якоря, пакеты данных и параметры кадров", + "Download this scene as JSON or an asset bundle": "Скачать эту сцену в формате JSON или архивом ресурсов" } diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json index 21632d398..63f4b6b05 100644 --- a/src/i18n/locales/zh-CN.json +++ b/src/i18n/locales/zh-CN.json @@ -2875,13 +2875,13 @@ "Replace the selected shot with the current view": "用当前视角替换所选镜头", "Click a shot to select it, double-click to rename.": "单击镜头即可选中,双击可重命名。", "scene|PLAY": "播放", - "Play the whole scene from its first shot": "从第一个镜头开始播放整个场景", "Stop playback (Esc)": "停止播放(Esc)", - "Play only the shot after the selected one": "仅播放所选镜头的下一个镜头", "SAVE & SHARE": "保存与分享", "Download every scene as a JSON file you can import later": "将所有场景下载为 JSON 文件,以便日后导入", "Load scenes from an exported JSON file": "从导出的 JSON 文件加载场景", "Download the timing log of the last play": "下载上次播放的计时日志", - "Edit the scene title and description": "编辑场景标题和描述", - "Share this scene as a link or file": "以链接或文件形式分享此场景" + "Play from this scene through the rest of the project": "从此场景开始播放项目中的其余场景", + "Play the shot after the selected one, moving on to the next scene when needed": "播放所选镜头的下一个镜头,必要时进入下一个场景", + "Edit anchors, data packs and shot details": "编辑锚点、数据包和镜头详情", + "Download this scene as JSON or an asset bundle": "将此场景下载为 JSON 或资源包" } diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json index 33316d6ed..d42742659 100644 --- a/src/i18n/locales/zh-Hant.json +++ b/src/i18n/locales/zh-Hant.json @@ -2875,13 +2875,13 @@ "Replace the selected shot with the current view": "用當前視角替換所選鏡頭", "Click a shot to select it, double-click to rename.": "單擊鏡頭即可選中,雙擊可重命名。", "scene|PLAY": "播放", - "Play the whole scene from its first shot": "從第一個鏡頭開始播放整個場景", "Stop playback (Esc)": "停止播放(Esc)", - "Play only the shot after the selected one": "僅播放所選鏡頭的下一個鏡頭", "SAVE & SHARE": "保存與分享", "Download every scene as a JSON file you can import later": "將所有場景下載為 JSON 文件,以便日後導入", "Load scenes from an exported JSON file": "從導出的 JSON 文件加載場景", "Download the timing log of the last play": "下載上次播放的計時日誌", - "Edit the scene title and description": "編輯場景標題和描述", - "Share this scene as a link or file": "以鏈接或文件形式分享此場景" + "Play from this scene through the rest of the project": "從此場景開始播放項目中的其餘場景", + "Play the shot after the selected one, moving on to the next scene when needed": "播放所選鏡頭的下一個鏡頭,必要時進入下一個場景", + "Edit anchors, data packs and shot details": "編輯錨點、數據包和鏡頭詳情", + "Download this scene as JSON or an asset bundle": "將此場景下載為 JSON 或資源包" } diff --git a/src/ui/sceneControls.js b/src/ui/sceneControls.js index 5976c2c05..c7e023f10 100644 --- a/src/ui/sceneControls.js +++ b/src/ui/sceneControls.js @@ -220,7 +220,11 @@ export class SceneControls { const shots = scene?.shots ?? []; presentSceneButtons(this.elements, running, state.hasRun, { hasScene: !!scene, - shotCount: shots.length, + // PLAY and NEXT run on into the following scenes. + playableShots: (state.scenes ?? []).reduce( + (total, item) => total + (item.shots?.length ?? 0), + 0, + ), hasSelectedShot: shots.some((shot) => shot.id === state.selectedShotId), }); this.elements.panel?.classList.toggle('has-shots', shots.length > 0); diff --git a/src/ui/sceneControls.test.mjs b/src/ui/sceneControls.test.mjs index b31a1a681..f53612a66 100644 --- a/src/ui/sceneControls.test.mjs +++ b/src/ui/sceneControls.test.mjs @@ -184,7 +184,16 @@ test('Authoring disables idle actions that would do nothing', () => { assert.equal(f.elements.update.disabled, true); assert.equal(f.elements.start.disabled, false); + // PLAY and NEXT run on into the following scenes, so an empty selected + // scene beside one with shots keeps them available. f.state.scenes[0].shots = []; + f.state.scenes.push({ id: 'scene-b', title: 'B', shots: [{ id: 'b1' }] }); + f.owner.setButtons(false); + assert.equal(f.elements.start.disabled, false); + assert.equal(f.elements.next.disabled, false); + assert.equal(f.elements.update.disabled, true); + + f.state.scenes.pop(); f.owner.setButtons(false); assert.equal(f.elements.start.disabled, true); assert.equal(f.elements.next.disabled, true); diff --git a/src/ui/scenePresentation.js b/src/ui/scenePresentation.js index 4f5711226..e77c832f0 100644 --- a/src/ui/scenePresentation.js +++ b/src/ui/scenePresentation.js @@ -173,22 +173,24 @@ export function presentSceneSelection(element, selectedShotId) { } /** - * Everything but STOP is off while a scene plays. Otherwise a button is off - * when it would do nothing: DELETE and CAPTURE SHOT without a scene, UPDATE - * SHOT without a selected shot, PLAY and NEXT on a scene with no shots. + * While a scene plays, the authoring and file actions here are off and STOP + * is on. Otherwise a button is off when it would do nothing: DELETE and + * CAPTURE SHOT without a scene, UPDATE SHOT without a selected shot, PLAY and + * NEXT when no scene in the project has a shot (both continue into the + * following scenes). */ export function presentSceneButtons( elements, running, hasRun, - { hasScene = true, shotCount = 1, hasSelectedShot = true } = {}, + { hasScene = true, playableShots = 1, hasSelectedShot = true } = {}, ) { const idleOff = { delete: !hasScene, capture: !hasScene, update: !hasSelectedShot, - start: shotCount === 0, - next: shotCount === 0, + start: playableShots === 0, + next: playableShots === 0, }; for (const name of [ 'start', diff --git a/src/ui/sceneSharing.js b/src/ui/sceneSharing.js index 30fbe9732..e8ebf9110 100644 --- a/src/ui/sceneSharing.js +++ b/src/ui/sceneSharing.js @@ -181,8 +181,12 @@ export function mountSceneSharing( bar.dataset.directorAuthoring = ''; bar.className = 'scene-controls'; const entries = [ - [t('EDIT DETAILS'), t('Edit the scene title and description'), edit], - [t('SHARE SCENE'), t('Share this scene as a link or file'), share], + [t('EDIT DETAILS'), t('Edit anchors, data packs and shot details'), edit], + [ + t('SHARE SCENE'), + t('Download this scene as JSON or an asset bundle'), + share, + ], ]; const removers = []; for (const [text, title, fn] of entries) { diff --git a/src/ui/styles/scenes.css b/src/ui/styles/scenes.css index 9893061e1..441bbbf65 100644 --- a/src/ui/styles/scenes.css +++ b/src/ui/styles/scenes.css @@ -223,6 +223,14 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { background: transparent; } +/* Keep the shared hover on the restyled actions. */ +#scene-panel .scene-btn-primary:hover:not(:disabled), +#scene-panel .scene-file-controls .scene-btn:hover:not(:disabled) { + color: var(--accent); + border-color: var(--accent); + background: color-mix(in srgb, var(--accent) 16%, transparent); +} + .scene-shot-hint { margin: 0 0 8px; font-size: 11px; @@ -311,6 +319,16 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { color: var(--text-primary); } +/* While renaming, the label holds only the editor at full width. */ +.scene-shot-label:has(.scene-shot-rename) { + overflow: visible; + white-space: normal; +} + +.scene-shot-label:has(.scene-shot-rename)::before { + content: none; +} + /* Shots are numbered 01, 02… in playback order. */ .scene-shot-label::before { content: counter(scene-shot, decimal-leading-zero); diff --git a/src/ui/templates/layer-panels.html b/src/ui/templates/layer-panels.html index 02b02d05a..5f5d11b4d 100644 --- a/src/ui/templates/layer-panels.html +++ b/src/ui/templates/layer-panels.html @@ -166,9 +166,9 @@

Click a shot to select it, double-click to rename.

PREVIEW

- + - +

SAVE & SHARE

diff --git a/src/voice/gevActions.test.mjs b/src/voice/gevActions.test.mjs index 4a3a8ec72..6145a998d 100644 --- a/src/voice/gevActions.test.mjs +++ b/src/voice/gevActions.test.mjs @@ -3931,3 +3931,26 @@ test('analyst-only lookup distinguishes duplicate names and uses canonical aircr assert.equal(plane.ok, true); assert.equal(plane.latitude, 36, 'canonical ID resolves the current position, not old coordinates'); }); + +test('set_panel_open accepts the Authoring name for the scene panel', async () => { + const calls = []; + const runner = createGevActionRunner({ + viewer: { + clock: { onTick: { addEventListener: () => () => {} } }, + scene: { canvas: { addEventListener() {}, removeEventListener() {} } }, + camera: { + moveEnd: { addEventListener() {} }, + positionWC: Cesium.Cartesian3.fromDegrees(-97.7, 30.2, 1000), + }, + }, + styleManager: { + setPanelCollapsed: (...args) => calls.push(args), + }, + dataManager: { layers: new Map(), isEnabled: () => false, getAll: () => [] }, + }); + for (const panel of ['authoring', 'Authoring', 'scenes']) { + const result = await runner('set_panel_open', { panelId: panel, open: true }); + assert.equal(result.panelId, 'scene-panel'); + } + assert.deepEqual(calls.at(-1), ['scene-panel', false, { explicit: true }]); +}); From a4820315d9ac091753e22faab192050711434a23 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 18:47:56 +0000 Subject: [PATCH 6/6] Translate Authoring for the six new languages and fit long words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the Authoring labels and tooltips to the de, fr, it, ja, pt and uk catalogs that arrived from main, and prunes the retired SCENES-era entries there. The file row's tighter padding and letter spacing keep one long translated word per line in the narrow Cyber panel (IMPORTIEREN, ESECUZIONE, ІМПОРТУВАТИ, EJECUCIÓN). --- src/i18n/locales/de.json | 31 ++++++++++++++++++++++++------- src/i18n/locales/fr.json | 31 ++++++++++++++++++++++++------- src/i18n/locales/it.json | 31 ++++++++++++++++++++++++------- src/i18n/locales/ja.json | 31 ++++++++++++++++++++++++------- src/i18n/locales/pt.json | 31 ++++++++++++++++++++++++------- src/i18n/locales/uk.json | 31 ++++++++++++++++++++++++------- src/ui/styles/scenes.css | 3 +++ 7 files changed, 147 insertions(+), 42 deletions(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 874fd5f31..3c5618b5b 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -833,13 +833,7 @@ "SAVE CAL": "KAL. SPEICHERN", "RESET CAL": "KAL. ZURÜCKSETZEN", "SCENE SUMMARY": "SZENEN-ÜBERSICHT", - "SCENES": "SZENEN", - "Scene recipe": "Szenenrezept", - "NEW": "NEU", - "CAPTURE SHOT": "AUFNAHME SPEICHERN", "UPDATE SHOT": "AUFNAHME AKTUALISIEREN", - "START": "START", - "EXPORT PRESETS": "PRESETS EXPORTIEREN", "IMPORT": "IMPORTIEREN", "RUN LOG": "PROTOKOLL", "POWER UP": "STARTKLAR", @@ -2922,5 +2916,28 @@ "Malformed cyclone snapshot": "Fehlerhafter Wirbelsturm-Snapshot", "STALE · Roads: {source} · Flow: cached TomTom tiles": "VERALTET · Straßen: {source} · Verkehrsfluss: TomTom-Kacheln aus dem Cache", "routing busy — too many routes at once": "Routing-Dienst ausgelastet – zu viele Routen gleichzeitig", - "route proxy error": "Fehler des Routen-Proxys" + "route proxy error": "Fehler des Routen-Proxys", + "scene|PLAY": "START", + "AUTHORING": "ERSTELLUNG", + "Create and edit scenes": "Szenen erstellen und bearbeiten", + "SCENE": "SZENE", + "Scene": "Szene", + "NEW SCENE": "NEUE SZENE", + "Start a new, empty scene": "Neue, leere Szene beginnen", + "DELETE": "LÖSCHEN", + "Delete this scene and all of its shots": "Diese Szene mit allen Aufnahmen löschen", + "SHOTS": "AUFNAHMEN", + "+ CAPTURE SHOT": "+ AUFNAHME SPEICHERN", + "Add the current view, style and layers as the next shot": "Aktuelle Ansicht, Stil und Ebenen als nächste Aufnahme hinzufügen", + "Replace the selected shot with the current view": "Ausgewählte Aufnahme durch die aktuelle Ansicht ersetzen", + "Click a shot to select it, double-click to rename.": "Aufnahme anklicken zum Auswählen, Doppelklick zum Umbenennen.", + "Play from this scene through the rest of the project": "Ab dieser Szene bis zum Ende des Projekts abspielen", + "Stop playback (Esc)": "Wiedergabe stoppen (Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "Aufnahme nach der ausgewählten abspielen, bei Bedarf in der nächsten Szene", + "SAVE & SHARE": "SPEICHERN & TEILEN", + "Download every scene as a JSON file you can import later": "Alle Szenen als JSON-Datei zum späteren Import herunterladen", + "Load scenes from an exported JSON file": "Szenen aus einer exportierten JSON-Datei laden", + "Download the timing log of the last play": "Zeitprotokoll der letzten Wiedergabe herunterladen", + "Edit anchors, data packs and shot details": "Anker, Datenpakete und Aufnahmedetails bearbeiten", + "Download this scene as JSON or an asset bundle": "Diese Szene als JSON oder Asset-Bundle herunterladen" } diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 005a22417..9fbe32264 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -2954,13 +2954,7 @@ "ALL": "TOUTES", "FLAT": "CLASSIQUES", "SINCE": "DEPUIS", - "SCENES": "SCÈNES", - "Scene recipe": "Recette de scène", - "NEW": "NOUV.", - "CAPTURE SHOT": "CAPTURER UN PLAN", "UPDATE SHOT": "MAJ DU PLAN", - "START": "LANCER", - "EXPORT PRESETS": "EXPORTER LES PRÉRÉGLAGES", "IMPORT": "IMPORTER", "RUN LOG": "JOURNAL", "POWER UP": "ALLUMER", @@ -2991,5 +2985,28 @@ "ESC to dismiss": "ESC pour fermer", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Astuce : le bouton GEV MIC du dock permet de parler à la carte.", "Malformed cyclone snapshot": "Instantané cyclonique mal formé", - "Cyclone request timed out": "Délai dépassé pour la requête cyclonique" + "Cyclone request timed out": "Délai dépassé pour la requête cyclonique", + "scene|PLAY": "LIRE", + "AUTHORING": "CRÉATION", + "Create and edit scenes": "Créer et modifier des scènes", + "SCENE": "SCÈNE", + "Scene": "Scène", + "NEW SCENE": "NOUVELLE SCÈNE", + "Start a new, empty scene": "Commencer une nouvelle scène vide", + "DELETE": "SUPPRIMER", + "Delete this scene and all of its shots": "Supprimer cette scène et tous ses plans", + "SHOTS": "PLANS", + "+ CAPTURE SHOT": "+ CAPTURER UN PLAN", + "Add the current view, style and layers as the next shot": "Ajouter la vue, le style et les couches actuels comme plan suivant", + "Replace the selected shot with the current view": "Remplacer le plan sélectionné par la vue actuelle", + "Click a shot to select it, double-click to rename.": "Cliquez sur un plan pour le sélectionner, double-cliquez pour le renommer.", + "Play from this scene through the rest of the project": "Lire de cette scène jusqu'à la fin du projet", + "Stop playback (Esc)": "Arrêter la lecture (Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "Lire le plan qui suit la sélection, en passant à la scène suivante si besoin", + "SAVE & SHARE": "ENREGISTRER ET PARTAGER", + "Download every scene as a JSON file you can import later": "Télécharger toutes les scènes dans un fichier JSON à importer plus tard", + "Load scenes from an exported JSON file": "Charger des scènes depuis un fichier JSON exporté", + "Download the timing log of the last play": "Télécharger le journal de minutage de la dernière lecture", + "Edit anchors, data packs and shot details": "Modifier les ancres, les paquets de données et les détails des plans", + "Download this scene as JSON or an asset bundle": "Télécharger cette scène en JSON ou en archive de ressources" } diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index bc9732d67..42938ab2e 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -2954,13 +2954,7 @@ "ALL": "TUTTE", "FLAT": "PIATTE", "SINCE": "DAL", - "SCENES": "SCENE", - "Scene recipe": "Ricetta della scena", - "NEW": "NUOVA", - "CAPTURE SHOT": "CATTURA SCATTO", "UPDATE SHOT": "AGGIORNA SCATTO", - "START": "AVVIA", - "EXPORT PRESETS": "ESPORTA PRESET", "IMPORT": "IMPORTA", "RUN LOG": "LOG ESECUZIONE", "POWER UP": "ACCENDI", @@ -2991,5 +2985,28 @@ "ESC to dismiss": "ESC per chiudere", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Suggerimento: il pulsante GEV MIC nel dock ti permette di parlare con la mappa.", "Malformed cyclone snapshot": "Snapshot dei cicloni non valido", - "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout" + "Cyclone request timed out": "La richiesta dei cicloni è andata in timeout", + "scene|PLAY": "AVVIA", + "AUTHORING": "CREAZIONE", + "Create and edit scenes": "Crea e modifica le scene", + "SCENE": "SCENA", + "Scene": "Scena", + "NEW SCENE": "NUOVA SCENA", + "Start a new, empty scene": "Inizia una nuova scena vuota", + "DELETE": "ELIMINA", + "Delete this scene and all of its shots": "Elimina questa scena e tutti i suoi scatti", + "SHOTS": "SCATTI", + "+ CAPTURE SHOT": "+ CATTURA SCATTO", + "Add the current view, style and layers as the next shot": "Aggiungi la vista, lo stile e i livelli attuali come scatto successivo", + "Replace the selected shot with the current view": "Sostituisci lo scatto selezionato con la vista attuale", + "Click a shot to select it, double-click to rename.": "Fai clic su uno scatto per selezionarlo, doppio clic per rinominarlo.", + "Play from this scene through the rest of the project": "Riproduci da questa scena fino alla fine del progetto", + "Stop playback (Esc)": "Interrompi la riproduzione (Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "Riproduci lo scatto dopo quello selezionato, passando alla scena successiva se serve", + "SAVE & SHARE": "SALVA E CONDIVIDI", + "Download every scene as a JSON file you can import later": "Scarica tutte le scene in un file JSON da importare in seguito", + "Load scenes from an exported JSON file": "Carica le scene da un file JSON esportato", + "Download the timing log of the last play": "Scarica il log dei tempi dell'ultima riproduzione", + "Edit anchors, data packs and shot details": "Modifica ancore, pacchetti dati e dettagli degli scatti", + "Download this scene as JSON or an asset bundle": "Scarica questa scena come JSON o pacchetto di risorse" } diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 7ac2840f6..34e4ffaf5 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -2814,13 +2814,7 @@ "ALL": "すべて", "FLAT": "平面", "SINCE": "期間", - "SCENES": "シーン", - "Scene recipe": "シーンレシピ", - "NEW": "新規", - "CAPTURE SHOT": "ショット取得", "UPDATE SHOT": "ショット更新", - "START": "開始", - "EXPORT PRESETS": "エクスポート", "IMPORT": "インポート", "RUN LOG": "実行ログ", "POWER UP": "パワーアップ", @@ -2853,5 +2847,28 @@ "routing busy — too many routes at once": "ルート検索サービスが混雑しています。同時に要求されたルートが多すぎます", "route proxy error": "ルート検索プロキシでエラーが発生しました", "Malformed cyclone snapshot": "サイクロンのスナップショットの形式が不正です", - "Cyclone request timed out": "サイクロンのリクエストがタイムアウトしました" + "Cyclone request timed out": "サイクロンのリクエストがタイムアウトしました", + "scene|PLAY": "再生", + "AUTHORING": "作成", + "Create and edit scenes": "シーンを作成・編集", + "SCENE": "シーン", + "Scene": "シーン", + "NEW SCENE": "新規シーン", + "Start a new, empty scene": "空の新しいシーンを作成", + "DELETE": "削除", + "Delete this scene and all of its shots": "このシーンとすべてのショットを削除", + "SHOTS": "ショット", + "+ CAPTURE SHOT": "+ ショット取得", + "Add the current view, style and layers as the next shot": "現在の視点・スタイル・レイヤーを次のショットとして追加", + "Replace the selected shot with the current view": "選択中のショットを現在の視点で置き換え", + "Click a shot to select it, double-click to rename.": "ショットをクリックして選択、ダブルクリックで名前を変更します。", + "Play from this scene through the rest of the project": "このシーンからプロジェクトの最後まで再生", + "Stop playback (Esc)": "再生を停止(Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "選択中の次のショットを再生(必要に応じて次のシーンへ進む)", + "SAVE & SHARE": "保存と共有", + "Download every scene as a JSON file you can import later": "すべてのシーンを、後でインポートできるJSONファイルとしてダウンロード", + "Load scenes from an exported JSON file": "書き出したJSONファイルからシーンを読み込む", + "Download the timing log of the last play": "前回の再生のタイミングログをダウンロード", + "Edit anchors, data packs and shot details": "アンカー、データパック、ショットの詳細を編集", + "Download this scene as JSON or an asset bundle": "このシーンをJSONまたはアセットバンドルとしてダウンロード" } diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 5e9a9a3ff..e4fe30626 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -2956,13 +2956,7 @@ "ALL": "TODAS", "FLAT": "PLANAS", "SINCE": "DESDE", - "SCENES": "CENAS", - "Scene recipe": "Receita de cena", - "NEW": "NOVA", - "CAPTURE SHOT": "CAPTURAR PLANO", "UPDATE SHOT": "ATUALIZAR PLANO", - "START": "INICIAR", - "EXPORT PRESETS": "EXPORTAR PREDEF.", "IMPORT": "IMPORTAR", "RUN LOG": "REGISTRO", "POWER UP": "ATIVAR", @@ -2991,5 +2985,28 @@ "Begin with a clean globe": "Comece com um globo limpo", "Don't show this again": "Não mostrar novamente", "ESC to dismiss": "ESC para fechar", - "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa." + "Tip: the GEV MIC button in the dock lets you talk to the map.": "Dica: o botão GEV MIC no dock permite falar com o mapa.", + "scene|PLAY": "INICIAR", + "AUTHORING": "CRIAÇÃO", + "Create and edit scenes": "Criar e editar cenas", + "SCENE": "CENA", + "Scene": "Cena", + "NEW SCENE": "NOVA CENA", + "Start a new, empty scene": "Começar uma nova cena vazia", + "DELETE": "EXCLUIR", + "Delete this scene and all of its shots": "Excluir esta cena e todos os seus planos", + "SHOTS": "PLANOS", + "+ CAPTURE SHOT": "+ CAPTURAR PLANO", + "Add the current view, style and layers as the next shot": "Adicionar a vista, o estilo e as camadas atuais como próximo plano", + "Replace the selected shot with the current view": "Substituir o plano selecionado pela vista atual", + "Click a shot to select it, double-click to rename.": "Clique em um plano para selecioná-lo e clique duas vezes para renomeá-lo.", + "Play from this scene through the rest of the project": "Reproduzir desta cena até o fim do projeto", + "Stop playback (Esc)": "Parar a reprodução (Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "Reproduzir o plano após o selecionado, passando à próxima cena se necessário", + "SAVE & SHARE": "SALVAR E COMPARTILHAR", + "Download every scene as a JSON file you can import later": "Baixar todas as cenas em um arquivo JSON para importar depois", + "Load scenes from an exported JSON file": "Carregar cenas de um arquivo JSON exportado", + "Download the timing log of the last play": "Baixar o registro de tempos da última reprodução", + "Edit anchors, data packs and shot details": "Editar âncoras, pacotes de dados e detalhes dos planos", + "Download this scene as JSON or an asset bundle": "Baixar esta cena como JSON ou pacote de recursos" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index f87454f1a..28fab0d40 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -3023,13 +3023,7 @@ "ALL": "УСІ", "FLAT": "ПЛОСКІ", "SINCE": "З ДАТИ", - "SCENES": "СЦЕНИ", - "Scene recipe": "Рецепт сцени", - "NEW": "НОВА", - "CAPTURE SHOT": "ЗНЯТИ КАДР", "UPDATE SHOT": "ОНОВИТИ КАДР", - "START": "СТАРТ", - "EXPORT PRESETS": "ЕКСПОРТУВАТИ ПРЕСЕТИ", "IMPORT": "ІМПОРТУВАТИ", "RUN LOG": "ЖУРНАЛ ВІДТВОРЕННЯ", "POWER UP": "ЗАПУСК", @@ -3060,5 +3054,28 @@ "ESC to dismiss": "ESC — приховати", "Tip: the GEV MIC button in the dock lets you talk to the map.": "Порада: кнопка МІК у доку дає змогу говорити з картою.", "Malformed cyclone snapshot": "Некоректний знімок циклонів", - "Cyclone request timed out": "Минув час очікування запиту циклонів" + "Cyclone request timed out": "Минув час очікування запиту циклонів", + "scene|PLAY": "СТАРТ", + "AUTHORING": "РЕДАКТОР", + "Create and edit scenes": "Створення й редагування сцен", + "SCENE": "СЦЕНА", + "Scene": "Сцена", + "NEW SCENE": "НОВА СЦЕНА", + "Start a new, empty scene": "Створити нову порожню сцену", + "DELETE": "ВИДАЛИТИ", + "Delete this scene and all of its shots": "Видалити цю сцену з усіма кадрами", + "SHOTS": "КАДРИ", + "+ CAPTURE SHOT": "+ ЗНЯТИ КАДР", + "Add the current view, style and layers as the next shot": "Додати поточний вигляд, стиль і шари як наступний кадр", + "Replace the selected shot with the current view": "Замінити вибраний кадр поточним виглядом", + "Click a shot to select it, double-click to rename.": "Натисніть кадр, щоб вибрати його, двічі — щоб перейменувати.", + "Play from this scene through the rest of the project": "Відтворити від цієї сцени до кінця проєкту", + "Stop playback (Esc)": "Зупинити відтворення (Esc)", + "Play the shot after the selected one, moving on to the next scene when needed": "Відтворити кадр після вибраного, за потреби перейшовши до наступної сцени", + "SAVE & SHARE": "ЗБЕРЕГТИ Й ПОДІЛИТИСЯ", + "Download every scene as a JSON file you can import later": "Завантажити всі сцени файлом JSON для подальшого імпорту", + "Load scenes from an exported JSON file": "Завантажити сцени з експортованого файлу JSON", + "Download the timing log of the last play": "Завантажити журнал таймінгів останнього відтворення", + "Edit anchors, data packs and shot details": "Змінити якорі, пакети даних і параметри кадрів", + "Download this scene as JSON or an asset bundle": "Завантажити цю сцену у форматі JSON або архівом ресурсів" } diff --git a/src/ui/styles/scenes.css b/src/ui/styles/scenes.css index 441bbbf65..726d7507a 100644 --- a/src/ui/styles/scenes.css +++ b/src/ui/styles/scenes.css @@ -220,6 +220,9 @@ html:not([lang='en']) #scene-panel .scene-controls .scene-btn { /* The file row is housekeeping; it stays quieter than the steps above. */ #scene-panel .scene-file-controls .scene-btn { font-size: 9px; + /* Room for one long translated word (IMPORTIEREN, ІМПОРТУВАТИ) per line. */ + padding: 8px 4px; + letter-spacing: 0.6px; background: transparent; }