#!/usr/bin/env bash # Visuelle Modell-Checks fuer Wackelpeter (Bazzite/KDE Wayland). # # Öffnet den Modell-Viewer (web/viewer.html) in einem eigenen Firefox-Fenster, # macht Turntable-Screenshots und räumt danach auf (Fenster zu, Konsole wieder # sichtbar, eigener Dev-Server gestoppt). Die Pfade der Crops gehen auf stdout. # # Usage: scripts/model_shot.sh [shots=4] [intervall-sek=1.5] [still] # modell-id: spider ghost frog bat bee slime brute crab turret shaman archer # bomber wisp turtle spore golem krake minotaurus spiderqueen # frostgiant necromancer dragon gnome mazeguard # still: beliebiges 4. Argument -> statische Pose (&still=1) # # Voraussetzung: maximiertes Firefox-Fenster auf 3440x1440 (feste Crop-Box). set -u MODEL="${1:?Modell-ID erforderlich, z.B. dragon}" SHOTS="${2:-4}" INTERVAL="${3:-1.5}" STILL="${4:-}" PORT=3100 cd "$(dirname "$0")/.." || exit 1 URL="http://localhost:$PORT/viewer.html?m=$MODEL" [ -n "$STILL" ] && URL="$URL&still=1" # --- eigener Dev-Server auf 3100 (nicht den Nutzer-Server auf 3000 anfassen) --- started_server=0 if ! ss -tln | grep -q ":$PORT "; then (cd web && npx vite --port "$PORT" --strictPort > /tmp/viewer-vite.log 2>&1 &) started_server=1 for _ in $(seq 1 40); do ss -tln | grep -q ":$PORT " && break sleep 0.5 done fi # --- KWin-Scripte (Fensterverwaltung ohne Fokus-Raten) --- kwin_run() { local name="$1" file="/tmp/qwen_kwin_$1.js" printf '%s\n' "$2" > "$file" qdbus org.kde.KWin /Scripting unloadScript "$name" > /dev/null 2>&1 qdbus org.kde.KWin /Scripting loadScript "$file" "$name" > /dev/null qdbus org.kde.KWin /Scripting start > /dev/null } kwin_run viewer_min 'for (const c of workspace.windowList()) { if (c.resourceClass.toLowerCase().includes("konsole")) c.minimized = true; }' flatpak run org.mozilla.firefox --new-window "$URL" > /dev/null 2>&1 & sleep 6 # --- Screenshots + feste Crop-Box (Mitte des maximierten Fensters) --- for i in $(seq 1 "$SHOTS"); do # Viewer-Fenster vor jedem Shot nach vorn holen (sonst kapert ein anderes # Fenster den Desktop-Screenshot) kwin_run viewer_raise 'for (const c of workspace.windowList()) { if (c.caption.includes("Modell-Viewer")) { c.minimized = false; workspace.activeWindow = c; } }' sleep 0.4 spectacle -b -n -o "/tmp/modelshot_$i.png" magick "/tmp/modelshot_$i.png" -crop 2200x1200+600+100 +repage "/tmp/modelshot_${i}_crop.png" echo "/tmp/modelshot_${i}_crop.png" [ "$i" -lt "$SHOTS" ] && sleep "$INTERVAL" done # --- Aufräumen: Konsole einblenden, Viewer-Fenster schließen --- kwin_run viewer_restore 'for (const c of workspace.windowList()) { const cls = c.resourceClass.toLowerCase(); if (cls.includes("konsole")) c.minimized = false; if (c.caption.includes("Modell-Viewer")) c.closeWindow(); }' if [ "$started_server" = 1 ]; then PID=$(ss -tlnp | grep ":$PORT " | grep -oP 'pid=\K[0-9]+' | head -1) [ -n "${PID:-}" ] && kill "$PID" 2> /dev/null fi