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-scaffold"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
publish.workspace = true
description = "llimphi-widget-scaffold — chasis de página estilo Flutter Scaffold: app bar opcional arriba, bottom bar opcional abajo, body que ocupa el resto, FAB anclado bottom-end opcional, drawers laterales opcionales (slide in)."
[dependencies]
llimphi-ui = { workspace = true }
llimphi-theme = { workspace = true }
+176
View File
@@ -0,0 +1,176 @@
//! `llimphi-widget-scaffold` — chasis de página.
//!
//! Inspiración Flutter `Scaffold`/Material 3 layout. Compone un layout
//! de página común:
//!
//! ```text
//! ┌──────────────────────────────┐
//! │ app bar (opcional) │ ← 48 px
//! ├──────────────────────────────┤
//! │ │
//! │ body (flex-grow 1) │
//! │ ╭──╮│
//! │ │+ ││ ← FAB opcional (bottom-end)
//! │ ╰──╯│
//! ├──────────────────────────────┤
//! │ bottom bar (opcional) │ ← 56 px
//! └──────────────────────────────┘
//! ```
//!
//! Los drawers laterales se ofrecen como **overlays** (la app los pasa
//! por `view_overlay`, no por el body — así no roban el layout cuando
//! están cerrados). Este widget sólo aporta el chasis central; los
//! drawers son responsabilidad de quien los abre.
#![forbid(unsafe_code)]
use llimphi_ui::llimphi_layout::taffy::{
prelude::{length, percent, FlexDirection, Size, Style},
AlignItems, JustifyContent, Position,
};
use llimphi_ui::llimphi_raster::peniko::Color;
use llimphi_ui::View;
use llimphi_theme::Theme;
#[derive(Debug, Clone, Copy)]
pub struct ScaffoldPalette {
pub bg: Color,
}
impl ScaffoldPalette {
pub fn from_theme(t: &Theme) -> Self {
Self { bg: t.bg_app }
}
}
/// Opciones del scaffold — todas las superficies son opcionales (un
/// scaffold con sólo `body` es válido y degenera en `View` con bg).
pub struct ScaffoldSpec<Msg: Clone + 'static> {
pub app_bar: Option<View<Msg>>,
pub body: View<Msg>,
pub bottom_bar: Option<View<Msg>>,
pub fab: Option<View<Msg>>,
}
/// Compone el scaffold. Llamado típicamente desde el `view(model)` de la
/// app como root. Para drawers, pasarlos por `view_overlay`.
pub fn scaffold_view<Msg: Clone + 'static>(
spec: ScaffoldSpec<Msg>,
palette: &ScaffoldPalette,
) -> View<Msg> {
let mut col_children: Vec<View<Msg>> = Vec::with_capacity(3);
if let Some(bar) = spec.app_bar {
col_children.push(
View::new(Style {
size: Size { width: percent(1.0_f32), height: length(48.0_f32) },
flex_shrink: 0.0,
..Default::default()
})
.children(vec![bar]),
);
}
// Body con FAB anclado.
let mut body_layer_children: Vec<View<Msg>> = vec![spec.body];
if let Some(f) = spec.fab {
body_layer_children.push(
View::new(Style {
position: Position::Absolute,
inset: llimphi_ui::llimphi_layout::taffy::Rect {
left: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
right: length(16.0_f32),
top: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
bottom: length(16.0_f32),
},
..Default::default()
})
.children(vec![f]),
);
}
let body_layer = View::new(Style {
size: Size {
width: percent(1.0_f32),
height: llimphi_ui::llimphi_layout::taffy::prelude::Dimension::auto(),
},
flex_grow: 1.0,
..Default::default()
})
.children(body_layer_children);
col_children.push(body_layer);
if let Some(bar) = spec.bottom_bar {
col_children.push(
View::new(Style {
size: Size { width: percent(1.0_f32), height: length(56.0_f32) },
flex_shrink: 0.0,
..Default::default()
})
.children(vec![bar]),
);
}
View::new(Style {
flex_direction: FlexDirection::Column,
size: Size { width: percent(1.0_f32), height: percent(1.0_f32) },
..Default::default()
})
.fill(palette.bg)
.children(col_children)
}
/// App bar estándar — barra superior 48 px con título a la izquierda y
/// slot de acciones a la derecha. El caller pasa el `View` de las
/// acciones (botones de ícono típicamente).
pub fn app_bar_view<Msg: Clone + 'static>(
title: impl Into<String>,
actions: Vec<View<Msg>>,
palette: &ScaffoldPalette,
theme: &Theme,
) -> View<Msg> {
use llimphi_ui::llimphi_text::Alignment;
let _ = palette;
let title_view = View::new(Style {
size: Size {
width: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
height: percent(1.0_f32),
},
flex_grow: 1.0,
align_items: Some(AlignItems::Center),
justify_content: Some(JustifyContent::FlexStart),
padding: llimphi_ui::llimphi_layout::taffy::Rect {
left: length(16.0_f32),
right: length(0.0_f32),
top: length(0.0_f32),
bottom: length(0.0_f32),
},
..Default::default()
})
.text_aligned(title.into(), 16.0, theme.fg_text, Alignment::Start)
.bold();
let actions_view = View::new(Style {
flex_direction: FlexDirection::Row,
size: Size {
width: llimphi_ui::llimphi_layout::taffy::prelude::auto(),
height: percent(1.0_f32),
},
align_items: Some(AlignItems::Center),
gap: Size { width: length(4.0_f32), height: length(0.0_f32) },
padding: llimphi_ui::llimphi_layout::taffy::Rect {
left: length(0.0_f32),
right: length(8.0_f32),
top: length(0.0_f32),
bottom: length(0.0_f32),
},
..Default::default()
})
.children(actions);
View::new(Style {
flex_direction: FlexDirection::Row,
size: Size { width: percent(1.0_f32), height: percent(1.0_f32) },
align_items: Some(AlignItems::Center),
..Default::default()
})
.fill(theme.bg_panel)
.children(vec![title_view, actions_view])
}