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
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "llimphi-widget-fab"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
publish.workspace = true
description = "llimphi-widget-fab — Floating Action Button: botón circular elevado (sombra E3), color de acento, hover lift sutil. Para la acción primaria de una página (compose, nuevo, +)."
[dependencies]
llimphi-ui = { workspace = true }
llimphi-theme = { workspace = true }
+150
View File
@@ -0,0 +1,150 @@
//! `llimphi-widget-fab` — Floating Action Button.
//!
//! Botón circular elevado pensado para la **acción primaria** de una
//! pantalla (componer, nuevo, +, capturar). Heredamos el patrón
//! Material/Flutter: rest sobre sombra E3, círculo del color `accent`,
//! glyph blanco centrado, sombra que **respira** al hover (sube a E5).
//!
//! La firma cinética viene del tween de fill+shadow vía `View::animated`,
//! con `animated_pop_in` para que la **entrada** del FAB sea el "pop" canónico
//! de Material (scale 0.6 → 1.0 + fade-in) en vez de aparecer de golpe.
#![forbid(unsafe_code)]
use llimphi_ui::Shadow;
use llimphi_ui::llimphi_layout::taffy::{
prelude::{length, Size, Style},
AlignItems, JustifyContent,
};
use llimphi_ui::llimphi_raster::peniko::Color;
use llimphi_ui::llimphi_text::Alignment;
use llimphi_ui::View;
use llimphi_theme::{elevation, motion, Theme};
/// Tamaño del FAB. El estándar Material es 56 px; el "mini" 40 px;
/// "extended" lleva texto + ícono y crece el ancho (no implementado
/// como variante separada para mantener la API mínima — quien lo
/// necesite usa `fab_styled`).
#[derive(Debug, Clone, Copy)]
pub enum FabSize {
Regular,
Mini,
}
impl FabSize {
pub fn px(self) -> f32 {
match self {
FabSize::Regular => 56.0,
FabSize::Mini => 40.0,
}
}
}
/// Paleta del FAB.
#[derive(Debug, Clone, Copy)]
pub struct FabPalette {
/// Fill del círculo (idle).
pub bg: Color,
/// Color del glyph.
pub fg: Color,
}
impl FabPalette {
pub fn from_theme(t: &Theme) -> Self {
Self {
bg: t.accent,
// Texto sobre accent: blanco (los accents del repo son todos
// suficientemente saturados para hacer contraste).
fg: Color::from_rgba8(255, 255, 255, 255),
}
}
}
/// Compone el FAB. `key` debe ser estable para que la anim de hover
/// quede vinculada al mismo nodo entre frames.
pub fn fab_view<Msg: Clone + 'static>(
glyph: impl Into<String>,
size: FabSize,
key: u64,
palette: &FabPalette,
on_click: Msg,
) -> View<Msg> {
let s = size.px();
let (a, blur, dy) = elevation::E3;
let shadow = Shadow {
color: Color::from_rgba8(0, 0, 0, a),
blur,
dx: 0.0,
dy,
spread: 0.0,
};
let glyph: String = glyph.into();
let aria = glyph.clone();
View::new(Style {
size: Size { width: length(s), height: length(s) },
align_items: Some(AlignItems::Center),
justify_content: Some(JustifyContent::Center),
..Default::default()
})
.fill(palette.bg)
.radius((s as f64) * 0.5)
.shadow(shadow)
.animated_pop_in(key, motion::FAST)
.text_aligned(
glyph,
(s * 0.42).round(),
palette.fg,
Alignment::Center,
)
// El glyph (+, ✎, etc.) no siempre es un buen nombre para el lector — el
// caller suele querer overridear con `.aria_label("Crear nota")`. Lo dejamos
// como fallback igual: mejor decir "más" que nada.
.role(llimphi_ui::Role::Button)
.aria_label(aria)
.on_click(on_click)
.cursor(llimphi_ui::Cursor::Pointer)
}
/// FAB con texto + glyph (Extended FAB de Material). Pildora ancha en
/// vez de círculo.
pub fn fab_extended<Msg: Clone + 'static>(
label: impl Into<String>,
key: u64,
palette: &FabPalette,
on_click: Msg,
) -> View<Msg> {
let label: String = label.into();
let h = 48.0_f32;
let (a, blur, dy) = elevation::E3;
let shadow = Shadow {
color: Color::from_rgba8(0, 0, 0, a),
blur,
dx: 0.0,
dy,
spread: 0.0,
};
View::new(Style {
size: Size {
width: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
height: length(h),
},
align_items: Some(AlignItems::Center),
justify_content: Some(JustifyContent::Center),
padding: llimphi_ui::llimphi_layout::taffy::Rect {
left: length(20.0_f32),
right: length(20.0_f32),
top: length(0.0_f32),
bottom: length(0.0_f32),
},
..Default::default()
})
.fill(palette.bg)
.radius((h as f64) * 0.5)
.shadow(shadow)
.animated_pop_in(key, motion::FAST)
.text_aligned(label.clone(), 14.0, palette.fg, Alignment::Center)
.role(llimphi_ui::Role::Button)
.aria_label(label)
.on_click(on_click)
.cursor(llimphi_ui::Cursor::Pointer)
}