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-chip"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
publish.workspace = true
description = "llimphi-widget-chip — chip compacto (filter / choice / input) con estado opcional seleccionado y x removible. Para tags, filtros, multi-select compacto."
[dependencies]
llimphi-ui = { workspace = true }
llimphi-theme = { workspace = true }
+189
View File
@@ -0,0 +1,189 @@
//! `llimphi-widget-chip` — chip compacto con cuatro sabores: **filter**
//! (toggle binario), **choice** (radio dentro de un grupo), **input**
//! (etiqueta removible con × al final) y **assist** (chip-acción con
//! ícono opcional).
//!
//! Forma: rectángulo redondeado bien pegado (radius pill), padding
//! horizontal 10/4, alto 24 px. Tema-consciente: cuando `selected`,
//! pinta `accent` apenas tinted (alpha bajo) — sobrio, no chillón.
//!
//! Como toda la elegancia de Llimphi, hereda de `llimphi-theme::motion`
//! para la transición de fill al togglear (animación implícita via
//! `View::animated(key, motion::MICRO)`).
#![forbid(unsafe_code)]
use llimphi_ui::llimphi_layout::taffy::{
prelude::{auto, length, FlexDirection, Size, Style},
AlignItems, JustifyContent, Rect,
};
use llimphi_ui::llimphi_raster::peniko::Color;
use llimphi_ui::llimphi_text::Alignment;
use llimphi_ui::View;
use llimphi_theme::{motion, radius, Theme};
/// Paleta del chip — tres slots: idle, selected, fg.
#[derive(Debug, Clone, Copy)]
pub struct ChipPalette {
pub bg_idle: Color,
pub bg_selected: Color,
pub fg_idle: Color,
pub fg_selected: Color,
pub border: Color,
}
impl ChipPalette {
pub fn from_theme(t: &Theme) -> Self {
// El selected es el accent atenuado hacia el fondo —"tinte", no
// bloque sólido—. Calculado en sRGB-ish: `accent · 0.32 + bg · 0.68`.
let a = t.accent.components;
let b = t.bg_panel.components;
let mix = Color {
components: [
a[0] * 0.32 + b[0] * 0.68,
a[1] * 0.32 + b[1] * 0.68,
a[2] * 0.32 + b[2] * 0.68,
1.0,
],
..t.accent
};
Self {
bg_idle: t.bg_button,
bg_selected: mix,
fg_idle: t.fg_text,
fg_selected: t.fg_text,
border: t.border,
}
}
}
/// Sabor del chip — decide cómo se interpreta el `selected` y si lleva
/// botón × removible.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChipKind {
/// Toggle binario (selected ↔ no). Usado en `FilterChip` de Material.
Filter,
/// Radio dentro de un grupo (selected = exclusive). Visualmente igual
/// a Filter; la diferencia está en el caller que mantiene 1 seleccionado.
Choice,
/// Etiqueta con × final que dispara `on_remove`. Para tags, multi-select
/// presentado como contenedor de chips.
Input,
/// Acción rápida (no togglea); selected siempre falso.
Assist,
}
/// Chip base — devuelve el view con anim implícita de fill por estado.
/// `key` debe ser estable entre frames del mismo chip (idx + grupo).
pub fn chip_view<Msg: Clone + 'static>(
label: impl Into<String>,
kind: ChipKind,
selected: bool,
key: u64,
palette: &ChipPalette,
on_click: Msg,
on_remove: Option<Msg>,
) -> View<Msg> {
let bg = if selected { palette.bg_selected } else { palette.bg_idle };
let fg = if selected { palette.fg_selected } else { palette.fg_idle };
let label: String = label.into();
let aria = label.clone();
let mut children = vec![View::new(Style {
size: Size { width: auto(), height: auto() },
..Default::default()
})
.text_aligned(label, 12.0, fg, Alignment::Center)];
if let (ChipKind::Input, Some(rm)) = (kind, on_remove) {
// ×: glifo pequeño a la derecha con on_click propio. No es
// botón nested (View no soporta nested on_click), así que es
// un nodo hermano con on_click separado dentro del mismo chip
// — el árbitro de hit-test elige el más interno.
children.push(
View::new(Style {
size: Size { width: length(14.0_f32), height: length(14.0_f32) },
margin: Rect {
left: length(6.0_f32),
right: length(0.0_f32),
top: length(0.0_f32),
bottom: length(0.0_f32),
},
align_items: Some(AlignItems::Center),
justify_content: Some(JustifyContent::Center),
..Default::default()
})
.radius(7.0)
.hover_fill(palette.border)
.text_aligned("×".to_string(), 12.0, fg, Alignment::Center)
.on_click(rm)
.cursor(llimphi_ui::Cursor::Pointer),
);
}
View::new(Style {
flex_direction: FlexDirection::Row,
align_items: Some(AlignItems::Center),
padding: Rect {
left: length(10.0_f32),
right: length(10.0_f32),
top: length(0.0_f32),
bottom: length(0.0_f32),
},
size: Size { width: auto(), height: length(24.0_f32) },
..Default::default()
})
.fill(bg)
.radius(radius::XL)
.border(1.0, palette.border)
.animated(key, motion::MICRO)
.children(children)
// Filter chips se reportan como botones de toggle (pressed = selected);
// los input/assist chips son botones plain. AccessKit anuncia el estado
// de toggle al lector, así "está seleccionado / no seleccionado" sale solo.
.role(llimphi_ui::Role::Button)
.aria_label(aria)
.aria_pressed(selected)
.on_click(on_click)
.cursor(llimphi_ui::Cursor::Pointer)
}
/// Atajo: chip filter (toggle).
pub fn filter_chip<Msg: Clone + 'static>(
label: impl Into<String>,
selected: bool,
key: u64,
palette: &ChipPalette,
on_toggle: Msg,
) -> View<Msg> {
chip_view(label, ChipKind::Filter, selected, key, palette, on_toggle, None)
}
/// Atajo: chip input (removible).
pub fn input_chip<Msg: Clone + 'static>(
label: impl Into<String>,
key: u64,
palette: &ChipPalette,
on_click: Msg,
on_remove: Msg,
) -> View<Msg> {
chip_view(
label,
ChipKind::Input,
false,
key,
palette,
on_click,
Some(on_remove),
)
}
/// Atajo: chip assist (acción).
pub fn assist_chip<Msg: Clone + 'static>(
label: impl Into<String>,
key: u64,
palette: &ChipPalette,
on_click: Msg,
) -> View<Msg> {
chip_view(label, ChipKind::Assist, false, key, palette, on_click, None)
}