tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

Rust 43Markdown 24TOML 17Shell 2805 Definitions

apps: swayimg 4.7 sellada, visor de imágenes en las cuatro imágenes

El plan proponía `imv` como paso 4. Al medirla apareció un muro que el método de
triaje no podía ver: imv dibuja con OpenGL de función fija (glBegin/glOrtho) y esta
distro NO tiene proveedor de GL de escritorio — las tres variantes de mesa van
-Dglx=disabled -Dglvnd=false y no publican libGL.so ni gl.pc ni opengl.pc, y no hay
receta libglvnd. La trampa fina: mesa SÍ instala GL/gl.h, así que compila entero y
muere al ligar. Darlo vuelta = autorar libglvnd + rehacer mesa (radio 139).

swayimg cubre el mismo caso de uso sin tocar GL (rasteriza a wl_shm) y con CERO
recetas nuevas: sus deps requeridas ya estaban en el corpus. De yapa trae backend DRM
(imágenes en TTY pelada, sin compositor).

Pineada 4.7 y no 5.5 a propósito: desde la 5.0 luajit es obligatoria y no hay receta
(la lua5.2 del OSC de mpv es otra ABI). Escribir luajit es el próximo paso barato.

-Dversion=4.7 no es cosmético: su default 0.0.0 dispara un `git describe` sobre el
árbol ⇒ la versión estampada en el binario dependería del checkout. Misma familia que
el -Dbuild-date de mpv.

Evidencia de que anda, no sólo de que sella: NEEDED = libc.so y nada más (cero glibc,
cero X11, cero GL), `--version` dice 4.7 con jpeg/png/gif/webp/tiff, prueba las dos
UIs (Wayland → DRM) y el bucle de decodificación rechaza lo que no es imagen.

Añadida a las raíces de los cuatro perfiles (sellado ≠ instalado). Los cinco grafos
quedan en N/N con cero deuda.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XB2iEmxeLZgzqNfhWChrLo

d8dd77981254ea80e274fe0be3268a1cdb177d83 · by Sergio · (1 month ago) · parent d54222e7f · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

8 files · +689 −178

diff --git a/docs/plan-apps-usuario-final.md b/docs/plan-apps-usuario-final.md
index a12144a3..6cf95934 100644
--- a/docs/plan-apps-usuario-final.md
+++ b/docs/plan-apps-usuario-final.md
@@ -34,7 +34,8 @@ Dos columnas, y **la que importa es la segunda**:
 | app | faltan | muros | veredicto |
 |---|---:|---|---|
 | ~~wf-recorder~~ | — | — | ✅ **SELLADA 2026-09-03** (b3:25caa359), con audio. Se destrabó al promover pipewire al corpus. Sólo en `escritorio-sway`: captura por `wlr-screencopy` y KWin/mutter no lo implementan. |
-| **imv** | 7 | — | barato: los 7 son cargadores de formato opcionales (heif, jxl, freeimage…). Visor de imágenes. |
+| ~~imv~~ | 7 | **GL de escritorio** | ❌ **BLOQUEADA 2026-09-03** — el muro no lo veía este método; ver abajo. Reemplazada por `swayimg`, sellada el mismo día. |
+| ~~swayimg~~ | — | — | ✅ **SELLADA 2026-09-03** (b3:601518b4), en las CUATRO imágenes. Visor sin GL: rasteriza a `wl_shm`. Trae backend DRM de yapa. |
 | **zathura** | 8 | — | lector de PDF; `girara` es su propia lib y ya usa GTK4 en Alpine. |
 | **mupdf** | 9 | X11 | el X11 es del visor `mupdf-x11`; el motor y `mupdf-gl` no. Requiere mirar. |
 | **inkscape** | 14 | — | sin muros, pero `gtkmm3` en la lista hay que verificarlo (¿GTK3 encubierto?). |
@@ -111,6 +112,55 @@ La regla general que sale de acá, y sirve para la próxima promoción:
 Consecuencias inmediatas: `mpv` pasó a `-Dpipewire=enabled` (con ALSA detrás, para imágenes sin
 demonio) y `wf-recorder` se escribió y selló el mismo día.
 
+## ⚠ EL TERCER DEFECTO DEL MÉTODO: la receta existe, es alcanzable, y aun así no sirve
+
+El defecto anterior era «¿existe la receta?» ≠ «¿la alcanza el consumidor?». Al ir a escribir `imv`
+apareció un **tercer eje**, y es el peor de los tres porque las dos preguntas anteriores dan que sí:
+
+> **La receta existe, el consumidor la alcanza, y la VARIANTE que se construyó no publica la ABI
+> que hace falta.**
+
+`imv` pide OpenGL. `mesa` existe, está en el corpus, y cualquier receta lo alcanza. Pero:
+
+- `imv/src/canvas.c` hace `#include <GL/gl.h>` y dibuja con `glBegin` / `glOrtho` /
+  `GL_TRIANGLE_FAN` / `GL_TEXTURE_RECTANGLE`, o sea **OpenGL de función fija**, perfil de
+  compatibilidad. No existe equivalente en GLES: no es una perilla, es otra API.
+- Su `meson.build` hace `gl_dep = dependency('gl', required: false)` y, si no la encuentra,
+  `dependency('opengl')` **sin `required: false`** ⇒ el configure muere.
+- Y esta distro **no tiene ningún proveedor de OpenGL de escritorio**. Medido en los artefactos
+  sellados, no supuesto: las **tres** variantes de mesa (`mesa`, `mesa-swrast`, `mesa-llvmpipe`)
+  llevan `-Dglx=disabled -Dglvnd=false`, y sus artefactos publican `libEGL.so.1`, `libGLESv2.so.2`,
+  `libgbm` y `egl.pc`/`glesv2.pc`/`gbm.pc` — **ni un `libGL.so*`, ni `gl.pc`, ni `opengl.pc`**.
+  No hay receta `libglvnd` en ninguna cola.
+
+**La trampa fina, y es la parte que hay que recordar:** mesa SÍ instala `/usr/include/GL/gl.h`
+(el header viene con `-Dopengl=true`). O sea que una app así **compila entera** y muere recién al
+LIGAR. Un triaje que mire headers da verde.
+
+### Qué costaría darlo vuelta (para que la decisión se tome con el número)
+
+El camino que el propio `meson.build` de imv nombra —«libglvnd fallback for pure-wayland systems»—
+es autorar `libglvnd` (que provee `libOpenGL.so`/`opengl.pc`) y reconstruir mesa con `-Dglvnd=true`.
+Eso es **radio 139 dependientes directos** sobre `mesa`, y además convierte a libglvnd en pieza
+obligatoria de las cuatro imágenes: sin ella no hay EGL. Es una decisión de distro, no un ticket de
+visor de imágenes.
+
+### La salida, que resultó mejor que el original
+
+`swayimg` cubre el mismo caso de uso **sin tocar GL**: rasteriza a un buffer y lo entrega por
+`wl_shm`. Sus deps requeridas (xkbcommon, fontconfig, freetype2, wayland, wayland-protocols) ya
+estaban todas en el corpus ⇒ **cero recetas nuevas**. Y trae un backend **DRM** que muestra imágenes
+en una TTY pelada, sin compositor, que es exactamente lo que le falta al instalador.
+
+Se pineó la **4.7** y no la 5.5 a propósito: desde la 5.0 `dependency('luajit')` es obligatoria y no
+hay receta `luajit` (la `lua5.2` del OSC de mpv es otra ABI). Escribir `luajit` destrabaría el salto
+a 5.x **y** le daría a mpv su intérprete preferido — es el próximo paso barato, no deuda de esta
+receta.
+
+**Regla que sale de acá, para el próximo triaje de apps:** la pregunta no es «¿existe la receta?»
+ni sólo «¿la alcanza?», sino **«¿la variante sellada publica el `.pc` y el `.so` que el consumidor
+pide?»**. Se contesta mirando el artefacto, no el catálogo.
+
 ## Los dos veredictos que corrigen al ADR
 
 ### Firefox NO es montón A
@@ -153,7 +203,9 @@ cierre (wayland, ffmpeg, libdrm) quedó completo cuando entró mpv.
 2. **decisión de audio del corpus** (el ⚠ de arriba). Destraba wf-recorder y le da a mpv
    su salida nativa. Es una decisión, no una campaña.
 3. **wf-recorder** — inmediato una vez tomada esa decisión; cubre el caso de uso principal de OBS.
-4. **imv** — visor de imágenes; los 7 faltantes son opcionales y se puede entrar con los mínimos.
+4. ✅ **visor de imágenes** — hecho (2026-09-03), pero con **`swayimg` 4.7 y no `imv`**: imv está
+   bloqueada por el muro de GL de escritorio (sección de arriba). En las cuatro imágenes.
+4b. **`luajit`** — receta barata que destraba swayimg 5.x y le da a mpv su intérprete preferido.
 5. **zathura** (+ backend PDF) — verificar antes que su cadena sea GTK4 y no GTK3.
 6. **Decisión de navegador** — no es trabajo de recetas, es la elección de arriba. No debería
    entrar a una cola de build hasta que esté tomada.
diff --git a/docs/state/build-state-cosmic.json b/docs/state/build-state-cosmic.json
index e238cda5..8014634e 100644
--- a/docs/state/build-state-cosmic.json
+++ b/docs/state/build-state-cosmic.json
@@ -1,14 +1,14 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 844,
-  "nodes": 845,
-  "sealed": 844,
+  "recipes": 845,
+  "nodes": 846,
+  "sealed": 845,
   "ajeno": 1
  },
  "by_class": {
   "ajeno": 1,
-  "c": 192,
+  "c": 193,
   "go": 362,
   "gui": 34,
   "kernel": 6,
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 804,
+   "sealed": 805,
    "ajeno": 1
   },
   "incoming-cosmic": {
@@ -36,9 +36,9 @@
    "sealed": 75
   },
   "escritorio-cosmic": {
-   "raices": 33,
-   "clausura": 106,
-   "sealed": 106
+   "raices": 34,
+   "clausura": 114,
+   "sealed": 114
   },
   "escritorio-mirada": {
    "raices": 14,
@@ -46,7 +46,7 @@
    "sealed": 33
   }
  },
- "sin_perfil": 649,
+ "sin_perfil": 647,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -4042,7 +4042,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 60
+   "dependientes_total": 61
   },
   "expat-shared": {
    "iname": "expat-shared",
@@ -4417,7 +4417,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 25
+   "dependientes_total": 26
   },
   "fontconfig-shared": {
    "iname": "fontconfig-shared",
@@ -4538,7 +4538,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "freetype-shared": {
    "iname": "freetype-shared",
@@ -4892,8 +4892,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 1
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 2
   },
   "git": {
    "iname": "git",
@@ -7326,9 +7331,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 2
+   "dependientes_total": 3
   },
   "json-glib": {
    "iname": "json-glib",
@@ -8521,7 +8529,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 141
+   "dependientes_total": 142
   },
   "libelogind": {
    "iname": "libelogind",
@@ -8626,7 +8634,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 100
+   "dependientes_total": 101
   },
   "libffi-shared": {
    "iname": "libffi-shared",
@@ -8736,9 +8744,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 14
+   "dependientes_total": 15
   },
   "libjpeg-turbo-shared": {
    "iname": "libjpeg-turbo-shared",
@@ -8854,7 +8865,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "libpng-pic": {
    "iname": "libpng-pic",
@@ -9018,9 +9029,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 11
+   "dependientes_total": 12
   },
   "libtiff-shared": {
    "iname": "libtiff-shared",
@@ -9146,8 +9160,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 0
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 1
   },
   "libxkbcommon": {
    "iname": "libxkbcommon",
@@ -9174,7 +9193,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 41
+   "dependientes_total": 42
   },
   "libxml2": {
    "iname": "libxml2",
@@ -9351,7 +9370,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "linux-metal": {
    "iname": "linux-metal",
@@ -10012,7 +10031,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 117
+   "dependientes_total": 118
   },
   "micro": {
    "iname": "micro",
@@ -11615,7 +11634,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 372
+   "dependientes_total": 373
   },
   "plow": {
    "iname": "plow",
@@ -11987,7 +12006,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 286
+   "dependientes_total": 287
   },
   "qrcp": {
    "iname": "qrcp",
@@ -12542,7 +12561,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 250
+   "dependientes_total": 251
   },
   "sassc": {
    "iname": "sassc",
@@ -12628,9 +12647,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 3
+   "dependientes_total": 4
   },
   "scorecard": {
    "iname": "scorecard",
@@ -13411,6 +13433,51 @@
    "perfiles": [],
    "dependientes_total": 0
   },
+  "swayimg": {
+   "iname": "swayimg",
+   "version": "4.7",
+   "link": "dynamic",
+   "compiler": "zig-cc",
+   "deps": [
+    "meson",
+    "samurai",
+    "python3",
+    "pkgconf",
+    "scdoc",
+    "linux-headers",
+    "wayland",
+    "wayland-protocols",
+    "libxkbcommon",
+    "libdrm",
+    "fontconfig",
+    "freetype",
+    "expat",
+    "libjpeg-turbo",
+    "libpng",
+    "libtiff",
+    "libwebp",
+    "giflib",
+    "json-c",
+    "zlib",
+    "zlib-shared",
+    "xz",
+    "zstd",
+    "libffi"
+   ],
+   "cls": "c",
+   "queue": "corpus",
+   "hash": "b3:601518b418088f3a4c6c0d0993441c7fd196266a092a057c18a96e96e3ad29cd",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 0
+  },
   "syft": {
    "iname": "syft",
    "version": "1.42.4",
@@ -14794,7 +14861,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 150
+   "dependientes_total": 151
   },
   "wayland-protocols": {
    "iname": "wayland-protocols",
@@ -14821,7 +14888,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 49
+   "dependientes_total": 50
   },
   "websocketd": {
    "iname": "websocketd",
@@ -15322,9 +15389,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-gnome"
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
    ],
-   "dependientes_total": 13
+   "dependientes_total": 14
   },
   "yamlfmt": {
    "iname": "yamlfmt",
@@ -15480,7 +15550,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 99
+   "dependientes_total": 100
   },
   "zlib-ng": {
    "iname": "zlib-ng",
@@ -15519,7 +15589,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 73
+   "dependientes_total": 74
   },
   "zola": {
    "iname": "zola",
@@ -15575,7 +15645,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   }
  }
 }
diff --git a/docs/state/build-state-gnome.json b/docs/state/build-state-gnome.json
index f2422f89..ebf680cd 100644
--- a/docs/state/build-state-gnome.json
+++ b/docs/state/build-state-gnome.json
@@ -1,14 +1,14 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 869,
-  "nodes": 870,
-  "sealed": 869,
+  "recipes": 870,
+  "nodes": 871,
+  "sealed": 870,
   "ajeno": 1
  },
  "by_class": {
   "ajeno": 1,
-  "c": 231,
+  "c": 232,
   "go": 362,
   "gui": 40,
   "kernel": 6,
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 795,
+   "sealed": 796,
    "ajeno": 1
   },
   "incoming-gnome": {
@@ -36,9 +36,9 @@
    "sealed": 74
   },
   "escritorio-gnome": {
-   "raices": 9,
-   "clausura": 132,
-   "sealed": 132
+   "raices": 10,
+   "clausura": 139,
+   "sealed": 139
   },
   "escritorio-mirada": {
    "raices": 14,
@@ -46,7 +46,7 @@
    "sealed": 33
   }
  },
- "sin_perfil": 663,
+ "sin_perfil": 661,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -3776,7 +3776,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 60
+   "dependientes_total": 61
   },
   "expat-shared": {
    "iname": "expat-shared",
@@ -4151,7 +4151,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 25
+   "dependientes_total": 26
   },
   "fontconfig-shared": {
    "iname": "fontconfig-shared",
@@ -4272,7 +4272,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "freetype-shared": {
    "iname": "freetype-shared",
@@ -4793,8 +4793,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 1
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 2
   },
   "git": {
    "iname": "git",
@@ -7562,9 +7567,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 2
+   "dependientes_total": 3
   },
   "json-glib": {
    "iname": "json-glib",
@@ -8783,7 +8791,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 141
+   "dependientes_total": 142
   },
   "libei": {
    "iname": "libei",
@@ -8918,7 +8926,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 100
+   "dependientes_total": 101
   },
   "libffi-shared": {
    "iname": "libffi-shared",
@@ -9231,9 +9239,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 14
+   "dependientes_total": 15
   },
   "libjpeg-turbo-shared": {
    "iname": "libjpeg-turbo-shared",
@@ -9349,7 +9360,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "libpng-pic": {
    "iname": "libpng-pic",
@@ -9634,9 +9645,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 11
+   "dependientes_total": 12
   },
   "libtiff-shared": {
    "iname": "libtiff-shared",
@@ -9780,8 +9794,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 0
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 1
   },
   "libxcvt": {
    "iname": "libxcvt",
@@ -9830,7 +9849,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 41
+   "dependientes_total": 42
   },
   "libxml2": {
    "iname": "libxml2",
@@ -10007,7 +10026,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "linux-metal": {
    "iname": "linux-metal",
@@ -10666,7 +10685,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 117
+   "dependientes_total": 118
   },
   "micro": {
    "iname": "micro",
@@ -12393,7 +12412,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 372
+   "dependientes_total": 373
   },
   "plow": {
    "iname": "plow",
@@ -12832,7 +12851,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 286
+   "dependientes_total": 287
   },
   "qrcp": {
    "iname": "qrcp",
@@ -13387,7 +13406,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 250
+   "dependientes_total": 251
   },
   "sassc": {
    "iname": "sassc",
@@ -13473,9 +13492,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 3
+   "dependientes_total": 4
   },
   "scorecard": {
    "iname": "scorecard",
@@ -14301,6 +14323,51 @@
    "perfiles": [],
    "dependientes_total": 0
   },
+  "swayimg": {
+   "iname": "swayimg",
+   "version": "4.7",
+   "link": "dynamic",
+   "compiler": "zig-cc",
+   "deps": [
+    "meson",
+    "samurai",
+    "python3",
+    "pkgconf",
+    "scdoc",
+    "linux-headers",
+    "wayland",
+    "wayland-protocols",
+    "libxkbcommon",
+    "libdrm",
+    "fontconfig",
+    "freetype",
+    "expat",
+    "libjpeg-turbo",
+    "libpng",
+    "libtiff",
+    "libwebp",
+    "giflib",
+    "json-c",
+    "zlib",
+    "zlib-shared",
+    "xz",
+    "zstd",
+    "libffi"
+   ],
+   "cls": "c",
+   "queue": "corpus",
+   "hash": "b3:601518b418088f3a4c6c0d0993441c7fd196266a092a057c18a96e96e3ad29cd",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 0
+  },
   "syft": {
    "iname": "syft",
    "version": "1.42.4",
@@ -15738,7 +15805,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 150
+   "dependientes_total": 151
   },
   "wayland-protocols": {
    "iname": "wayland-protocols",
@@ -15765,7 +15832,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 49
+   "dependientes_total": 50
   },
   "websocketd": {
    "iname": "websocketd",
@@ -16316,9 +16383,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-gnome"
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
    ],
-   "dependientes_total": 13
+   "dependientes_total": 14
   },
   "yamlfmt": {
    "iname": "yamlfmt",
@@ -16474,7 +16544,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 99
+   "dependientes_total": 100
   },
   "zlib-ng": {
    "iname": "zlib-ng",
@@ -16513,7 +16583,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 73
+   "dependientes_total": 74
   },
   "zola": {
    "iname": "zola",
@@ -16569,7 +16639,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   }
  }
 }
diff --git a/docs/state/build-state-kde.json b/docs/state/build-state-kde.json
index c158fe4c..b0089ad0 100644
--- a/docs/state/build-state-kde.json
+++ b/docs/state/build-state-kde.json
@@ -1,14 +1,14 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 988,
-  "nodes": 989,
-  "sealed": 988,
+  "recipes": 989,
+  "nodes": 990,
+  "sealed": 989,
   "ajeno": 1
  },
  "by_class": {
   "ajeno": 1,
-  "c": 355,
+  "c": 356,
   "go": 362,
   "gui": 36,
   "kernel": 6,
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 790
+   "sealed": 791
   },
   "incoming-kde": {
    "sealed": 198,
@@ -36,9 +36,9 @@
    "sealed": 70
   },
   "escritorio-kde": {
-   "raices": 14,
-   "clausura": 189,
-   "sealed": 188,
+   "raices": 15,
+   "clausura": 197,
+   "sealed": 196,
    "ajeno": 1
   },
   "escritorio-mirada": {
@@ -47,7 +47,7 @@
    "sealed": 29
   }
  },
- "sin_perfil": 711,
+ "sin_perfil": 709,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -3930,7 +3930,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 60
+   "dependientes_total": 61
   },
   "expat-shared": {
    "iname": "expat-shared",
@@ -4389,7 +4389,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 25
+   "dependientes_total": 26
   },
   "fontconfig-shared": {
    "iname": "fontconfig-shared",
@@ -4584,7 +4584,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "freetype-shared": {
    "iname": "freetype-shared",
@@ -4916,8 +4916,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 1
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 2
   },
   "git": {
    "iname": "git",
@@ -7453,9 +7458,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 2
+   "dependientes_total": 3
   },
   "jsonnet-bundler": {
    "iname": "jsonnet-bundler",
@@ -12265,7 +12273,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 141
+   "dependientes_total": 142
   },
   "libepoxy": {
    "iname": "libepoxy",
@@ -12349,7 +12357,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 100
+   "dependientes_total": 101
   },
   "libffi-shared": {
    "iname": "libffi-shared",
@@ -12449,9 +12457,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 14
+   "dependientes_total": 15
   },
   "libjpeg-turbo-shared": {
    "iname": "libjpeg-turbo-shared",
@@ -12823,7 +12834,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "libpng-pic": {
    "iname": "libpng-pic",
@@ -13009,9 +13020,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 11
+   "dependientes_total": 12
   },
   "libtiff-shared": {
    "iname": "libtiff-shared",
@@ -13198,8 +13212,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 0
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 1
   },
   "libxcb": {
    "iname": "libxcb",
@@ -13492,7 +13511,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "linux-metal": {
    "iname": "linux-metal",
@@ -14154,7 +14173,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 117
+   "dependientes_total": 118
   },
   "micro": {
    "iname": "micro",
@@ -16075,7 +16094,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 372
+   "dependientes_total": 373
   },
   "plasma-activities": {
    "iname": "plasma-activities",
@@ -17427,7 +17446,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 286
+   "dependientes_total": 287
   },
   "qcoro": {
    "iname": "qcoro",
@@ -18571,7 +18590,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 250
+   "dependientes_total": 251
   },
   "sassc": {
    "iname": "sassc",
@@ -18657,9 +18676,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 3
+   "dependientes_total": 4
   },
   "scorecard": {
    "iname": "scorecard",
@@ -19622,6 +19644,51 @@
    "perfiles": [],
    "dependientes_total": 0
   },
+  "swayimg": {
+   "iname": "swayimg",
+   "version": "4.7",
+   "link": "dynamic",
+   "compiler": "zig-cc",
+   "deps": [
+    "meson",
+    "samurai",
+    "python3",
+    "pkgconf",
+    "scdoc",
+    "linux-headers",
+    "wayland",
+    "wayland-protocols",
+    "libxkbcommon",
+    "libdrm",
+    "fontconfig",
+    "freetype",
+    "expat",
+    "libjpeg-turbo",
+    "libpng",
+    "libtiff",
+    "libwebp",
+    "giflib",
+    "json-c",
+    "zlib",
+    "zlib-shared",
+    "xz",
+    "zstd",
+    "libffi"
+   ],
+   "cls": "c",
+   "queue": "corpus",
+   "hash": "b3:601518b418088f3a4c6c0d0993441c7fd196266a092a057c18a96e96e3ad29cd",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 0
+  },
   "syft": {
    "iname": "syft",
    "version": "1.42.4",
@@ -21227,7 +21294,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 150
+   "dependientes_total": 151
   },
   "wayland-protocols": {
    "iname": "wayland-protocols",
@@ -21254,7 +21321,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 49
+   "dependientes_total": 50
   },
   "websocketd": {
    "iname": "websocketd",
@@ -21880,9 +21947,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-gnome"
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
    ],
-   "dependientes_total": 13
+   "dependientes_total": 14
   },
   "xz-shared": {
    "iname": "xz-shared",
@@ -22055,7 +22125,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 99
+   "dependientes_total": 100
   },
   "zlib-ng": {
    "iname": "zlib-ng",
@@ -22094,7 +22164,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 73
+   "dependientes_total": 74
   },
   "zola": {
    "iname": "zola",
@@ -22150,7 +22220,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "zxing-cpp": {
    "iname": "zxing-cpp",
diff --git a/docs/state/build-state-wlr.json b/docs/state/build-state-wlr.json
index 9787fbee..9edef806 100644
--- a/docs/state/build-state-wlr.json
+++ b/docs/state/build-state-wlr.json
@@ -1,14 +1,14 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 818,
-  "nodes": 819,
-  "sealed": 818,
+  "recipes": 819,
+  "nodes": 820,
+  "sealed": 819,
   "ajeno": 1
  },
  "by_class": {
   "ajeno": 1,
-  "c": 189,
+  "c": 190,
   "go": 362,
   "gui": 32,
   "kernel": 6,
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 803,
+   "sealed": 804,
    "ajeno": 1
   },
   "incoming-wlr": {
@@ -41,12 +41,12 @@
    "sealed": 33
   },
   "escritorio-sway": {
-   "raices": 63,
-   "clausura": 146,
-   "sealed": 146
+   "raices": 64,
+   "clausura": 150,
+   "sealed": 150
   }
  },
- "sin_perfil": 649,
+ "sin_perfil": 647,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -3576,7 +3576,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 60
+   "dependientes_total": 61
   },
   "expat-shared": {
    "iname": "expat-shared",
@@ -3951,7 +3951,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 25
+   "dependientes_total": 26
   },
   "fontconfig-shared": {
    "iname": "fontconfig-shared",
@@ -4072,7 +4072,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "freetype-shared": {
    "iname": "freetype-shared",
@@ -4445,8 +4445,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 1
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 2
   },
   "git": {
    "iname": "git",
@@ -6842,9 +6847,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 2
+   "dependientes_total": 3
   },
   "jsonnet-bundler": {
    "iname": "jsonnet-bundler",
@@ -8011,7 +8019,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 141
+   "dependientes_total": 142
   },
   "libepoxy": {
    "iname": "libepoxy",
@@ -8099,7 +8107,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 100
+   "dependientes_total": 101
   },
   "libffi-shared": {
    "iname": "libffi-shared",
@@ -8209,9 +8217,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 14
+   "dependientes_total": 15
   },
   "libjpeg-turbo-shared": {
    "iname": "libjpeg-turbo-shared",
@@ -8327,7 +8338,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "libpng-pic": {
    "iname": "libpng-pic",
@@ -8466,9 +8477,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 11
+   "dependientes_total": 12
   },
   "libtiff-shared": {
    "iname": "libtiff-shared",
@@ -8594,8 +8608,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 0
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 1
   },
   "libxkbcommon": {
    "iname": "libxkbcommon",
@@ -8622,7 +8641,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 41
+   "dependientes_total": 42
   },
   "libxml2": {
    "iname": "libxml2",
@@ -8799,7 +8818,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "linux-metal": {
    "iname": "linux-metal",
@@ -9440,7 +9459,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 117
+   "dependientes_total": 118
   },
   "micro": {
    "iname": "micro",
@@ -11004,7 +11023,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 372
+   "dependientes_total": 373
   },
   "plow": {
    "iname": "plow",
@@ -11334,7 +11353,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 286
+   "dependientes_total": 287
   },
   "qrcp": {
    "iname": "qrcp",
@@ -11889,7 +11908,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 250
+   "dependientes_total": 251
   },
   "sassc": {
    "iname": "sassc",
@@ -11975,9 +11994,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 3
+   "dependientes_total": 4
   },
   "scorecard": {
    "iname": "scorecard",
@@ -12915,6 +12937,51 @@
    ],
    "dependientes_total": 0
   },
+  "swayimg": {
+   "iname": "swayimg",
+   "version": "4.7",
+   "link": "dynamic",
+   "compiler": "zig-cc",
+   "deps": [
+    "meson",
+    "samurai",
+    "python3",
+    "pkgconf",
+    "scdoc",
+    "linux-headers",
+    "wayland",
+    "wayland-protocols",
+    "libxkbcommon",
+    "libdrm",
+    "fontconfig",
+    "freetype",
+    "expat",
+    "libjpeg-turbo",
+    "libpng",
+    "libtiff",
+    "libwebp",
+    "giflib",
+    "json-c",
+    "zlib",
+    "zlib-shared",
+    "xz",
+    "zstd",
+    "libffi"
+   ],
+   "cls": "c",
+   "queue": "corpus",
+   "hash": "b3:601518b418088f3a4c6c0d0993441c7fd196266a092a057c18a96e96e3ad29cd",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 0
+  },
   "swaylock": {
    "iname": "swaylock",
    "version": "1.8.0",
@@ -14339,7 +14406,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 150
+   "dependientes_total": 151
   },
   "wayland-protocols": {
    "iname": "wayland-protocols",
@@ -14366,7 +14433,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 49
+   "dependientes_total": 50
   },
   "websocketd": {
    "iname": "websocketd",
@@ -14838,9 +14905,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-gnome"
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
    ],
-   "dependientes_total": 13
+   "dependientes_total": 14
   },
   "yambar": {
    "iname": "yambar",
@@ -15039,7 +15109,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 99
+   "dependientes_total": 100
   },
   "zlib-ng": {
    "iname": "zlib-ng",
@@ -15078,7 +15148,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 73
+   "dependientes_total": 74
   },
   "zola": {
    "iname": "zola",
@@ -15134,7 +15204,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   }
  }
 }
diff --git a/docs/state/build-state.json b/docs/state/build-state.json
index 271d935d..41820b47 100644
--- a/docs/state/build-state.json
+++ b/docs/state/build-state.json
@@ -1,14 +1,14 @@
 {
  "schema": "hammer-build-state/1",
  "totals": {
-  "recipes": 804,
-  "nodes": 805,
-  "sealed": 804,
+  "recipes": 805,
+  "nodes": 806,
+  "sealed": 805,
   "ajeno": 1
  },
  "by_class": {
   "ajeno": 1,
-  "c": 175,
+  "c": 176,
   "go": 362,
   "gui": 32,
   "kernel": 6,
@@ -17,7 +17,7 @@
  "debt_by_class": {},
  "by_queue": {
   "corpus": {
-   "sealed": 804,
+   "sealed": 805,
    "ajeno": 1
   }
  },
@@ -38,7 +38,7 @@
    "sealed": 33
   }
  },
- "sin_perfil": 649,
+ "sin_perfil": 647,
  "orphan_deps": [],
  "topo_ok": true,
  "nodes": {
@@ -3551,7 +3551,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 60
+   "dependientes_total": 61
   },
   "expat-shared": {
    "iname": "expat-shared",
@@ -3926,7 +3926,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 25
+   "dependientes_total": 26
   },
   "fontconfig-shared": {
    "iname": "fontconfig-shared",
@@ -4047,7 +4047,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "freetype-shared": {
    "iname": "freetype-shared",
@@ -4379,8 +4379,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 1
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 2
   },
   "git": {
    "iname": "git",
@@ -6727,9 +6732,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 2
+   "dependientes_total": 3
   },
   "jsonnet-bundler": {
    "iname": "jsonnet-bundler",
@@ -7873,7 +7881,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 141
+   "dependientes_total": 142
   },
   "libepoxy": {
    "iname": "libepoxy",
@@ -7961,7 +7969,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 100
+   "dependientes_total": 101
   },
   "libffi-shared": {
    "iname": "libffi-shared",
@@ -8071,9 +8079,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 14
+   "dependientes_total": 15
   },
   "libjpeg-turbo-shared": {
    "iname": "libjpeg-turbo-shared",
@@ -8189,7 +8200,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 27
+   "dependientes_total": 28
   },
   "libpng-pic": {
    "iname": "libpng-pic",
@@ -8328,9 +8339,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 11
+   "dependientes_total": 12
   },
   "libtiff-shared": {
    "iname": "libtiff-shared",
@@ -8456,8 +8470,13 @@
    "state": "sealed",
    "blocked_by": [],
    "unblocks": 0,
-   "perfiles": [],
-   "dependientes_total": 0
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 1
   },
   "libxkbcommon": {
    "iname": "libxkbcommon",
@@ -8484,7 +8503,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 41
+   "dependientes_total": 42
   },
   "libxml2": {
    "iname": "libxml2",
@@ -8661,7 +8680,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   },
   "linux-metal": {
    "iname": "linux-metal",
@@ -9302,7 +9321,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 117
+   "dependientes_total": 118
   },
   "micro": {
    "iname": "micro",
@@ -10866,7 +10885,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 372
+   "dependientes_total": 373
   },
   "plow": {
    "iname": "plow",
@@ -11196,7 +11215,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 286
+   "dependientes_total": 287
   },
   "qrcp": {
    "iname": "qrcp",
@@ -11751,7 +11770,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 250
+   "dependientes_total": 251
   },
   "sassc": {
    "iname": "sassc",
@@ -11837,9 +11856,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 3
+   "dependientes_total": 4
   },
   "scorecard": {
    "iname": "scorecard",
@@ -12620,6 +12642,51 @@
    "perfiles": [],
    "dependientes_total": 0
   },
+  "swayimg": {
+   "iname": "swayimg",
+   "version": "4.7",
+   "link": "dynamic",
+   "compiler": "zig-cc",
+   "deps": [
+    "meson",
+    "samurai",
+    "python3",
+    "pkgconf",
+    "scdoc",
+    "linux-headers",
+    "wayland",
+    "wayland-protocols",
+    "libxkbcommon",
+    "libdrm",
+    "fontconfig",
+    "freetype",
+    "expat",
+    "libjpeg-turbo",
+    "libpng",
+    "libtiff",
+    "libwebp",
+    "giflib",
+    "json-c",
+    "zlib",
+    "zlib-shared",
+    "xz",
+    "zstd",
+    "libffi"
+   ],
+   "cls": "c",
+   "queue": "corpus",
+   "hash": "b3:601518b418088f3a4c6c0d0993441c7fd196266a092a057c18a96e96e3ad29cd",
+   "state": "sealed",
+   "blocked_by": [],
+   "unblocks": 0,
+   "perfiles": [
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
+   ],
+   "dependientes_total": 0
+  },
   "syft": {
    "iname": "syft",
    "version": "1.42.4",
@@ -14003,7 +14070,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 150
+   "dependientes_total": 151
   },
   "wayland-protocols": {
    "iname": "wayland-protocols",
@@ -14030,7 +14097,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 49
+   "dependientes_total": 50
   },
   "websocketd": {
    "iname": "websocketd",
@@ -14415,9 +14482,12 @@
    "blocked_by": [],
    "unblocks": 0,
    "perfiles": [
-    "escritorio-gnome"
+    "escritorio-cosmic",
+    "escritorio-gnome",
+    "escritorio-kde",
+    "escritorio-sway"
    ],
-   "dependientes_total": 13
+   "dependientes_total": 14
   },
   "yamlfmt": {
    "iname": "yamlfmt",
@@ -14573,7 +14643,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 99
+   "dependientes_total": 100
   },
   "zlib-ng": {
    "iname": "zlib-ng",
@@ -14612,7 +14682,7 @@
     "escritorio-kde",
     "escritorio-sway"
    ],
-   "dependientes_total": 73
+   "dependientes_total": 74
   },
   "zola": {
    "iname": "zola",
@@ -14668,7 +14738,7 @@
     "escritorio-mirada",
     "escritorio-sway"
    ],
-   "dependientes_total": 31
+   "dependientes_total": 32
   }
  }
 }
diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index 8a0c3af6..ad872d29 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -80,6 +80,13 @@ paquetes = [
   # `-Dpipewire-alsa=disabled` en las pipewire (⇒ no suena con PipeWire vivo), sin Lua (⇒ sin OSC)
   # y sin vaapi (⇒ sin decodificación por hardware).
   "mpv",
+  # ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
+  # `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
+  # OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
+  # escritorio — las tres mesa van `-Dglx=disabled -Dglvnd=false` ⇒ no hay `libGL.so` ni `gl.pc` en
+  # ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
+  # Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
+  "swayimg",
   # ── LAS `.so` QUE mesa Y wayland PIDEN EN RUNTIME Y NINGÚN ARTEFACTO DEL CIERRE PROVEE ────────
   # Medido el 2026-09-03 recorriendo los NEEDED de todo el cierre de esta imagen contra los SONAME
   # que ese mismo cierre publica: `libEGL.so.1` pide `libexpat.so.1` y `libwayland-client.so.0` pide
@@ -132,6 +139,13 @@ paquetes = [
   # `-Dpipewire-alsa=disabled` en las pipewire (⇒ no suena con PipeWire vivo), sin Lua (⇒ sin OSC)
   # y sin vaapi (⇒ sin decodificación por hardware).
   "mpv",
+  # ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
+  # `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
+  # OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
+  # escritorio — las tres mesa van `-Dglx=disabled -Dglvnd=false` ⇒ no hay `libGL.so` ni `gl.pc` en
+  # ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
+  # Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
+  "swayimg",
   # ── LAS `.so` QUE mesa Y wayland PIDEN EN RUNTIME Y NINGÚN ARTEFACTO DEL CIERRE PROVEE ────────
   # Medido el 2026-09-03 recorriendo los NEEDED de todo el cierre de esta imagen contra los SONAME
   # que ese mismo cierre publica: `libEGL.so.1` pide `libexpat.so.1` y `libwayland-client.so.0` pide
@@ -225,6 +239,13 @@ paquetes = [
   # `-Dpipewire-alsa=disabled` en las pipewire (⇒ no suena con PipeWire vivo), sin Lua (⇒ sin OSC)
   # y sin vaapi (⇒ sin decodificación por hardware).
   "mpv",
+  # ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
+  # `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
+  # OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
+  # escritorio — las tres mesa van `-Dglx=disabled -Dglvnd=false` ⇒ no hay `libGL.so` ni `gl.pc` en
+  # ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
+  # Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
+  "swayimg",
   # ── LAS `.so` QUE mesa Y wayland PIDEN EN RUNTIME Y NINGÚN ARTEFACTO DEL CIERRE PROVEE ────────
   # Medido el 2026-09-03 recorriendo los NEEDED de todo el cierre de esta imagen contra los SONAME
   # que ese mismo cierre publica: `libEGL.so.1` pide `libexpat.so.1` y `libwayland-client.so.0` pide
@@ -300,6 +321,13 @@ paquetes = [
   # `-Dpipewire-alsa=disabled` en las pipewire (⇒ no suena con PipeWire vivo), sin Lua (⇒ sin OSC)
   # y sin vaapi (⇒ sin decodificación por hardware).
   "mpv",
+  # ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
+  # `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
+  # OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
+  # escritorio — las tres mesa van `-Dglx=disabled -Dglvnd=false` ⇒ no hay `libGL.so` ni `gl.pc` en
+  # ninguna cola. swayimg rasteriza a `wl_shm` y no toca GL; el porqué largo está en su receta.
+  # Trae de yapa backend DRM: muestra imágenes en una TTY pelada, sin compositor.
+  "swayimg",
   # ── GRABADOR DE PANTALLA — sólo acá, y la razón es de PROTOCOLO, no de gusto ──────────────────
   # `wf-recorder` captura por `wlr-screencopy`, que implementan los compositores wlroots. KWin y
   # mutter NO lo implementan (usan el portal/ScreenCast), así que ponerlo en esas dos imágenes
diff --git a/recipes/swayimg.toml b/recipes/swayimg.toml
new file mode 100644
index 00000000..76e96f8e
--- /dev/null
+++ b/recipes/swayimg.toml
@@ -0,0 +1,81 @@
+# swayimg 4.7 — visor de imágenes Wayland-nativo, para las CUATRO imágenes.
+#
+# ══ POR QUÉ ESTA Y NO `imv`, QUE ERA LA QUE DECÍA EL PLAN ══════════════════════════════════════
+# `docs/plan-apps-usuario-final.md` proponía `imv` como paso 4 —«7 faltantes, todos cargadores de
+# formato opcionales, sin muros»—. Al ir a escribirla, la medición dijo otra cosa:
+#
+#   imv/src/canvas.c hace `#include <GL/gl.h>` y dibuja con `glBegin`/`glOrtho`/`GL_TRIANGLE_FAN`,
+#   o sea OpenGL de FUNCIÓN FIJA (perfil de compatibilidad). Su meson pide `dependency('gl')` y,
+#   si falta, `dependency('opengl')` SIN `required:false` ⇒ configure muere.
+#
+# Y esta distro **no tiene ningún proveedor de OpenGL de escritorio**. Medido en los artefactos, no
+# supuesto: las TRES variantes de mesa (`mesa`, `mesa-swrast`, `mesa-llvmpipe`) van
+# `-Dglx=disabled -Dglvnd=false` ⇒ publican `libEGL.so.1` y `libGLESv2.so.2` y **ni `libGL.so*` ni
+# `gl.pc` ni `opengl.pc`**; no hay receta `libglvnd` en ninguna cola. La trampa fina es que mesa SÍ
+# instala `/usr/include/GL/gl.h` ⇒ una app así compila y muere recién al LIGAR.
+# El muro está anotado en el plan; darlo vuelta es cambiar mesa (radio 139) + autorar libglvnd, o
+# sea una decisión de distro, no un ticket de visor de imágenes.
+#
+# swayimg cubre exactamente el mismo caso de uso **sin GL**: rasteriza a un buffer y lo entrega por
+# `wl_shm`. Encaja con la distro en vez de pelearse con ella, y de yapa trae backend **DRM**, que
+# muestra imágenes en una TTY pelada sin compositor.
+#
+# ══ VERSIÓN 4.7 Y NO 5.5, A PROPÓSITO ══════════════════════════════════════════════════════════
+# Desde la 5.0 `dependency('luajit')` es OBLIGATORIA (scripting), y no hay receta `luajit` — la
+# `lua5.2` que entró para el OSC de mpv no sirve, es otra ABI. La 4.7 es la última sin lua y sus
+# deps requeridas están TODAS en el corpus. Subir a 5.x = escribir `luajit` primero, que además le
+# daría a mpv su intérprete preferido; queda anotado como el camino, no como deuda de esta receta.
+#
+# ══ `-Dversion=4.7` NO ES COSMÉTICO ════════════════════════════════════════════════════════════
+# Su default es la cadena `0.0.0`, y meson.build:24-35 la interpreta como «averiguala vos»: corre
+# `git describe --tags --long --always --dirty` sobre el árbol. O sea que **la versión estampada
+# DENTRO del binario dependería del estado del checkout** (si hay `.git`, si trajo los tags, si
+# quedó sucio) y dos builds del mismo commit podrían dar bytes distintos. Misma familia que el
+# `-Dbuild-date` de mpv: la perilla que se busca en toda app nueva.
+#
+# ══ OPCIONES TODAS EXPLÍCITAS ══════════════════════════════════════════════════════════════════
+# Las doce de formato nacen `auto`, o sea que miran el sandbox y se prenden con lo que encuentren:
+# el artefacto pasaría a depender de qué otra cosa quedó montada en el lab. Se enumeran una por una.
+# ENCENDIDAS (la dep ya está en el corpus): jpeg, png, tiff, webp, gif, y `compositor` (json-c, es
+# la integración por IPC con sway).
+# APAGADAS por falta de receta: exr, heif, avif, jxl, sixel, raw, exif, bash.
+# APAGADA por cola: `svg` pide `librsvg-2.0`, que vive sólo en `incoming-gnome` — y una receta del
+# corpus no alcanza una cola hermana. Es el mismo hueco que dejó mudo a wf-recorder.
+#
+# `-Dprefer_static=true` como mpv: fontconfig, freetype, libpng, libjpeg, libtiff, libwebp, expat y
+# json-c son `.a` en el corpus, y sin esta perilla meson resuelve los `.pc` sin `Libs.private` y el
+# link muere con símbolos de expat «en libfontconfig.a», culpando a fontconfig. `link=dynamic`
+# porque wayland, libxkbcommon, libdrm y zstd sí publican `.so`.
+#
+# Fuente por commit git (ADR 0006): `v4.7` es un tag LIVIANO ⇒ éste es su commit.
+name    = "swayimg"
+version = "4.7"
+license = "MIT"
+
+[source]
+repo   = "https://github.com/artemsen/swayimg.git"
+commit = "8f0d660bb28a16e0972b986a1a27d4a1876b2cc5"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "dynamic"
+flags    = []
+
+[build.phases]
+configure = "PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release -Dprefer_static=true -Dversion=4.7 -Dwayland=enabled -Ddrm=enabled -Dcompositor=enabled -Djpeg=enabled -Dpng=enabled -Dtiff=enabled -Dwebp=enabled -Dgif=enabled -Dexr=disabled -Dheif=disabled -Davif=disabled -Djxl=disabled -Dsvg=disabled -Dsixel=disabled -Draw=disabled -Dexif=disabled -Dbash=disabled -Dzsh=disabled -Ddesktop=true -Dman=true -Dtests=disabled"
+compile   = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
+install   = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
+
+# `.pc Requires` → `[deps].build`, el patrón del corpus: fontconfig pide expat, freetype2 pide zlib
+# y libpng, wayland-client pide libffi, libtiff-4 pide zlib+xz+zstd+libjpeg, libwebpdemux pide
+# libsharpyuv (viene en el mismo artefacto). `scdoc` genera las dos man pages; `wayland` aporta
+# además el `wayland-scanner` nativo que teje los ocho protocolos.
+[deps]
+build = [
+  "meson", "samurai", "python3", "pkgconf", "scdoc", "linux-headers",
+  "wayland", "wayland-protocols", "libxkbcommon", "libdrm",
+  "fontconfig", "freetype", "expat",
+  "libjpeg-turbo", "libpng", "libtiff", "libwebp", "giflib", "json-c",
+  "zlib", "zlib-shared", "xz", "zstd", "libffi",
+]