refresh: stack al día (vello 0.7 / wgpu 27 / parley 0.6) + motor 3D voxel

Re-sincroniza las fuentes desde el monorepo (estaba en vello 0.5/wgpu 24 y con la
estructura vieja de eventloop) y suma el 3D:

- bump del workspace a vello 0.7 / wgpu 27 / parley 0.6, + accesskit 0.24 /
  accesskit_winit 0.33 / vello_hybrid 0.0.9.
- nuevos crates: llimphi-3d (voxels ray-march + mallas en un depth compartido,
  montable dentro de un View 2D vía set_viewport+scissor) y llimphi-voxel
  (world-gen, personajes, director de escenas) + shared/foreign-vox (puente .vox).
- README: sección "Not just 2D — a 3D voxel engine" + GIF (docs/llimphi_voxel.gif).
- excluido modules/allichay (arrastra deps fuera del alcance del front-door).
- cargo check --workspace: verde.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-06-18 14:40:00 +00:00
parent e74800d9da
commit ccab39f140
202 changed files with 44034 additions and 1811 deletions
+46 -1
View File
@@ -79,6 +79,29 @@ pub fn button_view<Msg: Clone + 'static>(
)
}
/// Tinte de la onda de ripple derivado de la paleta: el color de texto
/// (`fg`, normalmente claro sobre el botón dark) a alpha bajo, así contrasta
/// con el fondo y se adapta al theme sin añadir un campo a [`ButtonPalette`].
fn ripple_ink(palette: &ButtonPalette) -> Color {
let c = palette.fg.components;
Color { components: [c[0], c[1], c[2], 0.22], ..palette.fg }
}
/// Como [`button_view`] pero con feedback **ripple/InkWell**: al presionarlo
/// emite la salpicadura Material (círculo que se expande desde el punto del
/// tap y se desvanece, recortado al contorno del botón). `key` debe ser
/// **estable y único** entre los botones vivos del frame (índice del botón,
/// hash de su acción) — es lo que enlaza la onda retenida con este botón entre
/// frames. El tinte sale de la paleta ([`ripple_ink`]).
pub fn button_ripple<Msg: Clone + 'static>(
label: impl Into<String>,
key: u64,
palette: &ButtonPalette,
on_click: Msg,
) -> View<Msg> {
button_view(label, palette, on_click).ripple(key, ripple_ink(palette))
}
/// Variante con `Style` y alineación de texto explícitos — útil cuando
/// la app necesita un botón con dimensiones particulares o el texto a
/// la izquierda.
@@ -89,6 +112,11 @@ pub fn button_styled<Msg: Clone + 'static>(
palette: &ButtonPalette,
on_click: Msg,
) -> View<Msg> {
let label: String = label.into();
// Semántica accesible: rol Button + el texto visible como nombre. Si el
// caller le pasó un label vacío (botones puramente icónicos), igual sale
// como Button — lo correcto es agregarle un aria_label propio desde fuera.
let aria = label.clone();
// Gloss superior: gradient blanco alpha 28 → 0 sobre la mitad de
// arriba. `paint_with` corre entre el fill (que respeta hover_fill)
// y el texto, así que la luz se suma al color de base sin sustituirlo
@@ -119,6 +147,23 @@ pub fn button_styled<Msg: Clone + 'static>(
.with_stops([top, bot].as_slice());
scene.fill(Fill::NonZero, Affine::IDENTITY, &gradient, None, &rr);
})
.text_aligned(label.into(), 13.0, palette.fg, text_alignment)
.text_aligned(label, 13.0, palette.fg, text_alignment)
.role(llimphi_ui::Role::Button)
.aria_label(aria)
.on_click(on_click)
.cursor(llimphi_ui::Cursor::Pointer)
}
/// Como [`button_styled`] pero con feedback **ripple/InkWell** (ver
/// [`button_ripple`] para la semántica de `key`).
pub fn button_styled_ripple<Msg: Clone + 'static>(
label: impl Into<String>,
key: u64,
style: Style,
text_alignment: Alignment,
palette: &ButtonPalette,
on_click: Msg,
) -> View<Msg> {
button_styled(label, style, text_alignment, palette, on_click)
.ripple(key, ripple_ink(palette))
}