receta: photosuite (eolix) — el control independiente de que egui+wgpu entra; + el triaje de moli, zed, niri, rio, typst, jj, lapce y servo
Semantic delta
No definition changed: this change is text, documentation or data.
2 files · +131 −0
- docs/plan-apps-usuario-final.md +31 −0
- recipes/photosuite.toml +100 −0
diff --git a/docs/plan-apps-usuario-final.md b/docs/plan-apps-usuario-final.md
index 0029630a..28111847 100644
--- a/docs/plan-apps-usuario-final.md
+++ b/docs/plan-apps-usuario-final.md
@@ -541,3 +541,34 @@ el `cargo vendor` de takana le pisó su propio `vendor/`** (cuatro crates `hayro
`[patch.crates-io]` POR RUTA). El error hablaba de un `.cargo-checksum.json` que faltaba. Se arregla
con `cargo_vendor_dir`, igual que `boveda` y `mise`; `vectorcraft` committea un `vendor/` también y
lo lleva ahora de forma preventiva.
+
+## El CONTROL de todo esto: `photosuite`, de otra gente
+
+`eolix/photosuite` (1.110★, Apache-2.0, `v0.9.20`, 687 crates) hace lo mismo que `photocraft` con la
+misma cadena —**eframe/egui 0.36 + wgpu**— y lo hace **otro equipo**. Selló en una pasada
+(`b3:a4d43550`, hash predicho por el hub y confirmado por el worker) y **pinta**: 2.837 colores,
+`app_id` `io.github.eolix.PhotoSuite`. Importa porque convierte la frase «egui+wgpu entra en esta
+distro» de anécdota en medición: dos implementaciones independientes, el mismo resultado.
+
+Y gana donde las doce pierden: trae `arboard` con `wayland-data-control` ⇒ **sí tiene portapapeles**,
+y `winit` con `wayland-csd-adwaita` ⇒ dibuja sus propias decoraciones donde el compositor no las pone.
+O sea que el hueco del portapapeles **no es del toolkit**: es una línea del manifiesto de cada app.
+
+## Lo que NO entra, y por qué — para no volver a triarlo
+
+- **`lexmount/moli`** (17.791★, navegador headless para agentes, ~100 crates propios de DOM/layout/
+ paint): usa `v8` (`rusty_v8`), y su `build.rs` **se baja binarios en los DOS caminos** — el default
+ `download_static_lib_binaries()` y, con `V8_FROM_SOURCE=1`, su propio gn, ninja, clang y Rust. Sin
+ red en el sandbox y con «reproducir, no confiar» como premisa, eso es una contradicción, no una
+ dificultad. ⇒ **campaña de `v8`, no receta.**
+- **`zed`**: GPUI exige **Vulkan 1.3** en Linux. Desbloqueo: lavapipe.
+- **`niri`**: arrastra gtk4+libadwaita y compite con el compositor propio (smithay).
+- **`rio`**: redundante con `foot`, ya sellado y en los perfiles.
+
+**Lo que sí entraría y está medido, en orden:** `typst` (56.592★, Apache-2.0, 435 crates, CLI pura,
+y su `fontconfig-parser` es un parser en Rust, no la libfontconfig de C ⇒ cero deps C de tipografía),
+`jj` (32.018★, 53 crates `gix-*` ⇒ git en Rust puro sin `libgit2`) y `lapce` (38.918★, floem+wgpu, el
+editor gráfico que zed no puede ser acá; `openssl`/`zlib`/`zstd` ya tienen receta).
+**`servo`** es la única que cambiaría algo estructural: usa `mozjs_sys` —SpiderMonkey, que esta casa
+**ya construye desde fuente** dentro de firefox— así que, a diferencia de moli, no choca con la
+premisa. Sigue siendo campaña (1.148 crates), no receta de una tarde.
diff --git a/recipes/photosuite.toml b/recipes/photosuite.toml
new file mode 100644
index 00000000..4fded922
--- /dev/null
+++ b/recipes/photosuite.toml
@@ -0,0 +1,100 @@
+# photosuite — el OTRO editor de imágenes de esta ola, y el CONTROL de la suite ArtCraft
+#
+# ── POR QUÉ ENTRA, SI YA ESTÁ `photocraft` ─────────────────────────────────────────────────────
+# Porque es de otra gente (`github.com/eolix/photosuite`, 1.110★) y hace lo mismo con la misma
+# cadena: **Rust puro sobre eframe/egui 0.36 + wgpu**, MIT OR Apache-2.0, 687 crates. Tener dos
+# implementaciones independientes de la misma función sobre el mismo toolkit es lo que vuelve
+# medible la frase «egui+wgpu entra en esta distro»: si las dos pintan, no fue suerte de un repo.
+# Su diferencia declarada es la compatibilidad **PSD/PSB nativa** y un `.desktop` que registra
+# dieciocho tipos MIME de imagen.
+#
+# Triada el 2026-10-13 con el método de la adenda de `docs/plan-apps-usuario-final.md`, que es
+# mirar los `[target.…]` y no sólo el lock:
+# · `gtk`/`gtk-sys`/`gdk-sys`/`atk-sys`/`pango-sys` **están en el lock y NO se compilan**: entran
+# por `muda`, que vive bajo `cfg(target_os = "macos")`. Idéntico a `photocraft` y `filmcraft`.
+# · en Linux sus únicas deps propias son `x11rb` (protocolo X en Rust puro) y `rfd`.
+# · **`cc` aparece pero no es suyo**: viene de `blake3`, `wayland-backend` y `android-activity`.
+# · sin `cpal` ⇒ sin ALSA, a diferencia de deck/sound/effect/filmcraft.
+# · no committea `vendor/` ni usa `[patch.crates-io]` ⇒ el vendoreo va al `vendor/` por defecto
+# (la trampa que mató a `pdfcraft` no aplica acá; comprobado en el árbol del tag).
+#
+# ⚠ **Y trae DOS cosas que las doce de ArtCraft no tienen, las dos medidas en su manifiesto:**
+# 1. `arboard` con `wayland-data-control` ⇒ **sí tiene portapapeles** en esta distro, donde ocho
+# de las doce hermanas lo pierden en silencio.
+# 2. `winit` con `wayland-csd-adwaita` ⇒ dibuja sus propias decoraciones donde el compositor no
+# las pone (GNOME). Sin eso, una ventana egui en GNOME sale sin barra de título.
+#
+# ── LA FORMA ───────────────────────────────────────────────────────────────────────────────────
+# La misma que las doce: `link = "dynamic"` + `-crt-static` (winit/wgpu cargan wayland y EGL por
+# `dlopen`), lanzador e iconos de upstream, y el `app_id` del `with_app_id()` coincide con el
+# basename del `.desktop` y con su `StartupWMClass` (`io.github.eolix.PhotoSuite`).
+# ⚠ Lo que NO se instala es `packaging/linux/io.github.eolix.PhotoSuite.metainfo.xml.in`: es una
+# PLANTILLA (`.in`) que el empaquetador de upstream sustituye. Instalarla cruda dejaría un
+# AppStream con marcadores sin resolver, que es peor que no tenerlo. Y no hay `.mime.xml` separado:
+# los tipos van dentro del `.desktop`.
+name = "photosuite"
+version = "0.9.20"
+license = "MIT OR Apache-2.0"
+
+[source]
+# `v0.9.20`, el tag vigente al 2026-10-13. Se pinea el SHA: un tag se mueve.
+repo = "https://github.com/eolix/photosuite"
+commit = "c60705fc71d550ef34aa9c52c36cbb884f3a93a8"
+# El `Cargo.lock` está committeado ⇒ el vendoreo va con `--locked` y queda pineado en el tiempo.
+# ⚠ `vendor_cargo_deps` sobrescribe `<src>/.cargo/config.toml` (`fetch.rs:852`) y este repo trae
+# uno propio: hoy es inocuo, pero si un bump mete ahí un `rustflags` o un `linker`, desaparece sin
+# aviso. Mirarlo en cada subida de pin.
+
+[build]
+compiler = "zig-cc"
+target = "x86_64-linux-musl"
+link = "dynamic"
+flags = ["-p", "photosuite", "--bin", "photosuite"]
+
+[build.phases]
+compile = '''
+set -e
+# LOCKSTEP_XML_PATH — seguro barato heredado de `mirada-greeter`/`boveda`: `accesskit` → `atspi` →
+# `zbus-lockstep-macros`, cuyo `#[validate]` recorre el dir `xml/` y panicaba al toparse con el
+# subdirectorio `xml/schemas/`. ⚠ Medido el 2026-10-13: con `atspi-common` 0.13 ese panic **ya no
+# se dispara** (`vectorcraft` compiló sin esto). Se deja porque cuesta un `cp` y porque el día que
+# vuelva, el error no nombra la causa.
+XMLDIR="$PWD/.atspi-lockstep-xml"
+mkdir -p "$XMLDIR"
+ls vendor/atspi-common/xml/*.xml >/dev/null 2>&1 || { echo "no hay vendor/atspi-common/xml/*.xml — ¿cambió el vendoreo o la versión de atspi?" >&2; exit 1; }
+cp vendor/atspi-common/xml/*.xml "$XMLDIR"/
+export LOCKSTEP_XML_PATH="$XMLDIR"
+
+printf '%s\n' '#!/bin/sh' 'for a do' 'case "$a" in --target=*) a=--target=x86_64-linux-musl ;; esac' 'set -- "$@" "$a"' 'shift' 'done' 'exec zig cc -mcpu=baseline "$@"' > "$PWD/.hammer-zig-cc"
+chmod +x "$PWD/.hammer-zig-cc"
+printf '%s\n' '#!/bin/sh' 'exec zig ar "$@"' > "$PWD/.hammer-zig-ar"
+chmod +x "$PWD/.hammer-zig-ar"
+RF="-C linker=$PWD/.hammer-zig-cc"
+rustc -vV | grep -q 'host: .*-alpine-' || RF="$RF -C link-self-contained=no"
+CC="$PWD/.hammer-zig-cc" AR="$PWD/.hammer-zig-ar" RUSTFLAGS="$RF" cargo rustc --release --locked --offline -p photosuite --bin photosuite -- -C target-feature=-crt-static
+'''
+install = '''
+set -e
+test -x target/release/photosuite || { echo "no hay target/release/photosuite — ¿cambió el nombre del bin?" >&2; exit 1; }
+install -Dm755 target/release/photosuite /out/usr/bin/photosuite
+
+install -Dm644 packaging/linux/io.github.eolix.PhotoSuite.desktop /out/usr/share/applications/io.github.eolix.PhotoSuite.desktop
+n=0
+for p in assets/app-icon/hicolor/*/apps/io.github.eolix.PhotoSuite.*; do
+ [ -f "$p" ] || continue
+ install -Dm644 "$p" "/out/usr/share/icons/hicolor/${p#assets/app-icon/hicolor/}"
+ n=$((n+1))
+done
+[ "$n" -gt 0 ] || { echo "ningún icono instalado — ¿cambió assets/app-icon/hicolor/?" >&2; exit 1; }
+install -Dm644 LICENSE-MIT /out/usr/share/licenses/photosuite/LICENSE-MIT
+install -Dm644 LICENSE-APACHE /out/usr/share/licenses/photosuite/LICENSE-APACHE
+
+test -s /out/usr/share/applications/io.github.eolix.PhotoSuite.desktop
+test -s /out/usr/bin/photosuite
+'''
+
+[deps]
+# El mismo juego que las doce de ArtCraft y que `boveda`/`mirada-greeter`: el stack gráfico se
+# consulta en build-time y se carga por `dlopen` en runtime. Sin fontconfig ni freetype: las
+# fuentes van EMBEBIDAS por `default_fonts` de eframe.
+build = ["mesa", "wayland", "wayland-protocols", "libdrm", "expat", "zlib", "zstd", "libffi", "pkgconf"]