Renderer (gioser-canvas-web):
- Spring shake (SpringDamper1, 7.5 Hz / ζ=0.13) aplicado como rotación Z
en el MVP. impulse_click() inyecta velocidad alternada → vibración fuerte
con ~5 ciclos decayendo en ~0.8s.
- release_tilt() pone target del tilt en (0,0) → la chacana cae al frente
con el rebote natural del spring sub-crítico.
- world_scale_for_aspect(): en portrait (aspect<1) escala baja proporcional
para que el aro exterior no se corte por los lados. Base 1.05, piso 0.45.
- click_radius_css_px() expone radio del aro en CSS-pixels desde el centro
del canvas; la app lo usa para hit-test del impulso.
- set_client_size() separa CSS-pixels de device-pixels (DPR).
- tilt_degrees() ahora retorna (pitch, yaw, roll) — el brand replica los 3.
- 4 nuevos uniforms u_aire/fuego/tierra/agua_color para el shader de
partículas.
Shader (gioser-shaders/FS_CHACANA):
- Función element_particles(tip, outward, color, kind) → 4 partículas por
cardinal con personalidad: AIRE drift+sway, FUEGO rise+flicker (siempre
hacia +Y), TIERRA cae, AGUA ondula descendiendo. Gauss + envelope
sinusoidal en la vida. ~16 partículas total, costo modesto.
App (gioser-web):
- pointerdown en canvas → si distancia al centro < click_radius_css_px →
impulse_click(). Touch y mouse vienen unificados por PointerEvent.
- mouseleave en canvas → release_tilt(). Sin set_target, el spring se
quedaría en la última posición — ahora vuelve al frente con rebote.
- position_tips ahora clampea raw_x/raw_y a [margin, viewport - taskbar -
margin] en CSS pixels. Los botones NUNCA salen del canvas ni cubren la
taskbar incluso en aspect extremos o tilt máximo.
- AppState + TaskbarState (RefCell): trackea drawers abiertos + activo.
open_tab/switch_tab/close_tab/home aplican mutación + sync().
- sync() rebuild de taskbar-list innerHTML por cada cambio de estado,
más swap de body classes + drawer .open classes.
- Click delegation en taskbar-list — un listener para todas las cajitas.
- Botón home con data-home en la barra (svg de casa) cierra todo y
limpia el taskbar.
- Escape también cierra el drawer activo.
- update_tilt_css ahora setea --tilt-z también — brand title roll
visible en el shake.
CSS:
- .drawer bottom: 52px (reserva taskbar).
- .taskbar full ancho fixed bottom, glass + gold border, scrollable horiz
para muchas cajitas.
- .taskbar-item con --task-color por elemento (aire/fuego/tierra/agua),
.active glow del color + inset border bottom.
- .taskbar-home con svg de casa dorado, hover glow.
- Responsive: taskbar 46px en mobile + ajustes.
- .brand transform agrega rotateZ(--tilt-z) para que el título vibre con
la chacana en click impulses.
Workspace verde + 18 tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Visual de la chacana retrabajado contra chakana.png de referencia:
- Sol detrás (gauss + corona, masked al interior de la chacana — sólo
asoma por la superficie de la cruz, no se cuela afuera).
- Doble outline dorado (línea principal + paralela offset 0.020), color
CHACANA_LINE pasa de cyan helado a dorado-ámbar del logo.
- Interior con niebla violeta-noche (u_dark_color) y rayos radiales
sutiles desde el centro, modulados por sin(t * 0.3).
- Aro doble exterior: ring fino interior + ring grueso con 4 grupos de
3 puntos cardinales (calculados angularmente, no rayos largos).
- WORLD_SCALE 1.45→1.05, MAX_TILT 35°→28° (más sólido, menos caricaturesco).
Título "GioSer" centrado dentro de la superficie de la chacana, sin
subtítulo. Se inclina junto con la chacana vía CSS perspective +
rotateX/rotateY desde u-tilt-x/y inyectadas cada frame por WASM.
Botones (4 tips):
- Reposicionados a `arm_extent * 1.32` (entre punta y aro grueso).
- Bigger: min-width 168px, glyph 54px, label Cinzel 0.95rem.
- Doble anillo en hover (::before con border + glow).
- Cuando un drawer se abre, fade-out de tips + canvas + brand.
Drawers MD (uno por elemento):
- `<aside class="drawer drawer-{element}">` con transform-origin desde
CSS vars (--origin-x/y) seteadas por WASM al click — crece desde la
posición exacta del botón hasta fullscreen en 700ms con cubic-bezier.
- Ambience por elemento: AIRE (radial drift), FUEGO (flicker keyframe),
AGUA (tide vertical), TIERRA (warm earth gradient).
- Cerrado con botón X, Escape o data-close-drawer.
- Carga MD desde ./md/{element}.md via spawn_local + Reader::open_url.
Pluma (visor MD agnóstico, dos crates nuevos):
- `crates/modules/pluma/pluma-md` — wrapper sobre pulldown-cmark 0.12.
API: to_html(), to_themed_html(md, theme) con sanitización del theme,
events() para AST stream. GFM completo. No deps web. 5 tests.
- `crates/modules/pluma/pluma-reader-web` — toma HtmlElement, expone
open_url async (fetch via wasm-bindgen-futures), render_md sync,
show_loading/show_error. NO inyecta CSS — el host estiliza
`.pluma-doc[data-pluma-theme="..."]` con sus colores.
CSS pluma-doc completo: h1/h2/h3, code/pre con border-left accent,
blockquote, tables, lists, hr gradient. Loader spinner + error state.
Placeholders en md/{aire,fuego,tierra,agua}.md con texto seed.
Workspace verde + 18 tests (6 geom + 4 palette + 3 physics + 5 pluma-md).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- gioser-geom: ChacanaSpec paramétrica con `steps` (default 2). bounding box
cuadrado (no cruz alargada), centro 6s×6s, brazos cortos de 2 niveles que
adelgazan hacia la punta. arm_extent = 0.65 con thickness=0.13.
- gioser-shaders: nubes FBM 5× más rápidas, 3 estratos de estrellas con
twinkle independiente, 4 meteoros procedurales con cola/cabeza y vida
cíclica. Chacana SDF rediseñada para 2 escalones, aro doble (interior +
exterior), 12 rayos angulares y 4 marcas cardinales animadas.
- gioser-canvas-web: MAX_TILT 22°→35°, WORLD_SCALE 0.92→1.45, spring
1.8 Hz / ζ=0.62 (más languido). uniform `u_center_half` agregado.
Las puntas DOM se desplazan visiblemente con el tilt.
- README: fix wasm-bindgen-cli 0.2.99 → 0.2.121 + `--locked`.
13 tests pasan (6 geom + 4 palette + 3 physics).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>