El render agnóstico ya no es un esqueleto — porta al WASM la mayoría
de los detalles visuales que tenía solo el canvas gpui nativo:
- palette.rs: Palette dark/light replicando AstroPalette del theme
nativo, pero en Rgba (no Hsla de gpui). Métodos planet/aspect/sign
para resolver color por id simbólico, + house_ring con hue-shift.
- CompositionOpts extendido: palette, dial_3d, draw_ascensional_cross,
show_coord_labels, show_minor_aspects. Defaults razonables.
- compose_wheel ahora dibuja: background panel, dial 3D bevel (4
strokes concéntricos con alpha decreciente), subdivisiones cada 10°
con sign boundaries reforzados, signos con color elemental, casas
topocéntricas + geocéntricas en sus rings canónicos, cuerpos con
spread anti-solapamiento + clusters + disco coloreado por planeta,
coord labels "DD°MM'♈" en natal, aspectos con width inversa al
orbe + filtrado opcional de minors, cruz ascensional dashed +
pills ASC/MC/DESC/IC.
- cosmobiologia-web: nuevo render_model_to_svg_themed(dark: bool)
para que el cliente JS elija palette según preferencia del UA.
Tests del módulo math siguen verdes (10/10). Smoke test del server:
/api/sky.svg ahora emite 22 circles, 77 lines, 52 texts con paleta
real (vs ~6 circles, 24 lines, 36 texts del esqueleto previo).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cierra el requerimiento del módulo web. El cliente puede correr en
modo WASM (render local, scrubbing instantáneo, sin round-trip) o
caer al SSR (server compone el SVG) si el bundle WASM no está
desplegado. Switch automático sin configuración.
cosmobiologia-web (crate nuevo, cdylib + rlib):
- `lib.rs` con un único export wasm-bindgen
`render_model_to_svg(json, size, rot_offset_deg) -> String` que
deserializa un `RenderModel`, llama `compose_wheel` +
`draw_commands_to_svg` de cosmobiologia-render, y devuelve el
SVG inline listo para `wheel.innerHTML = svg`.
- Cargo.toml con `wasm-bindgen` + `getrandom` con feature
`wasm_js` solo bajo `target_arch = "wasm32"` (en nativo no se
arrastran).
- `.cargo/config.toml` con `--cfg getrandom_backend="wasm_js"`
para que la transitividad
`uuid → cosmobiologia-model → cosmobiologia-render` compile a
wasm32-unknown-unknown.
- `cargo check -p cosmobiologia-web` pasa en nativo (valida la
signature). Build WASM real lo dispara el usuario con
`wasm-pack build --target web --out-dir ../../../apps/
cosmobiologia-server/static/wasm` — comando documentado en
DEPLOY.md y en doc del crate.
cosmobiologia-server — soporte cliente WASM:
- Nuevo flag `--static-wasm <dir>` (default = static/wasm relativo
al cwd). Si el directorio existe, los archivos WASM se sirven
en `/static/wasm/*`. Si no existe, devuelve 404 y el cliente
cae al SSR.
- ServeDir de `tower-http` para fileserver simple.
index.html:
- Nueva función `tryLoadWasm()` que hace `import dinámico` del
módulo WASM al boot. Si carga OK, `wasm` global queda set; si
falla (archivo no existe o error de WASM), se loguea info y
sigue.
- `refreshSelected()` ahora hace fetch del RenderModel JSON
(`/api/sky` o `/api/charts/:id/render`); si hay WASM, llama
`wasm.render_model_to_svg(json)` localmente; si no hay WASM o
el render WASM falla, hace fetch del SVG SSR como fallback.
- Info row muestra "WASM" o "SSR" según el modo activo —
visualmente claro qué pipeline está corriendo.
cosmobiologia-server/DEPLOY.md (nuevo):
- Build del binario + build del WASM (con wasm-pack).
- systemd service template (sandboxing básico: ProtectSystem
strict, ProtectHome, PrivateTmp, NoNewPrivileges).
- Caddyfile y nginx para reverse proxy con TLS.
- DNS: A records para cosmobiologia.gioser.net + api.*.
- CORS: warnings sobre permissive vs producción multi-usuario.
- Separación demo público (DB vacía en VPS) vs desktop personal
(DB compartida en `~/.local/share/cosmobiologia/`).
- Backup con SQLite `.backup`.
- Smoke test post-deploy con curl.
- Tabla de referencia de TODOS los endpoints.
Tests: 10 verdes (cosmobiologia-render::math). El cliente WASM
no agrega tests propios — la lógica testeable vive en render.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>