mirror of
https://github.com/thunderheronight/splat-workshop.git
synced 2026-10-18 06:01:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20b1262fa9 |
No files matched your search
@@ -2,6 +2,17 @@
|
||||
|
||||
All notable changes to Splat Workshop. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versions follow [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [0.4.1] – 2026-10-15
|
||||
|
||||
Setup made clearer – thanks to the first two issues from outside (#1, #2).
|
||||
|
||||
### Fixed
|
||||
|
||||
- **A typo in the config is pointed out**: a setting Splat Workshop does not know – such as `splat-transform =` instead of `splat_transform =` – used to be ignored silently, so splat-transform stayed "not found" without a reason. Now the setup hints name it, with the right spelling. `install.sh` does too.
|
||||
- **splat-transform on the shell's PATH only**: `install.sh` checked the PATH of the shell it runs in, but Splat Workshop, started from the desktop or the tray, does not read `.bashrc`/`.zshrc` – the installer said ✓, the app said "not found". Now `install.sh` writes the full path into a new config, or prints the line to add to an existing one; the hint in the app explains why and how.
|
||||
- **The npm instructions** in the setup guide installed into a folder whose path did not match the one given for the config. Now: `npm install -g --prefix ~/arcturus/node @playcanvas/splat-transform` (no root needed) and `~/arcturus/node/bin/splat-transform`.
|
||||
- **The Arcturus pipeline and PyAV 19** ("unexpected keyword argument 'metadata_errors'"): Splat Workshop now spots a pipeline that is not pinned to PyAV below 19 before you start, and names the cause and the fix when a conversion fails because of it – instead of only a traceback. It does not change the pipeline itself.
|
||||
|
||||
## [0.4.0] – 2026-10-15
|
||||
|
||||
### Added
|
||||
@@ -138,6 +149,7 @@ First release.
|
||||
- **Floor plans** (experimental) in two styles with a measuring tool.
|
||||
- Configurable video player; English and German interface.
|
||||
|
||||
[0.4.1]: https://github.com/thunderheronight/splat-workshop/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://github.com/thunderheronight/splat-workshop/compare/v0.3.1...v0.4.0
|
||||
[0.3.1]: https://github.com/thunderheronight/splat-workshop/compare/v0.3.0...v0.3.1
|
||||
[0.3.0]: https://github.com/thunderheronight/splat-workshop/compare/v0.2.3...v0.3.0
|
||||
|
||||
@@ -88,7 +88,15 @@ Wandelt das Ergebnis in das kompakte SOG-Format, das Gaussian XR lädt:
|
||||
npm install -g @playcanvas/splat-transform
|
||||
```
|
||||
|
||||
Ohne globale Installation: `npm install --prefix ~/arcturus/node @playcanvas/splat-transform` und in der Config `splat_transform = "~/arcturus/node/bin/splat-transform"` eintragen.
|
||||
Scheitert `npm install -g` an fehlenden Rechten, ins eigene Home installieren – ohne root:
|
||||
|
||||
```bash
|
||||
npm install -g --prefix ~/arcturus/node @playcanvas/splat-transform
|
||||
```
|
||||
|
||||
und in der Config unter `[paths]` `splat_transform = "~/arcturus/node/bin/splat-transform"` eintragen (mit Unterstrich – `splat-transform =` ist keine Einstellung und wird ignoriert; die Splat-Werkstatt weist darauf hin).
|
||||
|
||||
**Immer den vollen Pfad in die Config schreiben**, wenn splat-transform nur im PATH deiner Shell steht (`.bashrc`, `.zshrc`): Vom Desktop oder Tray gestartet liest die Splat-Werkstatt diese Dateien nicht und findet es sonst nicht. `install.sh` trägt die Zeile ein oder gibt sie aus.
|
||||
|
||||
## 5. Der Splat-Werkstatt sagen, wo alles liegt
|
||||
|
||||
@@ -106,7 +114,7 @@ Splat-Werkstatt neu starten (Tray → Beenden, dann wieder starten). Fehlt noch
|
||||
|
||||
| Meldung / Problem | Ursache / Lösung |
|
||||
|---|---|
|
||||
| `av.open() got an unexpected keyword argument 'metadata_errors'` | PyAV 19 hat diese Option entfernt. Ältere Version festlegen: im `# /// script`-Kopf oben in `av1_to_3dgs.py` und `av1_colmap.py` `"av>=18.1"` in `"av>=18.1,<19"` ändern. (Mit der Pipeline vom Herbst 2026 nötig; neuere Versionen haben es evtl. behoben.) |
|
||||
| `av.open() got an unexpected keyword argument 'metadata_errors'` | PyAV 19 hat diese Option entfernt. Ältere Version festlegen: im `# /// script`-Kopf oben in `av1_to_3dgs.py` und `av1_colmap.py` `"av>=18.1"` in `"av>=18.1,<19"` ändern. (Mit der Pipeline vom Herbst 2026 nötig; neuere Versionen haben es evtl. behoben.) Die Splat-Werkstatt (ab 0.4.1) weist schon vor dem Start in ihren Einrichtungshinweisen darauf hin und nennt den Grund, falls eine Umwandlung daran scheitert. |
|
||||
| `Could not select unique evenly spaced capture instants` | Aufnahme zu kurz. Die Pipeline braucht mindestens 100 Aufnahmezeitpunkte – mindestens 10 Sekunden aufnehmen, besser 30+. |
|
||||
| Spirula findet keine GPU / nutzt llvmpipe | Vulkan-Treiber fehlt, siehe Schritt 1. |
|
||||
| Die Szene taucht in Gaussian XR nicht auf | Sie muss als echter Ordner (kein Symlink) mit den Galeriebildern in `Scenes/` von Gaussian XR liegen – das macht der Knopf *Auf die Frame*. Ein Steam-Update oder „Dateien überprüfen“ von Gaussian XR kann den Ordner zurücksetzen; dann die Szene einfach neu übertragen. |
|
||||
|
||||
+10
-2
@@ -88,7 +88,15 @@ Converts the result into the compact SOG format that Gaussian XR loads:
|
||||
npm install -g @playcanvas/splat-transform
|
||||
```
|
||||
|
||||
If you can't or don't want to install globally: `npm install --prefix ~/arcturus/node @playcanvas/splat-transform` and set `splat_transform = "~/arcturus/node/bin/splat-transform"` in the config.
|
||||
If `npm install -g` fails with a permission error, install it into your home instead – no root needed:
|
||||
|
||||
```bash
|
||||
npm install -g --prefix ~/arcturus/node @playcanvas/splat-transform
|
||||
```
|
||||
|
||||
and set `splat_transform = "~/arcturus/node/bin/splat-transform"` under `[paths]` in the config (with an underscore – `splat-transform =` is not a setting and is ignored; Splat Workshop points that out).
|
||||
|
||||
**Always set the full path in the config** if splat-transform is only on the PATH of your shell (`.bashrc`, `.zshrc`): started from the desktop or the tray, Splat Workshop does not read those files and would not find it. `install.sh` writes or prints the line for you.
|
||||
|
||||
## 5. Tell Splat Workshop where everything is
|
||||
|
||||
@@ -106,7 +114,7 @@ Restart Splat Workshop (tray → Quit, then start it again). If something is sti
|
||||
|
||||
| Symptom | Cause / fix |
|
||||
|---|---|
|
||||
| `av.open() got an unexpected keyword argument 'metadata_errors'` | PyAV 19 removed that option. Pin the older version: in the `# /// script` header at the top of `av1_to_3dgs.py` and `av1_colmap.py`, change `"av>=18.1"` to `"av>=18.1,<19"`. (Was needed with the pipeline from autumn 2026; newer versions may have fixed it.) |
|
||||
| `av.open() got an unexpected keyword argument 'metadata_errors'` | PyAV 19 removed that option. Pin the older version: in the `# /// script` header at the top of `av1_to_3dgs.py` and `av1_colmap.py`, change `"av>=18.1"` to `"av>=18.1,<19"`. (Was needed with the pipeline from autumn 2026; newer versions may have fixed it.) Splat Workshop (0.4.1 and newer) points this out in its setup hints before you start, and names it if a conversion fails because of it. |
|
||||
| `Could not select unique evenly spaced capture instants` | Recording too short. The pipeline needs at least 100 capture instants – record at least 10 seconds, better 30+. |
|
||||
| Spirula finds no GPU / uses llvmpipe | Vulkan driver missing, see step 1. |
|
||||
| The scene does not appear in Gaussian XR | It must be a real folder in Gaussian XR's `Scenes/` (no symlink) with the gallery images – Splat Workshop's *To the Frame* button does this for you. A Steam update or “verify files” of Gaussian XR can reset that folder; just copy the scene again. |
|
||||
|
||||
+24
-3
@@ -26,19 +26,40 @@ for tool in ffmpeg ffprobe uv ssh curl; do
|
||||
command -v "$tool" >/dev/null && echo " ✓ $tool" || { echo " ✗ $tool"; missing=1; }
|
||||
done
|
||||
command -v splat-transform >/dev/null && echo " ✓ splat-transform" ||
|
||||
echo " ! splat-transform not on PATH (npm install -g @playcanvas/splat-transform, or set it in the config)"
|
||||
echo " ! splat-transform not on PATH (npm install -g --prefix ~/.local @playcanvas/splat-transform needs no root; or set its path in the config)"
|
||||
python3 -c 'import PySide6' 2>/dev/null && echo " ✓ PySide6 (tray icon)" ||
|
||||
echo " · PySide6 not installed – uv will fetch it on first start for the tray icon"
|
||||
[ $missing = 0 ] || echo "Install the missing tools first (see README)."
|
||||
|
||||
mkdir -p "$CONF" "$APPS" "$ICONS"
|
||||
created=0
|
||||
if [ ! -f "$CONF/config.toml" ]; then
|
||||
cp "$ROOT/config.example.toml" "$CONF/config.toml"
|
||||
echo "Created $CONF/config.toml – set the paths to the Arcturus pipeline and Spirula, and your Frame's address."
|
||||
created=1
|
||||
echo "Created $CONF/config.toml from config.example.toml – set the paths to the Arcturus pipeline and Spirula, and your Frame's address."
|
||||
else
|
||||
echo "Keeping existing $CONF/config.toml"
|
||||
echo "Keeping existing $CONF/config.toml (all settings with explanations: $ROOT/config.example.toml)"
|
||||
fi
|
||||
|
||||
# Started from the desktop, Splat Workshop does not see a PATH set in .bashrc/.zshrc: give it the full path
|
||||
st=$(command -v splat-transform || true)
|
||||
conf_st=$(python3 -c 'import sys, tomllib
|
||||
print(tomllib.load(open(sys.argv[1], "rb")).get("paths", {}).get("splat_transform", ""))' "$CONF/config.toml" 2>/dev/null || true)
|
||||
if [ -n "$st" ] && [ -z "$conf_st" ]; then
|
||||
if [ $created = 1 ]; then
|
||||
sed -i "s|^splat_transform = \"\"|splat_transform = \"$st\"|" "$CONF/config.toml"
|
||||
echo " ✓ splat_transform = \"$st\" written to the config"
|
||||
else
|
||||
echo " ! Add this line under [paths] in $CONF/config.toml – started from the desktop,"
|
||||
echo " Splat Workshop does not see the PATH of your shell:"
|
||||
echo " splat_transform = \"$st\""
|
||||
fi
|
||||
fi
|
||||
# Settings Splat Workshop does not know (typos such as "splat-transform" instead of "splat_transform")
|
||||
(cd "$ROOT" && python3 -c 'from splat_workshop import config
|
||||
for key, hint in config.load().unknown:
|
||||
print(f" ! Unknown setting \"{key}\" in the config" + (f" – did you mean \"{hint}\"?" if hint else " – it is ignored"))') || true
|
||||
|
||||
cp "$ROOT/web/icon.svg" "$ICONS/splat-workshop.svg"
|
||||
entry() {
|
||||
cat <<EOF
|
||||
|
||||
@@ -5,7 +5,9 @@ Order: built-in defaults < ~/.config/splat-workshop/config.toml (or $SPLAT_WORKS
|
||||
|
||||
`python3 -m splat_workshop.config --shell` prints the values as shell assignments for scripts/.
|
||||
"""
|
||||
import difflib
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
@@ -32,9 +34,47 @@ DEFAULTS = {
|
||||
}
|
||||
|
||||
|
||||
def unknown_keys(data: dict) -> list[tuple[str, str]]:
|
||||
"""Settings in the config file that Splat Workshop does not know (e.g. a typo: "splat-transform"),
|
||||
as ("section.key", suggestion or "")."""
|
||||
out = []
|
||||
for section, values in data.items():
|
||||
if section not in DEFAULTS:
|
||||
close = difflib.get_close_matches(section, DEFAULTS, n=1, cutoff=0.6)
|
||||
out.append((section, close[0] if close else ""))
|
||||
continue
|
||||
if not isinstance(values, dict):
|
||||
continue
|
||||
for key in values:
|
||||
if key not in DEFAULTS[section]:
|
||||
close = difflib.get_close_matches(key.replace("-", "_"), DEFAULTS[section], n=1, cutoff=0.6)
|
||||
out.append((f"{section}.{key}", f"{section}.{close[0]}" if close else ""))
|
||||
return out
|
||||
|
||||
|
||||
# PyAV 19 removed av.open(metadata_errors=...), which the Arcturus pipeline (autumn 2026) uses
|
||||
PYAV_FILES = ("av1_to_3dgs.py", "av1_colmap.py")
|
||||
RX_AV_DEP = re.compile(r'^#\s*"av(?P<spec>[^"]*)"', re.M)
|
||||
|
||||
|
||||
def pyav_unpinned(pipeline: Path) -> list[str]:
|
||||
"""Pipeline scripts that use metadata_errors but allow PyAV 19 or newer."""
|
||||
out = []
|
||||
for name in PYAV_FILES:
|
||||
try:
|
||||
text = (pipeline / name).read_text(errors="replace")
|
||||
except OSError:
|
||||
continue
|
||||
m = RX_AV_DEP.search(text)
|
||||
if "metadata_errors" in text and m and "<19" not in m["spec"].replace(" ", ""):
|
||||
out.append(name)
|
||||
return out
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, data: dict, source: Path | None):
|
||||
def __init__(self, data: dict, source: Path | None, unknown=()):
|
||||
self.source = source
|
||||
self.unknown = list(unknown)
|
||||
base = source.parent if source else Path.home()
|
||||
|
||||
def path(v: str) -> Path:
|
||||
@@ -63,12 +103,17 @@ class Config:
|
||||
def problems(self) -> list[tuple[str, dict]]:
|
||||
"""Missing prerequisites as (message key, params) for the setup hints in the UI."""
|
||||
out = []
|
||||
for key, suggestion in self.unknown:
|
||||
out.append(("setup.unknown_key" if suggestion else "setup.unknown_key.plain",
|
||||
{"key": key, "suggestion": suggestion, "file": str(self.source)}))
|
||||
if not (self.pipeline / "av1_to_3dgs.py").is_file():
|
||||
out.append(("setup.pipeline", {"path": str(self.pipeline)}))
|
||||
elif bad := pyav_unpinned(self.pipeline):
|
||||
out.append(("setup.pyav", {"files": ", ".join(bad), "path": str(self.pipeline)}))
|
||||
if not os.access(self.spirula, os.X_OK):
|
||||
out.append(("setup.spirula", {"path": str(self.spirula)}))
|
||||
if not self.splat_transform:
|
||||
out.append(("setup.splat_transform", {}))
|
||||
out.append(("setup.splat_transform", {"file": str(self.source or CONFIG_FILE)}))
|
||||
for tool in ("ffmpeg", "ffprobe", "uv"):
|
||||
if not shutil.which(tool):
|
||||
out.append(("setup.tool", {"tool": tool}))
|
||||
@@ -103,12 +148,12 @@ def _merge(base: dict, over: dict) -> dict:
|
||||
|
||||
|
||||
def load() -> Config:
|
||||
data, source = DEFAULTS, None
|
||||
data, source, unknown = DEFAULTS, None, []
|
||||
if CONFIG_FILE.is_file():
|
||||
with open(CONFIG_FILE, "rb") as fh:
|
||||
data = _merge(DEFAULTS, tomllib.load(fh))
|
||||
source = CONFIG_FILE
|
||||
return Config(data, source)
|
||||
own = tomllib.load(fh)
|
||||
data, source, unknown = _merge(DEFAULTS, own), CONFIG_FILE, unknown_keys(own)
|
||||
return Config(data, source, unknown)
|
||||
|
||||
|
||||
def shell(cfg: Config) -> str:
|
||||
|
||||
@@ -29,7 +29,7 @@ from pathlib import Path
|
||||
from . import check, config
|
||||
from .i18n import T, detect
|
||||
|
||||
VERSION = "0.4.0"
|
||||
VERSION = "0.4.1"
|
||||
CFG = config.load()
|
||||
ROOT = config.ROOT
|
||||
WEB = ROOT / "web"
|
||||
@@ -594,9 +594,16 @@ def parse_output(text: str) -> dict:
|
||||
info["done"] = True
|
||||
if d[1] == "frame" and d[2]:
|
||||
info["folder"] = d[2]
|
||||
for needle, hint in KNOWN_FAILURES:
|
||||
if needle in text:
|
||||
info["hint"] = hint
|
||||
return {"phase": phase, "pct": pct, "eta": eta, "info": info}
|
||||
|
||||
|
||||
# Failures with a known cause: a line of the pipeline's output -> a hint in the interface (web/i18n.js)
|
||||
KNOWN_FAILURES = (("unexpected keyword argument 'metadata_errors'", "hint.pyav"),)
|
||||
|
||||
|
||||
def job_status(tail=True) -> dict | None:
|
||||
st = load_state().get("job")
|
||||
if not st:
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"""Setup hints (0.4.1, from issues #1 and #2): typos in the config, splat-transform only on the shell's PATH,
|
||||
an Arcturus pipeline that PyAV 19 breaks."""
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from conftest import ROOT, server
|
||||
from splat_workshop import config
|
||||
|
||||
UNPINNED = '''#!/usr/bin/env -S uv run --script
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "av>=18.1",
|
||||
# "numpy",
|
||||
# ]
|
||||
# ///
|
||||
import av
|
||||
av.open("x", metadata_errors="strict")
|
||||
'''
|
||||
|
||||
|
||||
def test_a_typo_in_the_config_is_named_with_the_right_spelling():
|
||||
unknown = config.unknown_keys({"paths": {"splat-transform": "/x", "pipeline": "/p"}, "frmae": {"host": ""}})
|
||||
assert unknown == [("paths.splat-transform", "paths.splat_transform"), ("frmae", "frame")]
|
||||
c = config.Config(config._merge(config.DEFAULTS, {}), None, unknown)
|
||||
keys = [k for k, _ in c.problems()]
|
||||
assert keys[:2] == ["setup.unknown_key", "setup.unknown_key"]
|
||||
|
||||
|
||||
def test_a_pipeline_that_pyav_19_breaks_is_found(tmp_path):
|
||||
for name in config.PYAV_FILES:
|
||||
(tmp_path / name).write_text(UNPINNED)
|
||||
assert config.pyav_unpinned(tmp_path) == list(config.PYAV_FILES)
|
||||
(tmp_path / "av1_colmap.py").write_text(UNPINNED.replace('"av>=18.1"', '"av>=18.1,<19"'))
|
||||
assert config.pyav_unpinned(tmp_path) == ["av1_to_3dgs.py"]
|
||||
c = config.Config(config._merge(config.DEFAULTS, {"paths": {"pipeline": str(tmp_path)}}), None)
|
||||
hint = dict(c.problems())["setup.pyav"]
|
||||
assert hint["files"] == "av1_to_3dgs.py"
|
||||
|
||||
|
||||
def test_a_conversion_failing_on_pyav_says_why():
|
||||
out = server.parse_output("Traceback ...\nTypeError: open() got an unexpected keyword argument 'metadata_errors'\n")
|
||||
assert out["info"]["hint"] == "hint.pyav"
|
||||
assert "hint" not in server.parse_output("Traceback ...\nValueError: something else\n")["info"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("existing", [False, True])
|
||||
def test_install_gives_the_full_path_of_splat_transform(tmp_path, existing):
|
||||
"""install.sh finds splat-transform on the shell's PATH: a new config gets the full path, an existing one
|
||||
a line to add – the app, started from the desktop, does not see that PATH."""
|
||||
home, xdg, bin_ = tmp_path / "home", tmp_path / "xdg", tmp_path / "bin"
|
||||
for d in (home, xdg, bin_):
|
||||
d.mkdir()
|
||||
(bin_ / "splat-transform").write_text("#!/bin/sh\n")
|
||||
(bin_ / "splat-transform").chmod(0o755)
|
||||
conf = xdg / "splat-workshop" / "config.toml"
|
||||
if existing:
|
||||
conf.parent.mkdir()
|
||||
conf.write_text('[paths]\nsplat-transform = "/typo"\n')
|
||||
env = {**os.environ, "HOME": str(home), "XDG_CONFIG_HOME": str(xdg), "XDG_DATA_HOME": str(tmp_path / "data"),
|
||||
"PATH": f"{bin_}:{os.environ['PATH']}"}
|
||||
env.pop("SPLAT_WORKSHOP_CONFIG", None)
|
||||
r = subprocess.run([str(ROOT / "install.sh")], env=env, capture_output=True, text=True, timeout=120)
|
||||
assert r.returncode == 0, r.stderr
|
||||
line = f'splat_transform = "{bin_ / "splat-transform"}"'
|
||||
if existing:
|
||||
assert line in r.stdout and line not in conf.read_text()
|
||||
assert 'Unknown setting "paths.splat-transform"' in r.stdout and '"paths.splat_transform"' in r.stdout
|
||||
else:
|
||||
assert line in conf.read_text() and "written to the config" in r.stdout
|
||||
+10
-2
@@ -15,7 +15,10 @@ const I18N = {
|
||||
"setup.hint": "Settings are in {file}. Restart Splat Workshop after changing them.",
|
||||
"setup.pipeline": "Arcturus pipeline not found in {path} (av1_to_3dgs.py). Download it from arcturus.vision/apps.",
|
||||
"setup.spirula": "Spirula Studio not found at {path}. Build it as described in the pipeline README.",
|
||||
"setup.splat_transform": "splat-transform not found – install it with: npm install -g @playcanvas/splat-transform",
|
||||
"setup.splat_transform": "splat-transform not found. Install it (without root: npm install -g --prefix ~/.local @playcanvas/splat-transform) and put its full path into {file}, e.g. splat_transform = \"/home/you/.local/bin/splat-transform\" – started from the desktop, Splat Workshop does not see a PATH set in .bashrc or .zshrc.",
|
||||
"setup.unknown_key": "Unknown setting “{key}” in {file} – did you mean “{suggestion}”? (Splat Workshop ignores it.)",
|
||||
"setup.unknown_key.plain": "Unknown setting “{key}” in {file} – Splat Workshop ignores it.",
|
||||
"setup.pyav": "The Arcturus pipeline in {path} will fail with “unexpected keyword argument 'metadata_errors'” (PyAV 19). In the # /// script header of {files}, change \"av>=18.1\" to \"av>=18.1,<19\" – see Troubleshooting in docs/arcturus-setup.md.",
|
||||
"setup.tool": "{tool} is not installed.",
|
||||
// job card
|
||||
"job.cancel": "Cancel", "job.dismiss": "Hide", "job.log": "Log",
|
||||
@@ -33,6 +36,7 @@ const I18N = {
|
||||
"res.cancelled": "Cancelled. Start again with the same name and choose “Resume” to continue.",
|
||||
"res.upload_failed": "The scene is finished, but copying to the Frame did not work (Frame off?). Use “To the Frame” in the list of finished scenes once it is on.",
|
||||
"res.failed": "Failed – the last lines of the log show why.",
|
||||
"hint.pyav": "Failed: the Arcturus pipeline does not work with PyAV 19 (“unexpected keyword argument 'metadata_errors'”). In the # /// script header of av1_to_3dgs.py and av1_colmap.py, change \"av>=18.1\" to \"av>=18.1,<19\", then resume – see Troubleshooting in docs/arcturus-setup.md.",
|
||||
"confirm.cancel": "Really cancel the conversion? With “Resume” you can continue later from the last saved state.",
|
||||
// step 1
|
||||
"s1.title": "Choose a recording", "tab.frame": "On the Frame", "tab.local": "On this PC",
|
||||
@@ -300,7 +304,10 @@ const I18N = {
|
||||
"setup.hint": "Die Einstellungen stehen in {file}. Nach Änderungen die Splat-Werkstatt neu starten.",
|
||||
"setup.pipeline": "Arcturus-Pipeline nicht gefunden in {path} (av1_to_3dgs.py). Download: arcturus.vision/apps.",
|
||||
"setup.spirula": "Spirula Studio nicht gefunden unter {path}. Bauen wie in der Pipeline-README beschrieben.",
|
||||
"setup.splat_transform": "splat-transform fehlt – installieren mit: npm install -g @playcanvas/splat-transform",
|
||||
"setup.splat_transform": "splat-transform nicht gefunden. Installieren (ohne root: npm install -g --prefix ~/.local @playcanvas/splat-transform) und den vollen Pfad in {file} eintragen, z. B. splat_transform = \"/home/du/.local/bin/splat-transform\" – vom Desktop gestartet sieht die Splat-Werkstatt keinen PATH aus .bashrc oder .zshrc.",
|
||||
"setup.unknown_key": "Unbekannte Einstellung „{key}“ in {file} – meintest du „{suggestion}“? (Die Splat-Werkstatt ignoriert sie.)",
|
||||
"setup.unknown_key.plain": "Unbekannte Einstellung „{key}“ in {file} – die Splat-Werkstatt ignoriert sie.",
|
||||
"setup.pyav": "Die Arcturus-Pipeline in {path} wird mit „unexpected keyword argument 'metadata_errors'“ scheitern (PyAV 19). Im # /// script-Kopf von {files} \"av>=18.1\" in \"av>=18.1,<19\" ändern – siehe Troubleshooting in docs/arcturus-setup.md.",
|
||||
"setup.tool": "{tool} ist nicht installiert.",
|
||||
"job.cancel": "Abbrechen", "job.dismiss": "Ausblenden", "job.log": "Protokoll",
|
||||
"job.standby": "💤 Danach in den Standby", "job.standby.in": "💤 Standby in {s} s",
|
||||
@@ -317,6 +324,7 @@ const I18N = {
|
||||
"res.cancelled": "Abgebrochen. Mit gleichem Namen erneut starten und „Fortsetzen“ wählen, um weiterzumachen.",
|
||||
"res.upload_failed": "Die Szene ist fertig gerechnet, aber das Kopieren auf die Frame hat nicht geklappt (Frame aus?). In der Liste der fertigen Szenen „Auf die Frame“ nutzen, sobald sie an ist.",
|
||||
"res.failed": "Fehlgeschlagen – die letzten Zeilen im Protokoll zeigen warum.",
|
||||
"hint.pyav": "Fehlgeschlagen: Die Arcturus-Pipeline läuft nicht mit PyAV 19 („unexpected keyword argument 'metadata_errors'“). Im # /// script-Kopf von av1_to_3dgs.py und av1_colmap.py \"av>=18.1\" in \"av>=18.1,<19\" ändern und fortsetzen – siehe Troubleshooting in docs/arcturus-setup.md.",
|
||||
"confirm.cancel": "Umwandlung wirklich abbrechen? Mit „Fortsetzen“ geht es später ab dem letzten Zwischenstand weiter.",
|
||||
"s1.title": "Aufnahme wählen", "tab.frame": "Auf der Frame", "tab.local": "Auf dem PC",
|
||||
"dl.all": "Alle holen ({n} · {size})", "dl.all.title": "Alle Aufnahmen, die noch nicht auf dem PC sind, nacheinander holen",
|
||||
|
||||
+1
-1
@@ -1016,7 +1016,7 @@ function renderJob() {
|
||||
: tr("res.ok.local", {name: j.name, path: "runs/" + j.slug}); }
|
||||
else if (j.result === "cancelled") { res.className = "result warn"; res.textContent = tr("res.cancelled"); }
|
||||
else if (j.phase === 4) { res.className = "result warn"; res.textContent = tr("res.upload_failed"); }
|
||||
else { res.className = "result bad"; res.textContent = tr("res.failed"); }
|
||||
else { res.className = "result bad"; res.textContent = i.hint ? tr(i.hint) : tr("res.failed"); }
|
||||
}
|
||||
const log = $("#log"), atBottom = log.scrollTop + log.clientHeight >= log.scrollHeight - 20;
|
||||
log.textContent = j.tail || ""; if (atBottom) log.scrollTop = log.scrollHeight;
|
||||
|
||||
Reference in new issue
Block a user