From 829a512c7da1b75c8033dc7fe3111504af2ade51 Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 14:00:46 +0300 Subject: [PATCH 1/8] Update depth_helper.py --- wallpaper_depth/depth_helper.py | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/wallpaper_depth/depth_helper.py b/wallpaper_depth/depth_helper.py index 85098d8..511c261 100755 --- a/wallpaper_depth/depth_helper.py +++ b/wallpaper_depth/depth_helper.py @@ -55,6 +55,95 @@ def atomic_json(path: Path, value: dict[str, object]) -> None: os.replace(temporary, path) +def is_nixos() -> bool: + """NixOS has no FHS-style /lib, /usr/lib search path, so pip-installed + manylinux wheels (numpy/onnxruntime/Pillow) can fail to find shared + libraries such as libstdc++.so.6 at import time even though `pip install` + itself succeeds.""" + if Path("/etc/NIXOS").exists(): + return True + try: + os_release = Path("/etc/os-release").read_text(encoding="utf-8") + except OSError: + return False + return any(line.strip() in ('ID=nixos', 'ID="nixos"') for line in os_release.splitlines()) + + +# stdenv.cc.cc.lib provides libstdc++.so.6 and libgcc_s.so.1 (onnxruntime) +# and libgomp.so.1 (numpy's OpenBLAS threading); zlib covers Pillow/onnxruntime +# fallbacks that aren't always vendored inside the wheel itself. +NIX_LIBRARY_PACKAGES = ("stdenv.cc.cc.lib", "zlib") + + +def nix_library_cache_path(data_dir: Path) -> Path: + return data_dir / "runtime" / "nix-library-path.json" + + +def resolve_nix_library_path(data_dir: Path) -> str: + cache_path = nix_library_cache_path(data_dir) + try: + cached = json.loads(cache_path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + cached = None + if ( + isinstance(cached, dict) + and cached.get("packages") == list(NIX_LIBRARY_PACKAGES) + and isinstance(cached.get("libDirs"), list) + ): + lib_dirs = [Path(entry) for entry in cached["libDirs"]] + if lib_dirs and all(path.is_dir() for path in lib_dirs): + return os.pathsep.join(str(path) for path in lib_dirs) + + store_paths: list[str] = [] + for attribute in NIX_LIBRARY_PACKAGES: + try: + result = subprocess.run( + ["nix-build", "", "-A", attribute, "--no-out-link"], + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + except FileNotFoundError as error: + raise RuntimeError( + "nix-build was not found; cannot resolve NixOS runtime libraries " + "needed by numpy/onnxruntime/Pillow" + ) from error + if result.returncode != 0 or not result.stdout.strip(): + raise RuntimeError( + f"nix-build could not resolve nixpkgs#{attribute}: " + f"{result.stderr.strip() or 'no output'}" + ) + store_paths.append(result.stdout.strip().splitlines()[-1]) + + lib_dirs = [str(Path(path) / "lib") for path in store_paths] + atomic_json( + cache_path, + {"packages": list(NIX_LIBRARY_PACKAGES), "libDirs": lib_dirs, "resolvedAt": int(time.time())}, + ) + return os.pathsep.join(lib_dirs) + + +def ensure_nixos_dynamic_linking(data_dir: Path) -> None: + """On NixOS, re-exec this interpreter with LD_LIBRARY_PATH patched so + pip-installed manylinux wheels can find libstdc++/libgomp/zlib. Every + subprocess spawned afterwards (venv creation, pip install, the runtime + readiness check, and the venv python that runs `generate`) inherits this + process's environment, so patching it once here is enough for the whole + plugin -- no changes to service.luau are needed.""" + if os.environ.get("_WALLPAPER_DEPTH_NIXOS_PATCHED") == "1": + return + if not is_nixos(): + return + lib_path = resolve_nix_library_path(data_dir) + existing = os.environ.get("LD_LIBRARY_PATH", "") + new_env = dict(os.environ) + new_env["LD_LIBRARY_PATH"] = f"{lib_path}{os.pathsep}{existing}" if existing else lib_path + new_env["_WALLPAPER_DEPTH_NIXOS_PATCHED"] = "1" + os.execve(sys.executable, [sys.executable] + sys.argv, new_env) + + def runtime_python(data_dir: Path) -> Path: return data_dir / "runtime" / ".venv" / "bin" / "python" @@ -393,6 +482,7 @@ def main() -> int: args = parse_args() data_dir = args.data_dir.expanduser().resolve() try: + ensure_nixos_dynamic_linking(data_dir) if args.command == "setup": setup(data_dir) elif args.command == "status": From 1a7f1fa4d7e27aef0ffd1df0562afebce36e8493 Mon Sep 17 00:00:00 2001 From: portanz Date: Sun, 23 Aug 2026 20:01:08 +0300 Subject: [PATCH 2/8] Add wallpaper_depth_large --- wallpaper_depth_large/README.md | 71 +++ wallpaper_depth_large/depth_helper.py | 506 +++++++++++++++++++++ wallpaper_depth_large/panel.luau | 232 ++++++++++ wallpaper_depth_large/plugin.toml | 49 ++ wallpaper_depth_large/service.luau | 491 ++++++++++++++++++++ wallpaper_depth_large/thumbnail.webp | Bin 0 -> 77234 bytes wallpaper_depth_large/translations/en.json | 69 +++ 7 files changed, 1418 insertions(+) create mode 100644 wallpaper_depth_large/README.md create mode 100755 wallpaper_depth_large/depth_helper.py create mode 100644 wallpaper_depth_large/panel.luau create mode 100644 wallpaper_depth_large/plugin.toml create mode 100644 wallpaper_depth_large/service.luau create mode 100644 wallpaper_depth_large/thumbnail.webp create mode 100644 wallpaper_depth_large/translations/en.json diff --git a/wallpaper_depth_large/README.md b/wallpaper_depth_large/README.md new file mode 100644 index 0000000..56b575d --- /dev/null +++ b/wallpaper_depth_large/README.md @@ -0,0 +1,71 @@ +# Wallpaper Depth + +Wallpaper Depth generates a foreground mask for each image wallpaper, allowing +Noctalia desktop widgets to pass behind nearby scenery. + +Depth estimation runs locally with +[Depth Anything V2 Small](https://huggingface.co/onnx-community/depth-anything-v2-small). +Wallpapers are never uploaded. + +## Plugin + +| Field | Value | +| --- | --- | +| ID | `noctalia/wallpaper_depth` | +| Entries | Service: `service`; panel: `manager` | + +## Requirements + +Install `python3` version 3.11โ€“3.14 with `venv` and `pip` support. Initial setup +requires network access, and shell offline mode must be disabled. + +From the plugin panel, setup creates an isolated Python environment in the +plugin data directory and downloads the 99 MB Apache-2.0 Depth Anything V2 +Small ONNX model from Hugging Face. The runtime contains pinned versions of +NumPy, ONNX Runtime, and Pillow; it does not modify the system Python +environment. + +## Usage + +1. Open the **Wallpaper Depth** panel, or toggle it from a terminal: + + ```sh + noctalia msg panel-toggle noctalia/wallpaper_depth:manager + ``` + +2. Select **Install model** and wait for setup to finish. +3. Apply an image wallpaper to each desired output. +4. Select **Generate masks**, or leave **Generate automatically** enabled. +5. Adjust **Foreground threshold** and **Edge feather** in the plugin settings + when the default mask does not match the scene. + +The panel reports generation state for every connected output. **Clear cache** +removes saved depth maps and masks; the plugin regenerates them when needed. + +## Settings + +| Setting | Type | Default | Description | +| --- | --- | --- | --- | +| `auto_generate` | `bool` | `true` | Regenerates masks when a wallpaper or mask parameter changes. | +| `threshold` | `int` | `50` | Normalized depth cutoff from 0โ€“100. Lower values place more of the scene in front of desktop widgets. | +| `feather` | `int` | `8` | Soft-transition width around the depth cutoff, from 0โ€“50. | + +## How it works + +The service processes each output independently. It preserves the wallpaper's +aspect ratio during inference, normalizes the relative depth prediction, and +refines it against the source image before applying the configured threshold +and feather. The resulting mask is restored to the wallpaper's original +resolution and registered with Noctalia for that output. + +Depth predictions are cached separately from masks, so changing threshold or +feather can reuse the expensive model result. Cache entries are keyed by the +wallpaper contents, model revision, and processing version, and old entries are +pruned automatically. + +## Licensing and privacy + +The plugin is MIT-licensed. Depth Anything V2 Small is downloaded at setup time +under the Apache-2.0 license. Model inference, depth caches, and generated masks +remain in the local plugin data directory; only the model download contacts +Hugging Face. diff --git a/wallpaper_depth_large/depth_helper.py b/wallpaper_depth_large/depth_helper.py new file mode 100755 index 0000000..511c261 --- /dev/null +++ b/wallpaper_depth_large/depth_helper.py @@ -0,0 +1,506 @@ +#!/usr/bin/env python3 +"""Bootstrap Depth Anything V2 Small and generate source-aligned wallpaper masks.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile +import time +import urllib.request + +MODEL_REVISION = "4472b7362082ad9968fee890ca0f1e5aca36b93d" +MODEL_URL = ( + "https://huggingface.co/onnx-community/depth-anything-v2-small/resolve/" + f"{MODEL_REVISION}/onnx/model.onnx?download=true" +) +MODEL_SHA256 = "afb6a5c28f3b6bf1618c6e43f02073ef9dfdc70e937502d51603e57b0a1df10c" +MODEL_SIZE = 99_060_839 +INPUT_SIZE = 518 +MODEL_PATCH_SIZE = 14 +DEPTH_PIPELINE_VERSION = 2 +MASK_PIPELINE_VERSION = 3 +REFINEMENT_MAX_DIMENSION = 1920 +GUIDED_FILTER_RADIUS = 8 +GUIDED_FILTER_EPSILON = 0.001 +PYTHON_MIN = (3, 11) +PYTHON_MAX = (3, 14) +PACKAGES = ( + "numpy==2.4.2", + "onnxruntime==1.28.0", + "Pillow==12.3.0", +) + + +def sha256_file(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as stream: + for chunk in iter(lambda: stream.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def atomic_json(path: Path, value: dict[str, object]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile("w", dir=path.parent, delete=False, encoding="utf-8") as stream: + json.dump(value, stream, separators=(",", ":"), sort_keys=True) + stream.write("\n") + temporary = Path(stream.name) + os.replace(temporary, path) + + +def is_nixos() -> bool: + """NixOS has no FHS-style /lib, /usr/lib search path, so pip-installed + manylinux wheels (numpy/onnxruntime/Pillow) can fail to find shared + libraries such as libstdc++.so.6 at import time even though `pip install` + itself succeeds.""" + if Path("/etc/NIXOS").exists(): + return True + try: + os_release = Path("/etc/os-release").read_text(encoding="utf-8") + except OSError: + return False + return any(line.strip() in ('ID=nixos', 'ID="nixos"') for line in os_release.splitlines()) + + +# stdenv.cc.cc.lib provides libstdc++.so.6 and libgcc_s.so.1 (onnxruntime) +# and libgomp.so.1 (numpy's OpenBLAS threading); zlib covers Pillow/onnxruntime +# fallbacks that aren't always vendored inside the wheel itself. +NIX_LIBRARY_PACKAGES = ("stdenv.cc.cc.lib", "zlib") + + +def nix_library_cache_path(data_dir: Path) -> Path: + return data_dir / "runtime" / "nix-library-path.json" + + +def resolve_nix_library_path(data_dir: Path) -> str: + cache_path = nix_library_cache_path(data_dir) + try: + cached = json.loads(cache_path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + cached = None + if ( + isinstance(cached, dict) + and cached.get("packages") == list(NIX_LIBRARY_PACKAGES) + and isinstance(cached.get("libDirs"), list) + ): + lib_dirs = [Path(entry) for entry in cached["libDirs"]] + if lib_dirs and all(path.is_dir() for path in lib_dirs): + return os.pathsep.join(str(path) for path in lib_dirs) + + store_paths: list[str] = [] + for attribute in NIX_LIBRARY_PACKAGES: + try: + result = subprocess.run( + ["nix-build", "", "-A", attribute, "--no-out-link"], + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + except FileNotFoundError as error: + raise RuntimeError( + "nix-build was not found; cannot resolve NixOS runtime libraries " + "needed by numpy/onnxruntime/Pillow" + ) from error + if result.returncode != 0 or not result.stdout.strip(): + raise RuntimeError( + f"nix-build could not resolve nixpkgs#{attribute}: " + f"{result.stderr.strip() or 'no output'}" + ) + store_paths.append(result.stdout.strip().splitlines()[-1]) + + lib_dirs = [str(Path(path) / "lib") for path in store_paths] + atomic_json( + cache_path, + {"packages": list(NIX_LIBRARY_PACKAGES), "libDirs": lib_dirs, "resolvedAt": int(time.time())}, + ) + return os.pathsep.join(lib_dirs) + + +def ensure_nixos_dynamic_linking(data_dir: Path) -> None: + """On NixOS, re-exec this interpreter with LD_LIBRARY_PATH patched so + pip-installed manylinux wheels can find libstdc++/libgomp/zlib. Every + subprocess spawned afterwards (venv creation, pip install, the runtime + readiness check, and the venv python that runs `generate`) inherits this + process's environment, so patching it once here is enough for the whole + plugin -- no changes to service.luau are needed.""" + if os.environ.get("_WALLPAPER_DEPTH_NIXOS_PATCHED") == "1": + return + if not is_nixos(): + return + lib_path = resolve_nix_library_path(data_dir) + existing = os.environ.get("LD_LIBRARY_PATH", "") + new_env = dict(os.environ) + new_env["LD_LIBRARY_PATH"] = f"{lib_path}{os.pathsep}{existing}" if existing else lib_path + new_env["_WALLPAPER_DEPTH_NIXOS_PATCHED"] = "1" + os.execve(sys.executable, [sys.executable] + sys.argv, new_env) + + +def runtime_python(data_dir: Path) -> Path: + return data_dir / "runtime" / ".venv" / "bin" / "python" + + +def model_path(data_dir: Path) -> Path: + return data_dir / "models" / "depth-anything-v2-small" / "model.onnx" + + +def verify_model(path: Path) -> bool: + return path.is_file() and path.stat().st_size == MODEL_SIZE and sha256_file(path) == MODEL_SHA256 + + +def runtime_ready(data_dir: Path) -> bool: + python = runtime_python(data_dir) + if not python.is_file(): + return False + result = subprocess.run( + [str(python), "-c", "import numpy, onnxruntime, PIL"], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=False, + ) + return result.returncode == 0 + + +def emit(value: dict[str, object]) -> None: + print(json.dumps(value, separators=(",", ":"), sort_keys=True), flush=True) + + +def download_model(destination: Path) -> None: + destination.parent.mkdir(parents=True, exist_ok=True) + temporary = destination.with_suffix(".onnx.part") + temporary.unlink(missing_ok=True) + request = urllib.request.Request(MODEL_URL, headers={"User-Agent": "Noctalia-Wallpaper-Depth/1.0"}) + try: + with urllib.request.urlopen(request, timeout=60) as response, temporary.open("wb") as stream: + while chunk := response.read(1024 * 1024): + stream.write(chunk) + if temporary.stat().st_size != MODEL_SIZE: + raise RuntimeError( + f"model size mismatch: expected {MODEL_SIZE} bytes, received {temporary.stat().st_size}" + ) + checksum = sha256_file(temporary) + if checksum != MODEL_SHA256: + raise RuntimeError(f"model checksum mismatch: expected {MODEL_SHA256}, received {checksum}") + os.replace(temporary, destination) + finally: + temporary.unlink(missing_ok=True) + + +def setup(data_dir: Path) -> None: + operation_path = data_dir / "setup-operation.json" + atomic_json( + operation_path, + {"state": "running", "startedAt": int(time.time()), "modelSize": MODEL_SIZE}, + ) + python_version = sys.version_info[:2] + if not PYTHON_MIN <= python_version <= PYTHON_MAX: + raise RuntimeError("Python 3.11 through 3.14 is required") + runtime_dir = data_dir / "runtime" + venv = runtime_dir / ".venv" + runtime_dir.mkdir(parents=True, exist_ok=True) + if not runtime_ready(data_dir): + subprocess.run( + [sys.executable, "-m", "venv", "--clear", str(venv)], + stdin=subprocess.DEVNULL, + check=True, + ) + subprocess.run( + [ + str(runtime_python(data_dir)), + "-m", + "pip", + "install", + "--disable-pip-version-check", + "--no-input", + "--only-binary=:all:", + *PACKAGES, + ], + stdin=subprocess.DEVNULL, + check=True, + ) + if not verify_model(model_path(data_dir)): + download_model(model_path(data_dir)) + if not runtime_ready(data_dir) or not verify_model(model_path(data_dir)): + raise RuntimeError("setup validation failed") + status = { + "ready": True, + "modelRevision": MODEL_REVISION, + "modelSha256": MODEL_SHA256, + "modelSize": MODEL_SIZE, + "packages": list(PACKAGES), + } + atomic_json(data_dir / "setup.json", status) + atomic_json( + operation_path, + { + "state": "ready", + "finishedAt": int(time.time()), + "modelRevision": MODEL_REVISION, + "modelSize": MODEL_SIZE, + }, + ) + emit(status) + + +def status(data_dir: Path) -> None: + model = model_path(data_dir) + emit( + { + "ready": runtime_ready(data_dir) and verify_model(model), + "runtimeReady": runtime_ready(data_dir), + "modelReady": verify_model(model), + "modelRevision": MODEL_REVISION, + "modelSize": MODEL_SIZE, + } + ) + + +def inference_size(source_width: int, source_height: int) -> tuple[int, int]: + scale = max(INPUT_SIZE / source_width, INPUT_SIZE / source_height) + width = max( + INPUT_SIZE, + round(source_width * scale / MODEL_PATCH_SIZE) * MODEL_PATCH_SIZE, + ) + height = max( + INPUT_SIZE, + round(source_height * scale / MODEL_PATCH_SIZE) * MODEL_PATCH_SIZE, + ) + return width, height + + +def smoothstep(values, low: float, high: float): + import numpy as np + + if high <= low: + return (values >= high).astype(np.float32) + scaled = np.clip((values - low) / (high - low), 0.0, 1.0) + return scaled * scaled * (3.0 - 2.0 * scaled) + + +def box_mean(values, radius: int): + import numpy as np + + padded = np.pad(values, ((radius, radius), (radius, radius)), mode="edge") + integral = np.pad(padded, ((1, 0), (1, 0)), mode="constant") + integral = np.cumsum(integral, axis=0, dtype=np.float64) + integral = np.cumsum(integral, axis=1, dtype=np.float64) + diameter = radius * 2 + 1 + total = ( + integral[diameter:, diameter:] + - integral[:-diameter, diameter:] + - integral[diameter:, :-diameter] + + integral[:-diameter, :-diameter] + ) + total *= 1.0 / (diameter * diameter) + return total.astype(np.float32) + + +def refine_depth(source_rgb, depth): + import numpy as np + from PIL import Image + + source_width, source_height = source_rgb.size + scale = min(1.0, REFINEMENT_MAX_DIMENSION / max(source_width, source_height)) + refinement_size = ( + max(1, round(source_width * scale)), + max(1, round(source_height * scale)), + ) + guide_image = source_rgb.convert("L") + if guide_image.size != refinement_size: + guide_image = guide_image.resize(refinement_size, Image.Resampling.LANCZOS) + guide = np.asarray(guide_image, dtype=np.float32) / np.float32(255.0) + coarse = np.asarray( + Image.fromarray(depth).resize(refinement_size, Image.Resampling.BICUBIC), + dtype=np.float32, + ) + + mean_guide = box_mean(guide, GUIDED_FILTER_RADIUS) + mean_depth = box_mean(coarse, GUIDED_FILTER_RADIUS) + correlation_guide = box_mean(guide * guide, GUIDED_FILTER_RADIUS) + correlation_cross = box_mean(guide * coarse, GUIDED_FILTER_RADIUS) + variance_guide = correlation_guide - mean_guide * mean_guide + covariance = correlation_cross - mean_guide * mean_depth + coefficient_a = covariance / (variance_guide + np.float32(GUIDED_FILTER_EPSILON)) + coefficient_b = mean_depth - coefficient_a * mean_guide + refined = np.clip( + box_mean(coefficient_a, GUIDED_FILTER_RADIUS) * guide + + box_mean(coefficient_b, GUIDED_FILTER_RADIUS), + 0.0, + 1.0, + ).astype(np.float32) + + if refinement_size != (source_width, source_height): + refined = np.asarray( + Image.fromarray(refined).resize((source_width, source_height), Image.Resampling.BICUBIC), + dtype=np.float32, + ) + return refined + + +def prune(directory: Path, maximum: int) -> None: + if not directory.is_dir(): + return + files = sorted( + (path for path in directory.iterdir() if path.is_file()), + key=lambda path: path.stat().st_mtime_ns, + reverse=True, + ) + for path in files[maximum:]: + path.unlink(missing_ok=True) + + +def generate(data_dir: Path, wallpaper: Path, threshold: float, feather: float) -> None: + import fcntl + import numpy as np + import onnxruntime as ort + from PIL import Image + + if not wallpaper.is_file(): + raise RuntimeError("wallpaper is missing or unreadable") + if not verify_model(model_path(data_dir)): + raise RuntimeError("model is missing or failed checksum validation; run setup again") + threshold = min(1.0, max(0.0, threshold)) + feather = min(0.5, max(0.0, feather)) + started = time.monotonic() + wallpaper_hash = sha256_file(wallpaper) + cache_key = ( + f"{wallpaper_hash}-{MODEL_SHA256[:16]}-d{DEPTH_PIPELINE_VERSION}-i{INPUT_SIZE}" + ) + depth_dir = data_dir / "cache" / "depth" + mask_dir = data_dir / "cache" / "masks" + depth_dir.mkdir(parents=True, exist_ok=True) + mask_dir.mkdir(parents=True, exist_ok=True) + depth_path = depth_dir / f"{cache_key}.npy" + mask_key = f"{cache_key}-v{MASK_PIPELINE_VERSION}-t{threshold:.4f}-f{feather:.4f}" + mask_path = mask_dir / f"{mask_key}.png" + lock_path = data_dir / "runtime" / "generate.lock" + lock_path.parent.mkdir(parents=True, exist_ok=True) + + with lock_path.open("w") as lock: + fcntl.flock(lock, fcntl.LOCK_EX) + cache_hit = depth_path.is_file() + with Image.open(wallpaper) as source: + source_rgb = source.convert("RGB") + source_width, source_height = source_rgb.size + if source_width <= 0 or source_height <= 0: + raise RuntimeError("wallpaper has invalid dimensions") + model_width, model_height = inference_size(source_width, source_height) + if cache_hit: + depth = np.load(depth_path, allow_pickle=False) + if depth.shape != (model_height, model_width): + depth_path.unlink(missing_ok=True) + cache_hit = False + if not cache_hit: + resized = source_rgb.resize((model_width, model_height), Image.Resampling.BICUBIC) + pixels = np.asarray(resized, dtype=np.float32) / np.float32(255.0) + pixels = (pixels - np.array([0.485, 0.456, 0.406], dtype=np.float32)) / np.array( + [0.229, 0.224, 0.225], dtype=np.float32 + ) + tensor = np.transpose(pixels, (2, 0, 1))[None, ...] + options = ort.SessionOptions() + options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL + session = ort.InferenceSession( + str(model_path(data_dir)), sess_options=options, providers=["CPUExecutionProvider"] + ) + input_name = session.get_inputs()[0].name + prediction = session.run(None, {input_name: tensor})[0] + depth = np.asarray(prediction, dtype=np.float32).squeeze() + if depth.shape != (model_height, model_width): + raise RuntimeError( + f"unexpected model output shape: {depth.shape}; " + f"expected {(model_height, model_width)}" + ) + minimum = float(np.min(depth)) + maximum = float(np.max(depth)) + if not np.isfinite(minimum) or not np.isfinite(maximum) or maximum <= minimum: + raise RuntimeError("model returned an invalid depth map") + depth = (depth - minimum) / (maximum - minimum) + with tempfile.NamedTemporaryFile("wb", dir=depth_dir, delete=False) as stream: + np.save(stream, depth, allow_pickle=False) + temporary_depth = Path(stream.name) + os.replace(temporary_depth, depth_path) + + if mask_path.is_file(): + with Image.open(mask_path) as cached_mask: + if cached_mask.size != (source_width, source_height): + mask_path.unlink(missing_ok=True) + if not mask_path.is_file(): + full_size_depth = refine_depth(source_rgb, depth) + half_feather = feather * 0.5 + alpha = smoothstep(full_size_depth, threshold - half_feather, threshold + half_feather) + alpha_image = Image.fromarray(np.rint(alpha * 255.0).astype(np.uint8)) + with tempfile.NamedTemporaryFile("wb", dir=mask_dir, delete=False) as stream: + alpha_image.save(stream, format="PNG", optimize=True) + temporary_mask = Path(stream.name) + os.replace(temporary_mask, mask_path) + + prune(depth_dir, 8) + prune(mask_dir, 32) + + emit( + { + "cacheHit": cache_hit, + "elapsedMs": round((time.monotonic() - started) * 1000), + "height": source_height, + "maskPath": str(mask_path), + "modelRevision": MODEL_REVISION, + "wallpaperPath": str(wallpaper), + "width": source_width, + } + ) + + +def clear_cache(data_dir: Path) -> None: + shutil.rmtree(data_dir / "cache", ignore_errors=True) + emit({"cleared": True}) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--data-dir", required=True, type=Path) + subparsers = parser.add_subparsers(dest="command", required=True) + subparsers.add_parser("setup") + subparsers.add_parser("status") + generate_parser = subparsers.add_parser("generate") + generate_parser.add_argument("--wallpaper", required=True, type=Path) + generate_parser.add_argument("--threshold", required=True, type=float) + generate_parser.add_argument("--feather", required=True, type=float) + subparsers.add_parser("clear-cache") + return parser.parse_args() + + +def main() -> int: + args = parse_args() + data_dir = args.data_dir.expanduser().resolve() + try: + ensure_nixos_dynamic_linking(data_dir) + if args.command == "setup": + setup(data_dir) + elif args.command == "status": + status(data_dir) + elif args.command == "generate": + generate(data_dir, args.wallpaper.expanduser().resolve(), args.threshold, args.feather) + elif args.command == "clear-cache": + clear_cache(data_dir) + return 0 + except Exception as error: # Keep the Luau-facing failure one line and actionable. + if args.command == "setup": + atomic_json( + data_dir / "setup-operation.json", + {"state": "error", "finishedAt": int(time.time()), "message": str(error)}, + ) + print(str(error), file=sys.stderr, flush=True) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/wallpaper_depth_large/panel.luau b/wallpaper_depth_large/panel.luau new file mode 100644 index 0000000..b9ca080 --- /dev/null +++ b/wallpaper_depth_large/panel.luau @@ -0,0 +1,232 @@ +--!nonstrict + +local status = { + setupState = "checking", + setupMessage = "", + busy = true, + outputs = {}, +} + +local function tr(key, params) + return noctalia.tr(key, params) +end + +local function outputState(row) + if row.state == "ready" then + local detail = tr("panel.output.ready") + if type(row.elapsedMs) == "number" then + detail = tr("panel.output.ready_time", { seconds = string.format("%.1f", row.elapsedMs / 1000) }) + end + if row.cacheHit == true then + detail = detail .. " ยท " .. tr("panel.output.cached") + end + return "check", "primary", detail + elseif row.state == "processing" then + return "loader-2", "primary", tr("panel.output.processing") + elseif row.state == "waiting" then + return "hourglass", "on_surface_variant", tr("panel.output.waiting") + elseif row.state == "error" then + return "alert-triangle", "error", row.message or tr("panel.output.error") + end + return "photo-off", "on_surface_variant", tr("panel.output.no_wallpaper") +end + +local function outputRows() + local rows = {} + for _, row in ipairs(status.outputs or {}) do + local glyph, color, detail = outputState(row) + table.insert(rows, ui.row({ + gap = 10, + align = "center", + padding = 10, + radius = 8, + fill = "surface_variant/0.35", + }, { + ui.glyph({ name = glyph, size = 18, color = color }), + ui.column({ gap = 2, flexGrow = 1 }, { + ui.label({ text = row.name or "", fontWeight = "bold", fontSize = 13 }), + ui.label({ text = detail, color = color, fontSize = 11, wrap = true }), + }), + })) + end + if #rows == 0 then + table.insert(rows, ui.label({ + text = tr("panel.no_outputs"), + color = "on_surface_variant", + fontSize = 12, + })) + end + return rows +end + +local function setupCard() + local state = status.setupState or "checking" + local glyph = "loader-2" + local color = "on_surface_variant" + local title = tr("panel.setup.checking") + if state == "ready" then + glyph = "circle-check" + color = "primary" + title = tr("panel.setup.ready") + elseif state == "running" then + glyph = "download" + color = "primary" + title = tr("panel.setup.running") + elseif state == "missing" then + glyph = "package" + title = tr("panel.setup.missing") + elseif state == "error" then + glyph = "alert-triangle" + color = "error" + title = tr("panel.setup.error") + end + + local children = { + ui.row({ gap = 10, align = "center" }, { + ui.glyph({ name = glyph, size = 20, color = color }), + ui.column({ gap = 2, flexGrow = 1 }, { + ui.label({ text = title, fontWeight = "bold", fontSize = 13 }), + ui.label({ + text = status.setupMessage or "", + color = color, + fontSize = 11, + wrap = true, + visible = type(status.setupMessage) == "string" and status.setupMessage ~= "", + }), + }), + }), + } + + if state ~= "ready" then + local prerequisites = {} + if status.pythonAvailable ~= true then + table.insert(prerequisites, "python3") + end + if #prerequisites > 0 then + table.insert(children, ui.label({ + text = tr("panel.setup.prerequisites", { commands = table.concat(prerequisites, ", ") }), + color = "error", + fontSize = 11, + wrap = true, + })) + end + if status.offline == true then + table.insert(children, ui.label({ + text = tr("panel.setup.offline"), + color = "error", + fontSize = 11, + wrap = true, + })) + end + table.insert(children, ui.label({ + text = tr("panel.setup.disclosure"), + color = "on_surface_variant", + fontSize = 11, + wrap = true, + })) + table.insert(children, ui.button({ + text = state == "error" and tr("panel.setup.retry") or tr("panel.setup.install"), + glyph = "download", + variant = "primary", + enabled = state ~= "running" + and status.offline ~= true + and status.pythonAvailable == true + and status.busy ~= true, + onClick = "onSetup", + })) + end + + return ui.column({ gap = 8, padding = 10, radius = 8, fill = "surface_variant/0.35" }, children) +end + +local function render() + local ready = status.setupState == "ready" + local threshold = math.floor((status.threshold or 0) * 100 + 0.5) + local feather = math.floor((status.feather or 0) * 100 + 0.5) + panel.render(ui.column({ flexGrow = 1, gap = 10, padding = 10 }, { + ui.row({ align = "center", gap = 8 }, { + ui.glyph({ name = "layers-subtract", size = 20, color = "primary" }), + ui.label({ text = tr("title"), fontSize = 16, fontWeight = "bold", flexGrow = 1 }), + ui.button({ glyph = "close", variant = "ghost", onClick = function() + panel.close() + end }), + }), + ui.label({ + text = tr("panel.description"), + color = "on_surface_variant", + fontSize = 12, + wrap = true, + }), + setupCard(), + ui.row({ align = "center", justify = "space_between" }, { + ui.label({ text = tr("panel.parameters"), fontWeight = "bold", fontSize = 13 }), + ui.button({ text = tr("panel.settings"), glyph = "settings", variant = "ghost", onClick = "onSettings" }), + }), + ui.row({ gap = 12, paddingH = 4 }, { + ui.column({ gap = 1, flexGrow = 1 }, { + ui.label({ text = tr("panel.threshold"), color = "on_surface_variant", fontSize = 11 }), + ui.label({ text = tostring(threshold) .. "%", fontWeight = "bold", fontSize = 13 }), + }), + ui.column({ gap = 1, flexGrow = 1 }, { + ui.label({ text = tr("panel.feather"), color = "on_surface_variant", fontSize = 11 }), + ui.label({ text = tostring(feather) .. "%", fontWeight = "bold", fontSize = 13 }), + }), + ui.column({ gap = 1, flexGrow = 1 }, { + ui.label({ text = tr("panel.automatic"), color = "on_surface_variant", fontSize = 11 }), + ui.label({ + text = status.autoGenerate == true and tr("panel.on") or tr("panel.off"), + fontWeight = "bold", + fontSize = 13, + }), + }), + }), + ui.separator({}), + ui.label({ text = tr("panel.outputs"), fontWeight = "bold", fontSize = 13 }), + ui.scroll({ flexGrow = 1, gap = 6 }, outputRows()), + ui.row({ gap = 8 }, { + ui.button({ + text = tr("panel.generate"), + glyph = "sparkles", + variant = "primary", + flexGrow = 1, + enabled = ready and status.busy ~= true, + onClick = "onGenerate", + }), + ui.button({ + text = tr("panel.clear_cache"), + glyph = "trash", + variant = "outline", + enabled = status.busy ~= true, + onClick = "onClearCache", + }), + }), + })) +end + +function onSetup() + noctalia.state.set("wallpaper_depth.command", { action = "setup" }) +end + +function onGenerate() + noctalia.state.set("wallpaper_depth.command", { action = "generate" }) +end + +function onClearCache() + noctalia.state.set("wallpaper_depth.command", { action = "clear_cache" }) +end + +function onSettings() + noctalia.openSettings() +end + +function onOpen(_context) + status = noctalia.state.get("wallpaper_depth.status") or status + render() +end + +noctalia.state.watch("wallpaper_depth.status", function(value) + if type(value) == "table" then + status = value + render() + end +end) diff --git a/wallpaper_depth_large/plugin.toml b/wallpaper_depth_large/plugin.toml new file mode 100644 index 0000000..82e2034 --- /dev/null +++ b/wallpaper_depth_large/plugin.toml @@ -0,0 +1,49 @@ +id = "noctalia/wallpaper_depth" +name = "Wallpaper Depth" +version = "1.0.2" +plugin_api = 26 +author = "noctalia" +license = "MIT" +dependencies = ["python3"] +tags = ["wallpaper", "desktop", "ai"] +icon = "layers-subtract" +description = "Generate depth masks that place desktop widgets behind wallpaper foregrounds." + +[[setting]] +key = "auto_generate" +type = "bool" +label_key = "settings.auto_generate.label" +description_key = "settings.auto_generate.description" +default = true + +[[setting]] +key = "threshold" +type = "int" +label_key = "settings.threshold.label" +description_key = "settings.threshold.description" +default = 50 +min = 0 +max = 100 +step = 1 + +[[setting]] +key = "feather" +type = "int" +label_key = "settings.feather.label" +description_key = "settings.feather.description" +default = 8 +min = 0 +max = 50 +step = 1 + +[[service]] +id = "service" +entry = "service.luau" + +[[panel]] +id = "manager" +entry = "panel.luau" +width = 500 +height = 660 +placement = "attached" +position = "auto" diff --git a/wallpaper_depth_large/service.luau b/wallpaper_depth_large/service.luau new file mode 100644 index 0000000..90af403 --- /dev/null +++ b/wallpaper_depth_large/service.luau @@ -0,0 +1,491 @@ +--!nonstrict + +noctalia.setUpdateInterval(1000) + +local MODEL_SIZE = 99060839 +local helperPath = noctalia.pluginDir() .. "/depth_helper.py" +local dataDir = noctalia.pluginDataDir() +if dataDir == nil then + error("Wallpaper Depth requires a plugin data directory") +end +local operationPath = dataDir .. "/setup-operation.json" +local runtimePython = dataDir .. "/runtime/.venv/bin/python" + +local setupState = "checking" +local setupMessage = "" +local activeJob = nil +local cacheOperation = false +local pending = {} +local queued = {} +local outputs = {} +local lastParametersKey = nil +local lastAutoGenerate = nil +local pythonAvailable = noctalia.commandExists("python3") + +local function decodeObject(raw) + if type(raw) ~= "string" or raw == "" then + return nil + end + local value = noctalia.json.decode(raw) + if type(value) ~= "table" then + return nil + end + return value +end + +local function shortError(result, fallback) + local message = "" + if type(result) == "table" then + message = noctalia.string.trim(result.stderr or "") + if message == "" then + message = noctalia.string.trim(result.stdout or "") + end + end + if message == "" then + message = fallback + end + if #message > 300 then + message = string.sub(message, 1, 297) .. "..." + end + return message +end + +local function parameters() + local threshold = noctalia.getConfig("threshold") + local feather = noctalia.getConfig("feather") + local autoGenerate = noctalia.getConfig("auto_generate") + if type(threshold) ~= "number" or type(feather) ~= "number" or type(autoGenerate) ~= "boolean" then + return nil, noctalia.tr("service.invalid_settings") + end + threshold = math.max(0, math.min(100, threshold)) / 100 + feather = math.max(0, math.min(50, feather)) / 100 + return { + threshold = threshold, + feather = feather, + autoGenerate = autoGenerate, + key = string.format("%.4f:%.4f", threshold, feather), + }, nil +end + +local function publish() + local rows = {} + for _, row in pairs(outputs) do + table.insert(rows, { + name = row.name, + wallpaperPath = row.wallpaperPath, + state = row.state, + message = row.message, + cacheHit = row.cacheHit, + elapsedMs = row.elapsedMs, + }) + end + table.sort(rows, function(left, right) + return left.name < right.name + end) + local params, parameterError = parameters() + noctalia.state.set("wallpaper_depth.status", { + setupState = setupState, + setupMessage = setupMessage ~= "" and setupMessage or parameterError, + busy = setupState == "running" or activeJob ~= nil or cacheOperation, + offline = noctalia.getSetting("shell.offline_mode"), + pythonAvailable = pythonAvailable, + modelSize = MODEL_SIZE, + threshold = params ~= nil and params.threshold or 0, + feather = params ~= nil and params.feather or 0, + autoGenerate = params ~= nil and params.autoGenerate or false, + outputs = rows, + }) +end + +local function setSetupState(state, message) + setupState = state + setupMessage = message or "" + publish() +end + +local function readOperation() + return decodeObject(noctalia.readFile(operationPath)) +end + +local function enqueue(outputName, wallpaperPath, params) + if setupState ~= "ready" or type(wallpaperPath) ~= "string" or wallpaperPath == "" then + return + end + local key = wallpaperPath .. "\n" .. params.key + if queued[outputName] == key then + return + end + if activeJob ~= nil and activeJob.outputName == outputName and activeJob.key == key then + return + end + queued[outputName] = key + table.insert(pending, { + outputName = outputName, + wallpaperPath = wallpaperPath, + threshold = params.threshold, + feather = params.feather, + parametersKey = params.key, + key = key, + }) +end + +local runNext + +runNext = function() + if activeJob ~= nil or cacheOperation or setupState ~= "ready" then + return + end + local params = parameters() + if params == nil then + return + end + + local job = nil + while #pending > 0 do + local candidate = table.remove(pending, 1) + queued[candidate.outputName] = nil + local currentPath = noctalia.wallpaperPath(candidate.outputName) + if currentPath == candidate.wallpaperPath and candidate.parametersKey == params.key then + job = candidate + break + end + end + if job == nil then + publish() + return + end + + activeJob = job + local row = outputs[job.outputName] + if row ~= nil then + row.state = "processing" + row.message = "" + row.cacheHit = nil + row.elapsedMs = nil + end + publish() + + local accepted = noctalia.runAsync({ + runtimePython, + helperPath, + "--data-dir", + dataDir, + "generate", + "--wallpaper", + job.wallpaperPath, + "--threshold", + tostring(job.threshold), + "--feather", + tostring(job.feather), + }, function(result) + local completedJob = activeJob + activeJob = nil + if completedJob == nil then + runNext() + return + end + + local currentParameters = parameters() + local currentPath = noctalia.wallpaperPath(completedJob.outputName) + local currentRow = outputs[completedJob.outputName] + local stale = currentParameters == nil + or currentParameters.key ~= completedJob.parametersKey + or currentPath ~= completedJob.wallpaperPath + if stale then + if currentRow ~= nil then + currentRow.state = currentPath ~= nil and "waiting" or "no_wallpaper" + end + if currentParameters ~= nil and currentPath ~= nil then + enqueue(completedJob.outputName, currentPath, currentParameters) + end + publish() + runNext() + return + end + + if result.exitCode ~= 0 or result.timedOut then + noctalia.setWallpaperMask(completedJob.outputName, nil) + if currentRow ~= nil then + currentRow.state = "error" + currentRow.message = shortError(result, noctalia.tr("service.generation_failed")) + end + else + local generated = decodeObject(result.stdout) + if generated == nil + or type(generated.maskPath) ~= "string" + or generated.maskPath == "" + or generated.wallpaperPath ~= completedJob.wallpaperPath + then + noctalia.setWallpaperMask(completedJob.outputName, nil) + if currentRow ~= nil then + currentRow.state = "error" + currentRow.message = noctalia.tr("service.invalid_result") + end + else + noctalia.setWallpaperMask(completedJob.outputName, { + path = generated.maskPath, + wallpaperPath = completedJob.wallpaperPath, + }) + if currentRow ~= nil then + currentRow.state = "ready" + currentRow.message = "" + currentRow.cacheHit = generated.cacheHit == true + currentRow.elapsedMs = tonumber(generated.elapsedMs) + end + end + end + publish() + runNext() + end, 60000) + + if not accepted then + activeJob = nil + noctalia.setWallpaperMask(job.outputName, nil) + if row ~= nil then + row.state = "error" + row.message = noctalia.tr("service.start_helper_failed") + end + publish() + runNext() + end +end + +local function enqueueAll(force) + local params, parameterError = parameters() + if params == nil then + setSetupState(setupState, parameterError) + return + end + for outputName, row in pairs(outputs) do + if type(row.wallpaperPath) == "string" and row.wallpaperPath ~= "" then + if force then + noctalia.setWallpaperMask(outputName, nil) + row.state = "waiting" + row.message = "" + end + enqueue(outputName, row.wallpaperPath, params) + end + end + publish() + runNext() +end + +local function verifySetup() + if not pythonAvailable then + setSetupState("missing", noctalia.tr("service.python_missing")) + return + end + setSetupState("checking", "") + local accepted = noctalia.runAsync({ + "python3", + helperPath, + "--data-dir", + dataDir, + "status", + }, function(result) + if result.exitCode ~= 0 or result.timedOut then + setSetupState("missing", shortError(result, noctalia.tr("service.validation_failed"))) + return + end + local value = decodeObject(result.stdout) + if value ~= nil and value.ready == true then + setSetupState("ready", "") + enqueueAll(false) + else + setSetupState("missing", noctalia.tr("service.setup_missing")) + end + end, 60000) + if not accepted then + setSetupState("error", noctalia.tr("service.start_validation_failed")) + end +end + +local function startSetup() + if noctalia.getSetting("shell.offline_mode") then + setSetupState("error", noctalia.tr("service.offline")) + return + end + if not pythonAvailable then + setSetupState("error", noctalia.tr("service.python_missing")) + return + end + if activeJob ~= nil or cacheOperation then + setSetupState("error", noctalia.tr("service.busy")) + return + end + + noctalia.writeFile(operationPath, '{"state":"starting"}\n') + setSetupState("running", noctalia.tr("service.setup_running")) + local accepted = noctalia.runAsync({ + "python3", + helperPath, + "--data-dir", + dataDir, + "setup", + }) + if not accepted then + setSetupState("error", noctalia.tr("service.start_setup_failed")) + end +end + +local function pollSetup() + if setupState ~= "running" then + return + end + local operation = readOperation() + if operation == nil or operation.state == "starting" or operation.state == "running" then + return + end + if operation.state == "ready" then + verifySetup() + elseif operation.state == "error" then + setSetupState( + "error", type(operation.message) == "string" and operation.message or noctalia.tr("service.setup_failed") + ) + end +end + +local function clearCache() + if activeJob ~= nil or cacheOperation or setupState == "running" then + return + end + cacheOperation = true + pending = {} + queued = {} + for outputName, row in pairs(outputs) do + noctalia.setWallpaperMask(outputName, nil) + row.state = row.wallpaperPath ~= nil and "waiting" or "no_wallpaper" + row.message = "" + end + publish() + local accepted = noctalia.runAsync({ + "python3", + helperPath, + "--data-dir", + dataDir, + "clear-cache", + }, function(result) + cacheOperation = false + if result.exitCode ~= 0 or result.timedOut then + setupMessage = shortError(result, noctalia.tr("service.clear_cache_failed")) + else + setupMessage = "" + end + publish() + local params = parameters() + if params ~= nil and params.autoGenerate then + enqueueAll(false) + end + end, 60000) + if not accepted then + cacheOperation = false + setupMessage = noctalia.tr("service.start_clear_cache_failed") + publish() + end +end + +local function syncOutputs() + local params, parameterError = parameters() + if params == nil then + setupMessage = parameterError + publish() + return + end + local current = {} + for _, output in ipairs(noctalia.outputs()) do + current[output.name] = true + local wallpaperPath = noctalia.wallpaperPath(output.name) + if wallpaperPath ~= nil and not noctalia.fileExists(wallpaperPath) then + wallpaperPath = nil + end + local row = outputs[output.name] + if row == nil then + row = { name = output.name, state = "no_wallpaper", message = "" } + outputs[output.name] = row + end + if row.wallpaperPath ~= wallpaperPath then + noctalia.setWallpaperMask(output.name, nil) + row.wallpaperPath = wallpaperPath + row.state = wallpaperPath ~= nil and "waiting" or "no_wallpaper" + row.message = "" + row.cacheHit = nil + row.elapsedMs = nil + queued[output.name] = nil + if params.autoGenerate and wallpaperPath ~= nil then + enqueue(output.name, wallpaperPath, params) + end + end + end + for outputName, _ in pairs(outputs) do + if current[outputName] ~= true then + outputs[outputName] = nil + queued[outputName] = nil + end + end + + if lastParametersKey ~= nil and lastParametersKey ~= params.key then + for outputName, row in pairs(outputs) do + noctalia.setWallpaperMask(outputName, nil) + row.state = row.wallpaperPath ~= nil and "waiting" or "no_wallpaper" + row.message = "" + end + pending = {} + queued = {} + if params.autoGenerate then + enqueueAll(false) + end + end + if lastAutoGenerate == false and params.autoGenerate then + for outputName, row in pairs(outputs) do + if row.state == "waiting" and row.wallpaperPath ~= nil then + enqueue(outputName, row.wallpaperPath, params) + end + end + end + lastParametersKey = params.key + lastAutoGenerate = params.autoGenerate + publish() + runNext() +end + +noctalia.state.watch("wallpaper_depth.command", function(command) + if type(command) ~= "table" then + return + end + noctalia.state.set("wallpaper_depth.command", nil) + if command.action == "setup" then + startSetup() + elseif command.action == "generate" then + enqueueAll(true) + elseif command.action == "clear_cache" then + clearCache() + end +end) + +function onIpc(event, _payload) + if event == "setup" then + startSetup() + elseif event == "generate" then + enqueueAll(true) + elseif event == "clear-cache" then + clearCache() + end +end + +function onConfigChanged() + syncOutputs() +end + +function update() + pollSetup() + syncOutputs() +end + +local operation = readOperation() +if operation ~= nil and (operation.state == "running" or operation.state == "starting") then + setupState = "running" + setupMessage = noctalia.tr("service.setup_running") +else + verifySetup() +end +syncOutputs() diff --git a/wallpaper_depth_large/thumbnail.webp b/wallpaper_depth_large/thumbnail.webp new file mode 100644 index 0000000000000000000000000000000000000000..b0db42ea02bb77ac4c3c437f27f5eb95bb87c8d6 GIT binary patch literal 77234 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

n!7elOBY6s6XluWwOz2Z3H3 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 Date: Sun, 23 Aug 2026 20:16:31 +0300 Subject: [PATCH 3/8] Update depth_helper.py --- wallpaper_depth_large/depth_helper.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wallpaper_depth_large/depth_helper.py b/wallpaper_depth_large/depth_helper.py index 511c261..055f0c3 100755 --- a/wallpaper_depth_large/depth_helper.py +++ b/wallpaper_depth_large/depth_helper.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Bootstrap Depth Anything V2 Small and generate source-aligned wallpaper masks.""" +"""Bootstrap Depth Anything V2 Large and generate source-aligned wallpaper masks.""" from __future__ import annotations @@ -15,13 +15,13 @@ import time import urllib.request -MODEL_REVISION = "4472b7362082ad9968fee890ca0f1e5aca36b93d" +MODEL_REVISION = "0306443f3d6bd5eab8723897d5201f2c8aac95de" MODEL_URL = ( - "https://huggingface.co/onnx-community/depth-anything-v2-small/resolve/" + "https://huggingface.co/onnx-community/depth-anything-v2-large/resolve/" f"{MODEL_REVISION}/onnx/model.onnx?download=true" ) -MODEL_SHA256 = "afb6a5c28f3b6bf1618c6e43f02073ef9dfdc70e937502d51603e57b0a1df10c" -MODEL_SIZE = 99_060_839 +MODEL_SHA256 = "a93aa89b5e92e30e0afbe0f7c3ec692b35cfca791ae9004a190fb0ca2010e905" +MODEL_SIZE = 1_336_922_232 INPUT_SIZE = 518 MODEL_PATCH_SIZE = 14 DEPTH_PIPELINE_VERSION = 2 @@ -149,7 +149,7 @@ def runtime_python(data_dir: Path) -> Path: def model_path(data_dir: Path) -> Path: - return data_dir / "models" / "depth-anything-v2-small" / "model.onnx" + return data_dir / "models" / "depth-anything-v2-large" / "model.onnx" def verify_model(path: Path) -> bool: From fd0d52e03e9ffbcca9c994640a0e430e761b89c1 Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:18:24 +0300 Subject: [PATCH 4/8] Update service.luau --- wallpaper_depth_large/service.luau | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wallpaper_depth_large/service.luau b/wallpaper_depth_large/service.luau index 90af403..879cf0a 100644 --- a/wallpaper_depth_large/service.luau +++ b/wallpaper_depth_large/service.luau @@ -2,7 +2,7 @@ noctalia.setUpdateInterval(1000) -local MODEL_SIZE = 99060839 +local MODEL_SIZE = 1336922232 local helperPath = noctalia.pluginDir() .. "/depth_helper.py" local dataDir = noctalia.pluginDataDir() if dataDir == nil then From b2083a2328a88834f65fdf64c6bae85c5b003de0 Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:19:11 +0300 Subject: [PATCH 5/8] Update plugin.toml --- wallpaper_depth_large/plugin.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wallpaper_depth_large/plugin.toml b/wallpaper_depth_large/plugin.toml index 82e2034..448acdf 100644 --- a/wallpaper_depth_large/plugin.toml +++ b/wallpaper_depth_large/plugin.toml @@ -1,5 +1,5 @@ -id = "noctalia/wallpaper_depth" -name = "Wallpaper Depth" +id = "noctalia/wallpaper_depth_large" +name = "Wallpaper Depth Large" version = "1.0.2" plugin_api = 26 author = "noctalia" @@ -7,7 +7,7 @@ license = "MIT" dependencies = ["python3"] tags = ["wallpaper", "desktop", "ai"] icon = "layers-subtract" -description = "Generate depth masks that place desktop widgets behind wallpaper foregrounds." +description = "Generate depth masks that place desktop widgets behind wallpaper foregrounds. Uses the large model for better results." [[setting]] key = "auto_generate" From ae1177762081766122d348c8a1d966187135fa6f Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:23:02 +0300 Subject: [PATCH 6/8] Update catalog.toml --- catalog.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/catalog.toml b/catalog.toml index bf61869..302fbb3 100644 --- a/catalog.toml +++ b/catalog.toml @@ -199,3 +199,16 @@ plugin_api = 25 version = "1.0.0" updated_at = 1786549052 rev = "4933b1c459459af3a0f9d14898b76ce0564d43b3" + +[[plugin]] +id = "noctalia/wallpaper_depth_large" +name = "Wallpaper Depth" +version = "1.0.2" +updated_at = 1786565714 +added_at = 1786549052 +author = "noctalia" +license = "MIT" +icon = "layers-subtract" +description = "Generate depth masks that place desktop widgets behind wallpaper foregrounds. Uses the larger model for better results." +plugin_api = 26 +tags = ["wallpaper", "desktop", "ai"] From ff071896393f980f5d620e9ee07458de565728b4 Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:32:14 +0300 Subject: [PATCH 7/8] Update catalog.toml --- catalog.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalog.toml b/catalog.toml index 302fbb3..4f2caf2 100644 --- a/catalog.toml +++ b/catalog.toml @@ -202,7 +202,7 @@ rev = "4933b1c459459af3a0f9d14898b76ce0564d43b3" [[plugin]] id = "noctalia/wallpaper_depth_large" -name = "Wallpaper Depth" +name = "Wallpaper Depth Large" version = "1.0.2" updated_at = 1786565714 added_at = 1786549052 From fc8e13eba937ab1a2b50ddc9d4cb2e0951f5f890 Mon Sep 17 00:00:00 2001 From: portanz <116716060+portanz@users.noreply.github.com> Date: Sun, 23 Aug 2026 20:34:00 +0300 Subject: [PATCH 8/8] Update README.md --- wallpaper_depth_large/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wallpaper_depth_large/README.md b/wallpaper_depth_large/README.md index 56b575d..77ec5d6 100644 --- a/wallpaper_depth_large/README.md +++ b/wallpaper_depth_large/README.md @@ -11,7 +11,7 @@ Wallpapers are never uploaded. | Field | Value | | --- | --- | -| ID | `noctalia/wallpaper_depth` | +| ID | `noctalia/wallpaper_depth_large` | | Entries | Service: `service`; panel: `manager` | ## Requirements @@ -30,7 +30,7 @@ environment. 1. Open the **Wallpaper Depth** panel, or toggle it from a terminal: ```sh - noctalia msg panel-toggle noctalia/wallpaper_depth:manager + noctalia msg panel-toggle noctalia/wallpaper_depth_large:manager ``` 2. Select **Install model** and wait for setup to finish.