chore: refresco desde el monorepo (pin tawasuyu.git v0.2.0)
Regenerado con scripts/actualizar-standalone.py: código del dominio al día, git-deps repineadas a v0.2.0 y doble-fuente resuelta con [patch] al source git. cargo check --workspace verde.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
> Visualización agnóstica del backend. El "tercer ojo" del monorepo.
|
||||
|
||||

|
||||
|
||||
Pineal es un catálogo de painters especializados — cartesiano, polar,
|
||||
mesh, treemap, phosphor, flow, heatmap, stream, financial, hexbin,
|
||||
contour y bars — sobre una **única abstracción de pintura**, el trait
|
||||
@@ -116,8 +118,8 @@ pasada vello hermana) cuando hagan falta etiquetas.
|
||||
|
||||
## Consideraciones
|
||||
|
||||
- pineal **no calcula** — sólo dibuja. Para correr una simulación hablás
|
||||
con `dominium`, `tinkuy`, `cosmos`, etc., y le pasás el resultado.
|
||||
- pineal **no calcula** — sólo dibuja. Para correr una simulación hablas
|
||||
con `dominium`, `tinkuy`, `cosmos`, etc., y le pasas el resultado.
|
||||
- El export a SVG es vector real (no captura de píxeles). El PNG es un
|
||||
rasterizador software diminuto — sin stack gráfico nativo. El texto se
|
||||
omite en PNG y en el camino GPU (usar SVG o una pasada vello hermana).
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
> Backend-agnostic visualization. The "third eye" of the monorepo.
|
||||
|
||||

|
||||
|
||||
Pineal is a catalog of specialized painters — cartesian, polar, mesh,
|
||||
treemap, phosphor, flow, heatmap, stream, financial, hexbin, contour and
|
||||
bars — over a **single painter abstraction**, the `Canvas` trait. Any
|
||||
|
||||
@@ -22,7 +22,7 @@ cargo run --release -p pineal-stream-demo
|
||||
|
||||
## Crateskuna
|
||||
|
||||
Tukuy crates yachachiyninwan iskay versionkunapi: [`pineal-core`](pineal-core/README.md) escena modelo, [`pineal-render`](pineal-render/README.md) Llimphi rikuchikuy, [`pineal-{cartesian,polar,mesh,treemap,phosphor,flow,heatmap,stream,financial,umbrella}`](pineal-cartesian/README.md) sapanka layakuna, [`pineal-export`](pineal-export/README.md) PNG/SVG/GIF qatinapaq, [`pineal-{demo,financial-demo,phosphor-demo,stream-demo}`](pineal-demo/README.md) muestrakuna.
|
||||
Tukuy crates yachachiyninwan iskay versionkunapi: [`pineal-core`](pineal-core/README.md) escena modelo, [`pineal-render`](pineal-render/README.md) Llimphi rikuchikuy, [`pineal-{cartesian,polar,mesh,treemap,phosphor,flow,heatmap,stream,financial,umbrella}`](pineal-cartesian/README.md) sapanka layakuna, [`pineal-export`](pineal-export/README.md) PNG/SVG/GIF qatinapaq, [`pineal-{demo,financial-demo,phosphor-demo,stream-demo}`](demos/pineal-demo/README.md) muestrakuna.
|
||||
|
||||
## Yuyaykunaq
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# pineal-bars-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
El painter de barras del catálogo, en sus cinco modos, sobre una grilla estática:
|
||||
|
||||
- **Columnas** (vertical simple, con un valor negativo para mostrar el
|
||||
baseline).
|
||||
- **Barras** (horizontal simple).
|
||||
- **Agrupadas** (dos series clustered por categoría).
|
||||
- **Apiladas** (segmentos sobre un baseline común).
|
||||
- **Histograma** (muestra gaussiana sintética bineada).
|
||||
|
||||
Datos 100 % deterministas (sin `Date::now`/random): la muestra del
|
||||
histograma sale de un LCG sembrado con constante. Es un showcase, sin
|
||||
animación. Las etiquetas de eje no las pinta el painter (regla del
|
||||
SDD: el texto va aparte) — aquí los títulos viven en Views hermanas.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-bars-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-bars-demo
|
||||
|
||||
The catalog's bar painter in its five modes, over a static grid:
|
||||
|
||||
- **Columns** (simple vertical, with a negative value to show the baseline).
|
||||
- **Bars** (simple horizontal).
|
||||
- **Grouped** (two series clustered per category).
|
||||
- **Stacked** and the remaining variants.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -11,7 +11,7 @@
|
||||
//! Datos 100 % deterministas (sin `Date::now`/random): la muestra del
|
||||
//! histograma sale de un LCG sembrado con constante. Es un showcase, sin
|
||||
//! animación. Las etiquetas de eje no las pinta el painter (regla del
|
||||
//! SDD: el texto va aparte) — acá los títulos viven en Views hermanas.
|
||||
//! SDD: el texto va aparte) — aquí los títulos viven en Views hermanas.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# pineal-contour-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Campo escalar con 8 isolíneas + heatmap base.
|
||||
|
||||
Renderiza primero el heatmap Viridis del campo (para contexto), y
|
||||
encima 8 isolíneas extraídas por marching squares con gradiente
|
||||
azul→rojo. Matriz 64×48; el campo es
|
||||
`sin(x · 0.4 - t · 0.1) + cos(y · 0.4 + t · 0.07)` con un tick lento
|
||||
para que se vea la deformación.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-contour-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
# pineal-contour-demo
|
||||
|
||||
A scalar field with 8 isolines plus a base heatmap.
|
||||
|
||||
It first renders the field's Viridis heatmap (for context), and over it 8 isolines
|
||||
extracted by marching squares with a blue→red gradient. A 64×48 matrix; the field
|
||||
is `sin(x · 0.4 - t · 0.1) + cos(y · 0.4 + t · 0.07)` with a slow tick.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-demo
|
||||
|
||||
> Demo gallery del catálogo de [pineal](../README.md).
|
||||
> Demo gallery del catálogo de [pineal](../../README.md).
|
||||
|
||||
Binario que muestra todos los backends (`cartesian`, `polar`, `mesh`, `treemap`, `flow`, `heatmap`, `umbrella`) en una grid Llimphi. Click en una demo abre la vista completa. Sirve como **regression visual**: si rompés un backend, la demo lo grita.
|
||||
Binario que muestra todos los backends (`cartesian`, `polar`, `mesh`, `treemap`, `flow`, `heatmap`, `umbrella`) en una grid Llimphi. Click en una demo abre la vista completa. Sirve como **regression visual**: si rompes un backend, la demo lo grita.
|
||||
|
||||
## Uso
|
||||
|
||||
@@ -13,4 +13,4 @@ cargo run --release -p pineal-demo
|
||||
## Deps
|
||||
|
||||
- Todos los backends de pineal
|
||||
- [`llimphi-ui`](../../../02_ruway/llimphi/)
|
||||
- [`llimphi-ui`](../../../../02_ruway/llimphi/)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# pineal-demo
|
||||
|
||||
> Catalog demo gallery for [pineal](../README.md).
|
||||
> Catalog demo gallery for [pineal](../../README.md).
|
||||
|
||||
Binary that shows all backends (`cartesian`, `polar`, `mesh`, `treemap`, `flow`, `heatmap`, `umbrella`) in a Llimphi grid. Click on a demo opens the full view. Works as **visual regression**: if you break a backend, the demo screams.
|
||||
|
||||
@@ -13,4 +13,4 @@ cargo run --release -p pineal-demo
|
||||
## Deps
|
||||
|
||||
- All pineal backends
|
||||
- [`llimphi-ui`](../../../02_ruway/llimphi/)
|
||||
- [`llimphi-ui`](../../../../02_ruway/llimphi/)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-financial-demo
|
||||
|
||||
> Demo del backend financiero de [pineal](../README.md).
|
||||
> Demo del backend financiero de [pineal](../../README.md).
|
||||
|
||||
Carga bars OHLCV sintéticos (o de un CSV pasado por CLI), aplica overlays (SMA, EMA, Bollinger) y los muestra. Si pasás un símbolo y tenés conexión, intenta cargar bars desde un endpoint público — pero por defecto opera offline con datos generados.
|
||||
Carga bars OHLCV sintéticos (o de un CSV pasado por CLI), aplica overlays (SMA, EMA, Bollinger) y los muestra. Si pasas un símbolo y tienes conexión, intenta cargar bars desde un endpoint público — pero por defecto opera offline con datos generados.
|
||||
|
||||
## Uso
|
||||
|
||||
@@ -13,4 +13,4 @@ cargo run --release -p pineal-financial-demo -- --csv bars.csv
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-financial`](../pineal-financial/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-financial`](../../pineal-financial/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# pineal-financial-demo
|
||||
|
||||
> Financial backend demo for [pineal](../README.md).
|
||||
> Financial backend demo for [pineal](../../README.md).
|
||||
|
||||
Loads synthetic OHLCV bars (or from a CSV passed via CLI), applies overlays (SMA, EMA, Bollinger) and renders them. If you pass a symbol with connectivity, it tries to load bars from a public endpoint — but by default it works offline with generated data.
|
||||
|
||||
@@ -13,4 +13,4 @@ cargo run --release -p pineal-financial-demo -- --csv bars.csv
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-financial`](../pineal-financial/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-financial`](../../pineal-financial/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# pineal-flow-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Sankey de presupuesto familiar.
|
||||
|
||||
4 fuentes de ingreso → 5 categorías de gasto → 1 nodo de ahorro.
|
||||
El algoritmo de layout (longest-path + barycenter) ubica los
|
||||
nodos en columnas y minimiza cruces; las bandas se tesselan con
|
||||
curva S (smoothstep) y se rendean como triangle strips.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-flow-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-flow-demo
|
||||
|
||||
A Sankey of a household budget.
|
||||
|
||||
Four income sources → five spending categories → one savings node. The layout
|
||||
algorithm (longest-path + barycenter) places the nodes in columns and minimizes
|
||||
crossings; the bands are tessellated with an S curve (smoothstep) and rendered as
|
||||
triangle strips.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -21,3 +21,11 @@ pineal-contour = { path = "../../pineal-contour" }
|
||||
pineal-flow = { path = "../../pineal-flow" }
|
||||
pineal-mesh = { path = "../../pineal-mesh" }
|
||||
pineal-bars = { path = "../../pineal-bars" }
|
||||
|
||||
[dev-dependencies]
|
||||
# Sólo para los examples headless (`pantallazo_pineal`, `pineal_showreel`).
|
||||
pollster = { workspace = true }
|
||||
png = { workspace = true }
|
||||
# Beats animados extra del showreel (no los usa la galería estática).
|
||||
pineal-financial = { path = "../../pineal-financial" }
|
||||
pineal-cartesian = { path = "../../pineal-cartesian" }
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# pineal-galeria-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Galería estática de TODO el catálogo de painters.
|
||||
|
||||
Una sola ventana con una grilla 3×3 de tiles; cada tile pinta un
|
||||
painter distinto de pineal con datos sintéticos deterministas (sin
|
||||
timers, sin RNG de sistema): cartesian (sinusoide a mano), polar
|
||||
(pie/donut y radar), treemap, heatmap, hexbin, contour, flow (Sankey)
|
||||
y mesh (grafo force-directed pre-relajado).
|
||||
|
||||
Los painters animados (phosphor, stream) y el financial tienen su
|
||||
propio demo en vivo y quedan FUERA — la galería es un showcase
|
||||
estático. El tile #9 es un cartesiano extra (segunda señal) para
|
||||
completar la grilla.
|
||||
|
||||
Cada tile reusa la construcción de datos de su demo suelto en
|
||||
`pineal-<painter>-demo`, así que las firmas son las reales. Cada
|
||||
closure de `paint_with` captura SUS datos por `move`.
|
||||
|
||||
Cableado de UI: barra de menú principal mínima (Archivo / Ver). Los
|
||||
tiles son canvas estáticos sin edición ni clipboard.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-galeria-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-galeria-demo
|
||||
|
||||
A static gallery of the WHOLE painter catalog.
|
||||
|
||||
One window with a 3×3 grid of tiles; each tile paints a different pineal painter
|
||||
with deterministic synthetic data (no timers, no system RNG): cartesian (a
|
||||
hand-made sinusoid), polar (pie/donut and radar), treemap, heatmap, hexbin,
|
||||
contour, flow (Sankey) and the rest.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -0,0 +1,159 @@
|
||||
//! Pantallazo headless de `pineal` — la galería completa de painters.
|
||||
//!
|
||||
//! Monta la **view real** de `pineal-galeria-demo` (grilla de 11 tiles:
|
||||
//! cartesian, pie/donut, radar, treemap, heatmap, hexbin, contour, sankey,
|
||||
//! mesh force-directed, bars e histograma — todos con datos sintéticos
|
||||
//! deterministas, sin reloj ni RNG de sistema) reutilizando el `init` y el
|
||||
//! `view` del demo vía `#[path]`, con un `Handle::for_test()` (no hay
|
||||
//! event loop).
|
||||
//!
|
||||
//! Pinta a una textura wgpu sin ventana y vuelca PNG (mismo patrón que
|
||||
//! `tullpu-app-llimphi/examples/pantallazo_tullpu.rs`).
|
||||
//!
|
||||
//! `cargo run -p pineal-galeria-demo --example pantallazo_pineal --release -- [out.png]`
|
||||
#![allow(dead_code)]
|
||||
|
||||
// El demo es un crate binario sin lib: incluimos su `main.rs` real por
|
||||
// `#[path]` para montar exactamente la misma view que pinta la ventana.
|
||||
#[path = "../src/main.rs"]
|
||||
mod galeria;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
|
||||
use llimphi_theme::Theme;
|
||||
use llimphi_ui::llimphi_hal::{wgpu, Hal};
|
||||
use llimphi_ui::llimphi_layout::taffy;
|
||||
use llimphi_ui::llimphi_layout::LayoutTree;
|
||||
use llimphi_ui::llimphi_raster::peniko::Color;
|
||||
use llimphi_ui::llimphi_raster::{vello, Renderer};
|
||||
use llimphi_ui::llimphi_text::Typesetter;
|
||||
use llimphi_ui::{measure_text_node, mount, paint, App, Handle};
|
||||
|
||||
use crate::galeria::GaleriaDemo;
|
||||
|
||||
const W: u32 = 1280;
|
||||
const H: u32 = 860;
|
||||
const FMT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
|
||||
|
||||
fn main() {
|
||||
let out = std::env::args()
|
||||
.nth(1)
|
||||
.unwrap_or_else(|| "/tmp/shots/pineal.png".to_string());
|
||||
if let Some(dir) = std::path::Path::new(&out).parent() {
|
||||
std::fs::create_dir_all(dir).ok();
|
||||
}
|
||||
|
||||
// El init real del demo: relaja el grafo del tile mesh, bina el hexbin
|
||||
// y computa el campo escalar. El handle de test descarta dispatches.
|
||||
let handle: Handle<galeria::Msg> = Handle::for_test();
|
||||
let model = GaleriaDemo::init(&handle);
|
||||
let root = GaleriaDemo::view(&model);
|
||||
|
||||
// view → layout → scene (misma secuencia que el eventloop real).
|
||||
let mut layout = LayoutTree::new();
|
||||
let mounted = mount(&mut layout, root);
|
||||
let mut ts = Typesetter::new();
|
||||
let computed = {
|
||||
let tmap = &mounted.text_measures;
|
||||
layout
|
||||
.compute_with_measure(mounted.root, (W as f32, H as f32), |nid, known, avail| {
|
||||
match tmap.get(&nid) {
|
||||
Some(tm) => measure_text_node(&mut ts, tm, known, avail),
|
||||
None => taffy::Size::ZERO,
|
||||
}
|
||||
})
|
||||
.expect("layout")
|
||||
};
|
||||
let mut scene = vello::Scene::new();
|
||||
paint(&mut scene, &mounted, &computed, &mut ts, None, None);
|
||||
|
||||
let hal = pollster::block_on(Hal::new(None)).expect("hal");
|
||||
let mut renderer = Renderer::new(&hal).expect("renderer");
|
||||
let target = hal.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("pantallazo-pineal"),
|
||||
size: wgpu::Extent3d {
|
||||
width: W,
|
||||
height: H,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: FMT,
|
||||
usage: wgpu::TextureUsages::STORAGE_BINDING
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
| wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = target.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
// Mismo fondo que el init del demo (Theme::dark) — el campo `theme`
|
||||
// del Model es privado al módulo incluido.
|
||||
let [r, g, b, _] = Theme::dark().bg_app.components;
|
||||
let bg = Color::from_rgba8((r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8, 255);
|
||||
renderer
|
||||
.render_to_view(&hal, &scene, &view, W, H, bg)
|
||||
.expect("render_to_view");
|
||||
|
||||
write_png(&hal, &target, &out);
|
||||
eprintln!("pantallazo_pineal: escrito {out} ({W}x{H})");
|
||||
}
|
||||
|
||||
/// Lee la textura a CPU y la vuelca como PNG RGBA8.
|
||||
fn write_png(hal: &Hal, target: &wgpu::Texture, path: &str) {
|
||||
let unpadded = (W * 4) as usize;
|
||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
|
||||
let padded = unpadded.div_ceil(align) * align;
|
||||
let buf = hal.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("readback"),
|
||||
size: (padded * H as usize) as u64,
|
||||
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let mut enc = hal
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
enc.copy_texture_to_buffer(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: target,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &buf,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(padded as u32),
|
||||
rows_per_image: Some(H),
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: W,
|
||||
height: H,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
hal.queue.submit(std::iter::once(enc.finish()));
|
||||
let slice = buf.slice(..);
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
slice.map_async(wgpu::MapMode::Read, move |r| {
|
||||
let _ = tx.send(r);
|
||||
});
|
||||
let _ = hal.device.poll(wgpu::PollType::wait_indefinitely());
|
||||
rx.recv().unwrap().unwrap();
|
||||
let data = slice.get_mapped_range();
|
||||
let mut pixels = Vec::with_capacity((W * H * 4) as usize);
|
||||
for row in 0..H as usize {
|
||||
let s = row * padded;
|
||||
pixels.extend_from_slice(&data[s..s + unpadded]);
|
||||
}
|
||||
drop(data);
|
||||
buf.unmap();
|
||||
let file = File::create(path).expect("png");
|
||||
let mut enc = png::Encoder::new(BufWriter::new(file), W, H);
|
||||
enc.set_color(png::ColorType::Rgba);
|
||||
enc.set_depth(png::BitDepth::Eight);
|
||||
let mut w = enc.write_header().unwrap();
|
||||
w.write_image_data(&pixels).unwrap();
|
||||
}
|
||||
@@ -0,0 +1,819 @@
|
||||
//! **Showreel** de `pineal` — montaje de tipos de gráfico para el README
|
||||
//! del standalone (audiencia r/rust). NO es eye-candy abstracto: cada beat
|
||||
//! invoca un **painter REAL** del catálogo de pineal (`paint_bars`,
|
||||
//! `paint_heatmap`, `paint_contours`, `paint_pie`, `paint_radar`,
|
||||
//! `paint_treemap`, `paint_hexbin`, `paint_sankey`, el grafo force-directed
|
||||
//! de `pineal-mesh` y los candlesticks de `pineal-financial`) sobre el
|
||||
//! `Canvas` de `pineal-render` (backend vello/wgpu de Llimphi).
|
||||
//!
|
||||
//! El render es **headless y determinista** (sin reloj, sin runtime, sin
|
||||
//! winit): frame `i` de `N` → `t = i/(N-1)` → `vello::Scene` → wgpu → PNG.
|
||||
//! El stage central cruza de un gráfico al siguiente con **cross-fade**
|
||||
//! (capas vello con alpha), y los datos de cada gráfico se derivan de su
|
||||
//! progreso local para que *animen* mientras están en pantalla. Cold-open
|
||||
//! sobrio (trazo bezier draw-on) + wordmark final **"pineal"** con
|
||||
//! subtítulo "data visualization, in Rust".
|
||||
//!
|
||||
//! ```text
|
||||
//! cargo run -p pineal-galeria-demo --example pineal_showreel --release -- \
|
||||
//! [out_dir] [n_frames] [W] [H]
|
||||
//! ```
|
||||
//! Defaults: `out_dir=showreel_frames_pineal`, `n_frames=300`, `W=1600`, `H=900`.
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::BufWriter;
|
||||
|
||||
use llimphi_ui::llimphi_hal::{wgpu, Hal};
|
||||
use llimphi_ui::llimphi_raster::kurbo::{Affine, BezPath, Circle, Point as KPoint, Stroke};
|
||||
use llimphi_ui::llimphi_raster::peniko::{self, Color as PColor, Fill, Gradient};
|
||||
use llimphi_ui::llimphi_raster::{vello, Renderer};
|
||||
use llimphi_ui::llimphi_text::{
|
||||
draw_layout_brush_xf, measurement, Alignment, Typesetter,
|
||||
};
|
||||
|
||||
use pineal_bars::{paint_bars, Bar, BarStyle, Histogram};
|
||||
use pineal_cartesian::{ChartViewport, CoordinateSystem};
|
||||
use pineal_contour::paint_contours;
|
||||
use pineal_financial::{paint_candlesticks, CandlestickStyle, OhlcBuffer};
|
||||
use pineal_flow::{compute_layout, paint_sankey, SankeyLink, SankeyNode};
|
||||
use pineal_heatmap::{paint as paint_heatmap, HeatmapMatrix, Ramp};
|
||||
use pineal_mesh::{EdgeBuffer, ForceLayout, ForceParams, NodeBuffer};
|
||||
use pineal_polar::{paint_pie, paint_radar, Slice};
|
||||
use pineal_render::{Canvas as _, Color, Point, Rect, SceneCanvas, StrokeStyle};
|
||||
use pineal_treemap::{paint_treemap, Tile};
|
||||
|
||||
const FMT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm;
|
||||
|
||||
// ───────────────────────── utilidades de tiempo / color ─────────────────────────
|
||||
|
||||
/// Reescala `t` desde el subintervalo `[lo,hi]` a `[0,1]`, clampado.
|
||||
fn seg(t: f32, lo: f32, hi: f32) -> f32 {
|
||||
((t - lo) / (hi - lo)).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
fn lerp(a: f64, b: f64, t: f64) -> f64 {
|
||||
a + (b - a) * t
|
||||
}
|
||||
|
||||
fn ease_in_out_cubic(t: f32) -> f32 {
|
||||
if t < 0.5 {
|
||||
4.0 * t * t * t
|
||||
} else {
|
||||
let f = 2.0 * t - 2.0;
|
||||
0.5 * f * f * f + 1.0
|
||||
}
|
||||
}
|
||||
|
||||
fn ease_out_cubic(t: f32) -> f32 {
|
||||
let f = t - 1.0;
|
||||
f * f * f + 1.0
|
||||
}
|
||||
|
||||
fn ease_out_back(t: f32) -> f32 {
|
||||
let c1 = 1.70158_f32;
|
||||
let c3 = c1 + 1.0;
|
||||
let f = t - 1.0;
|
||||
1.0 + c3 * f * f * f + c1 * f * f
|
||||
}
|
||||
|
||||
/// `PColor` (peniko) con alpha sobreescrito.
|
||||
fn palpha(c: PColor, a: f32) -> PColor {
|
||||
let [r, g, b, _] = c.components;
|
||||
PColor::new([r, g, b, a.clamp(0.0, 1.0)])
|
||||
}
|
||||
|
||||
// ───────────────────────── paleta del showreel ─────────────────────────
|
||||
|
||||
struct Skin {
|
||||
bg: PColor,
|
||||
panel_hi: PColor,
|
||||
panel_lo: PColor,
|
||||
border: PColor,
|
||||
accent: PColor,
|
||||
fg: PColor,
|
||||
fg_muted: PColor,
|
||||
/// Fondo del área de plot dentro del stage (oscuro como en la galería).
|
||||
plot_bg: Color,
|
||||
}
|
||||
|
||||
fn skin() -> Skin {
|
||||
Skin {
|
||||
bg: PColor::from_rgba8(0x0C, 0x0E, 0x12, 0xFF),
|
||||
panel_hi: PColor::from_rgba8(0x18, 0x1D, 0x26, 0xFF),
|
||||
panel_lo: PColor::from_rgba8(0x10, 0x14, 0x1B, 0xFF),
|
||||
border: PColor::from_rgba8(0x2A, 0x31, 0x3E, 0xFF),
|
||||
accent: PColor::from_rgba8(0x2B, 0xD9, 0xA6, 0xFF), // teal firma
|
||||
fg: PColor::from_rgba8(0xE8, 0xEC, 0xF2, 0xFF),
|
||||
fg_muted: PColor::from_rgba8(0x8A, 0x93, 0xA3, 0xFF),
|
||||
plot_bg: Color::rgba(0.043, 0.055, 0.078, 1.0),
|
||||
}
|
||||
}
|
||||
|
||||
// ───────────────────────── stage central ─────────────────────────
|
||||
|
||||
/// Rect (pineal) interior del stage donde pinta el painter, con padding.
|
||||
fn plot_rect_of(stage: KurboRectLite, pad: f64) -> Rect {
|
||||
Rect::new(
|
||||
(stage.x + pad) as f32,
|
||||
(stage.y + pad) as f32,
|
||||
(stage.w - 2.0 * pad) as f32,
|
||||
(stage.h - 2.0 * pad) as f32,
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct KurboRectLite {
|
||||
x: f64,
|
||||
y: f64,
|
||||
w: f64,
|
||||
h: f64,
|
||||
}
|
||||
|
||||
// ───────────────────────── los 8 beats: cada uno un painter REAL ─────────────────────────
|
||||
//
|
||||
// `lp ∈ [0,1]` = progreso local del beat (para animar datos). `area` = rect
|
||||
// de plot (coords pineal). Todos hablan contra el trait `Canvas` vía
|
||||
// `SceneCanvas`. El fondo del plot ya está pintado por el caller.
|
||||
|
||||
const N_BEATS: usize = 8;
|
||||
|
||||
fn beat_label(i: usize) -> (&'static str, &'static str) {
|
||||
match i {
|
||||
0 => ("bars", "columnas + histograma"),
|
||||
1 => ("heatmap", "campo escalar · Viridis"),
|
||||
2 => ("contour", "marching squares · 8 niveles"),
|
||||
3 => ("polar", "pie / donut + radar"),
|
||||
4 => ("treemap", "squarified"),
|
||||
5 => ("financial", "candlesticks OHLC"),
|
||||
6 => ("flow", "diagrama Sankey"),
|
||||
_ => ("mesh", "grafo force-directed"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Despacha el painter del beat `i` con progreso local `lp`.
|
||||
fn paint_beat(i: usize, lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect, plotbg: Color) {
|
||||
canvas.fill_rect(area, plotbg);
|
||||
match i {
|
||||
0 => beat_bars(lp, canvas, area),
|
||||
1 => beat_heatmap(lp, canvas, area),
|
||||
2 => beat_contour(lp, canvas, area),
|
||||
3 => beat_polar(lp, canvas, area),
|
||||
4 => beat_treemap(lp, canvas, area),
|
||||
5 => beat_financial(lp, canvas, area),
|
||||
6 => beat_sankey(lp, canvas, area),
|
||||
_ => beat_mesh(lp, canvas, area),
|
||||
}
|
||||
}
|
||||
|
||||
/// 0 — bars: barras a la izquierda (con un negativo) + histograma a la
|
||||
/// derecha. Las alturas crecen desde el baseline con `lp`.
|
||||
fn beat_bars(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let g = ease_out_cubic(seg(lp, 0.0, 0.85));
|
||||
let raw = [4.0, 7.0, 2.0, -3.0, 5.0, 6.5, 3.5, 5.8];
|
||||
let bars: Vec<Bar> = raw
|
||||
.iter()
|
||||
.map(|&v| {
|
||||
let c = if v < 0.0 { 0xd08770 } else { 0x2bd9a6 };
|
||||
Bar::new(v * g as f64, Color::from_hex(c))
|
||||
})
|
||||
.collect();
|
||||
let half = area.w * 0.5 - 12.0;
|
||||
let left = Rect::new(area.x + 8.0, area.y + 8.0, half - 8.0, area.h - 16.0);
|
||||
paint_bars(&bars, left, &BarStyle::vertical().with_gap(0.18), canvas);
|
||||
|
||||
// Histograma (gaussiana de un LCG sembrado), altura escalada por lp.
|
||||
let mut rng: u32 = 0x0BAD_F00D;
|
||||
let mut next = || {
|
||||
rng = rng.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
|
||||
(rng >> 8) as f32 / (1u32 << 24) as f32
|
||||
};
|
||||
let mut sample = Vec::with_capacity(4000);
|
||||
for _ in 0..4000 {
|
||||
let gg: f32 = (0..6).map(|_| next()).sum::<f32>() / 6.0;
|
||||
sample.push((gg - 0.5) * 6.0);
|
||||
}
|
||||
let mut hbars = Histogram::new(&sample, 28).to_bars(Color::from_hex(0xb48ead));
|
||||
for b in hbars.iter_mut() {
|
||||
b.value *= g as f64;
|
||||
}
|
||||
let right = Rect::new(area.x + half + 16.0, area.y + 8.0, half - 8.0, area.h - 16.0);
|
||||
paint_bars(&hbars, right, &BarStyle::vertical().with_gap(0.04), canvas);
|
||||
}
|
||||
|
||||
/// Campo escalar 64×40 animado por `lp` (la fase de las ondas avanza).
|
||||
fn animated_field(lp: f32) -> HeatmapMatrix {
|
||||
const W: usize = 64;
|
||||
const H: usize = 40;
|
||||
let ph = lp * std::f32::consts::TAU * 0.5;
|
||||
let mut m = HeatmapMatrix::new(W, H);
|
||||
let mut data = Vec::with_capacity(W * H);
|
||||
for y in 0..H {
|
||||
for x in 0..W {
|
||||
let v = (x as f32 * 0.22 + ph).sin() + (y as f32 * 0.26 - ph * 0.7).cos()
|
||||
+ 0.6 * ((x as f32 * 0.1).sin() * (y as f32 * 0.12).cos());
|
||||
data.push(v);
|
||||
}
|
||||
}
|
||||
m.replace_data(data);
|
||||
m
|
||||
}
|
||||
|
||||
/// 1 — heatmap Viridis del campo animado.
|
||||
fn beat_heatmap(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let field = animated_field(lp);
|
||||
paint_heatmap(&field, Ramp::Viridis, area, canvas);
|
||||
}
|
||||
|
||||
/// 2 — contour: el mismo campo + isolíneas (marching squares). El nº de
|
||||
/// niveles sube de 3 a 9 con `lp` (las curvas "aparecen").
|
||||
fn beat_contour(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let field = animated_field(lp * 0.6);
|
||||
paint_heatmap(&field, Ramp::Viridis, area, canvas);
|
||||
let levels = (3.0 + 6.0 * ease_out_cubic(seg(lp, 0.0, 0.9))) as usize;
|
||||
paint_contours(
|
||||
&field,
|
||||
levels.max(2),
|
||||
area,
|
||||
Color::rgba(0.35, 0.62, 1.0, 0.9),
|
||||
Color::rgba(1.0, 0.42, 0.32, 0.95),
|
||||
1.3,
|
||||
canvas,
|
||||
);
|
||||
}
|
||||
|
||||
/// 3 — polar: donut a la izquierda (barrido por lp) + radar a la derecha
|
||||
/// (vértices que crecen). Dos painters de pineal-polar en un beat.
|
||||
fn beat_polar(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let g = ease_out_cubic(seg(lp, 0.0, 0.85));
|
||||
// Donut.
|
||||
let cx = area.x + area.w * 0.27;
|
||||
let cy = area.y + area.h * 0.5;
|
||||
let r_out = (area.w.min(area.h) * 0.34).max(20.0);
|
||||
let r_in = r_out * 0.5;
|
||||
let base = [28.0_f32, 18.0, 14.0, 12.0, 10.0, 8.0];
|
||||
let pal = [0x2bd9a6, 0xd08770, 0xa3be8c, 0xebcb8b, 0xb48ead, 0x5e81ac];
|
||||
let slices: Vec<Slice> = base
|
||||
.iter()
|
||||
.zip(pal.iter())
|
||||
.map(|(&v, &c)| Slice::new(v * g, Color::from_hex(c)))
|
||||
.collect();
|
||||
if g > 0.01 {
|
||||
paint_pie(&slices, Point::new(cx, cy), r_out, r_in, canvas);
|
||||
}
|
||||
// Radar.
|
||||
let rcx = area.x + area.w * 0.73;
|
||||
let rcy = cy;
|
||||
let rr = (area.w.min(area.h) * 0.34).max(20.0);
|
||||
for step in 1..=4 {
|
||||
let t = step as f32 / 4.0;
|
||||
let ring: Vec<f32> = (0..=72)
|
||||
.flat_map(|k| {
|
||||
let a = (k as f32 / 72.0) * std::f32::consts::TAU - std::f32::consts::FRAC_PI_2;
|
||||
[rcx + (rr * t) * a.cos(), rcy + (rr * t) * a.sin()]
|
||||
})
|
||||
.collect();
|
||||
canvas.stroke_polyline(&ring, StrokeStyle::new(0.6, Color::rgba(0.5, 0.56, 0.66, 0.35)));
|
||||
}
|
||||
let values: Vec<f32> = [8.0_f32, 6.5, 9.0, 4.0, 7.0, 5.5].iter().map(|v| v * g).collect();
|
||||
paint_radar(
|
||||
&values,
|
||||
10.0,
|
||||
Point::new(rcx, rcy),
|
||||
rr,
|
||||
Color::rgba(0.169, 0.851, 0.651, 0.30),
|
||||
StrokeStyle::new(1.8, Color::from_hex(0x2bd9a6)),
|
||||
canvas,
|
||||
);
|
||||
}
|
||||
|
||||
/// 4 — treemap squarified: 14 tiles, los pesos respiran con `lp`.
|
||||
fn beat_treemap(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let pal = [
|
||||
0x2bd9a6, 0xd08770, 0xa3be8c, 0xebcb8b, 0xb48ead, 0x5e81ac, 0x81a1c1, 0xbf616a,
|
||||
0x8fbcbb, 0xd8dee9, 0x88c0d0, 0xebcb8b, 0xa3be8c, 0x5e81ac,
|
||||
];
|
||||
let base = [40.0, 28.0, 22.0, 18.0, 14.0, 12.0, 10.0, 8.0, 6.0, 5.0, 4.0, 3.5, 3.0, 2.0];
|
||||
let wob = lp * std::f32::consts::TAU;
|
||||
let tiles: Vec<Tile> = base
|
||||
.iter()
|
||||
.zip(pal.iter())
|
||||
.enumerate()
|
||||
.map(|(k, (&w, &c))| {
|
||||
let m = 1.0 + 0.25 * (wob + k as f32 * 0.6).sin();
|
||||
Tile::new((w * m) as f64, Color::from_hex(c))
|
||||
})
|
||||
.collect();
|
||||
let inset = Rect::new(area.x + 6.0, area.y + 6.0, area.w - 12.0, area.h - 12.0);
|
||||
paint_treemap(&tiles, inset, 3.0, canvas);
|
||||
}
|
||||
|
||||
/// 5 — financial: candlesticks OHLC (random-walk determinista). El nº de
|
||||
/// velas visibles crece con `lp` (se van "imprimiendo" de izq a der).
|
||||
fn beat_financial(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
const N: usize = 64;
|
||||
let mut buf = OhlcBuffer::with_capacity(N);
|
||||
let mut rng: u32 = 0xCAFE_1234;
|
||||
let mut next = || {
|
||||
rng = rng.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
|
||||
((rng >> 8) as f32 / (1u32 << 24) as f32) - 0.5
|
||||
};
|
||||
let mut price = 100.0_f32;
|
||||
let mut lo_all = f32::MAX;
|
||||
let mut hi_all = f32::MIN;
|
||||
let shown = ((N as f32) * ease_out_cubic(seg(lp, 0.0, 0.95))).round() as usize;
|
||||
let shown = shown.clamp(2, N);
|
||||
for i in 0..shown {
|
||||
let o = price;
|
||||
let drift = next() * 4.0 + 0.25 * (i as f32 * 0.3).sin();
|
||||
let c = (o + drift).max(5.0);
|
||||
let hi = o.max(c) + next().abs() * 3.0;
|
||||
let lo = o.min(c) - next().abs() * 3.0;
|
||||
buf.push_values(i as f32, o, hi, lo, c, 1.0);
|
||||
price = c;
|
||||
lo_all = lo_all.min(lo);
|
||||
hi_all = hi_all.max(hi);
|
||||
}
|
||||
if hi_all <= lo_all {
|
||||
return;
|
||||
}
|
||||
let pad = (hi_all - lo_all) * 0.08;
|
||||
let vp = ChartViewport::new(
|
||||
-1.0,
|
||||
N as f64,
|
||||
(lo_all - pad) as f64,
|
||||
(hi_all + pad) as f64,
|
||||
);
|
||||
let plot = Rect::new(area.x + 6.0, area.y + 6.0, area.w - 12.0, area.h - 12.0);
|
||||
let cs = CoordinateSystem::new(vp, plot);
|
||||
let mut style = CandlestickStyle::default();
|
||||
style.bull_color = Color::from_hex(0x2bd9a6);
|
||||
style.bear_color = Color::from_hex(0xe06c75);
|
||||
style.body_width_ratio = 0.68;
|
||||
paint_candlesticks(canvas, &cs, &buf, style);
|
||||
}
|
||||
|
||||
/// 6 — flow: diagrama Sankey de un presupuesto. Los ribbons aparecen con
|
||||
/// `lp` vía el alpha del color de link.
|
||||
fn beat_sankey(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let nodes: Vec<SankeyNode> = [
|
||||
"Sueldo", "Freelance", "Renta", "Dividendos", "Vivienda", "Comida", "Transporte",
|
||||
"Ocio", "Salud", "Ahorro",
|
||||
]
|
||||
.iter()
|
||||
.map(|n| SankeyNode::new(*n))
|
||||
.collect();
|
||||
let links: Vec<SankeyLink> = vec![
|
||||
SankeyLink { source: 0, target: 4, value: 1200.0 },
|
||||
SankeyLink { source: 0, target: 5, value: 600.0 },
|
||||
SankeyLink { source: 0, target: 6, value: 250.0 },
|
||||
SankeyLink { source: 0, target: 9, value: 950.0 },
|
||||
SankeyLink { source: 1, target: 5, value: 200.0 },
|
||||
SankeyLink { source: 1, target: 7, value: 300.0 },
|
||||
SankeyLink { source: 1, target: 9, value: 400.0 },
|
||||
SankeyLink { source: 2, target: 4, value: 400.0 },
|
||||
SankeyLink { source: 2, target: 8, value: 150.0 },
|
||||
SankeyLink { source: 3, target: 9, value: 350.0 },
|
||||
SankeyLink { source: 3, target: 7, value: 80.0 },
|
||||
];
|
||||
let inset = Rect::new(area.x + 16.0, area.y + 16.0, area.w - 32.0, area.h - 32.0);
|
||||
let layout = compute_layout(&nodes, &links, inset, 16.0, 8.0);
|
||||
let ribbon_a = 0.10 + 0.40 * ease_out_cubic(seg(lp, 0.0, 0.85));
|
||||
paint_sankey(
|
||||
&layout,
|
||||
Color::from_hex(0xe5e9f0),
|
||||
Color::rgba(0.169, 0.851, 0.651, ribbon_a),
|
||||
canvas,
|
||||
);
|
||||
}
|
||||
|
||||
/// 7 — mesh: grafo force-directed pre-relajado, que rota lentamente con
|
||||
/// `lp` para que se note la profundidad de la maraña.
|
||||
fn beat_mesh(lp: f32, canvas: &mut SceneCanvas<'_>, area: Rect) {
|
||||
let g = relaxed_graph();
|
||||
let cx = area.x + area.w * 0.5;
|
||||
let cy = area.y + area.h * 0.5;
|
||||
let scale = (area.w.min(area.h) / 170.0).max(0.5);
|
||||
let ang = lp * std::f32::consts::TAU * 0.15;
|
||||
let (sa, ca) = ang.sin_cos();
|
||||
let rot = |x: f32, y: f32| -> (f32, f32) {
|
||||
(cx + (x * ca - y * sa) * scale, cy + (x * sa + y * ca) * scale)
|
||||
};
|
||||
let edge = StrokeStyle::new(1.0, Color::rgba(0.55, 0.62, 0.7, 0.4));
|
||||
for (u, v) in g.edges.iter() {
|
||||
let (xu, yu) = g.nodes.pos(u);
|
||||
let (xv, yv) = g.nodes.pos(v);
|
||||
let (ax, ay) = rot(xu, yu);
|
||||
let (bx, by) = rot(xv, yv);
|
||||
canvas.stroke_line(Point::new(ax, ay), Point::new(bx, by), edge);
|
||||
}
|
||||
let n = g.nodes.len();
|
||||
for i in 0..n {
|
||||
let (x, y) = g.nodes.pos(i);
|
||||
let r = g.nodes.radius(i) * scale;
|
||||
let (px, py) = rot(x, y);
|
||||
let color = if i < N_RING { Color::from_hex(0x2bd9a6) } else { Color::from_hex(0xa3be8c) };
|
||||
canvas.fill_rect(Rect::new(px - r, py - r, r * 2.0, r * 2.0), color);
|
||||
}
|
||||
}
|
||||
|
||||
// ── grafo del beat mesh (mismo armado que pineal-mesh-demo / la galería) ──
|
||||
|
||||
const N_RING: usize = 12;
|
||||
const N_SAT: usize = 12;
|
||||
|
||||
struct Graph {
|
||||
nodes: NodeBuffer,
|
||||
edges: EdgeBuffer,
|
||||
}
|
||||
|
||||
fn relaxed_graph() -> Graph {
|
||||
let mut nodes = NodeBuffer::new();
|
||||
for i in 0..N_RING {
|
||||
let a = (i as f32 / N_RING as f32) * std::f32::consts::TAU;
|
||||
nodes.push(20.0 * a.cos(), 20.0 * a.sin(), 6.0);
|
||||
}
|
||||
for i in 0..N_SAT {
|
||||
let a = (i as f32 / N_SAT as f32) * std::f32::consts::TAU + 0.13;
|
||||
nodes.push(60.0 * a.cos(), 60.0 * a.sin(), 4.5);
|
||||
}
|
||||
let mut edges = EdgeBuffer::new();
|
||||
for i in 0..N_RING {
|
||||
edges.push(i, (i + 1) % N_RING);
|
||||
}
|
||||
for i in 0..N_RING {
|
||||
edges.push(i, (i + 3) % N_RING);
|
||||
}
|
||||
for i in 0..N_SAT {
|
||||
edges.push(i, N_RING + i);
|
||||
}
|
||||
let mut sim = ForceLayout::new(ForceParams { k: 38.0, temperature: 60.0, cooling: 0.985 });
|
||||
for _ in 0..400 {
|
||||
let _ = sim.step(&mut nodes, &edges);
|
||||
}
|
||||
Graph { nodes, edges }
|
||||
}
|
||||
|
||||
// ───────────────────────── overlays vector (cold-open + wordmark + chrome) ─────────────────────────
|
||||
|
||||
fn signature_path(cw: f64, ch: f64) -> BezPath {
|
||||
let cx = cw / 2.0;
|
||||
let cy = ch / 2.0;
|
||||
let mut p = BezPath::new();
|
||||
p.move_to((cx - 380.0, cy + 30.0));
|
||||
p.curve_to(
|
||||
(cx - 150.0, cy - 200.0),
|
||||
(cx + 150.0, cy + 200.0),
|
||||
(cx + 380.0, cy - 30.0),
|
||||
);
|
||||
p
|
||||
}
|
||||
|
||||
fn trim_path(full: &BezPath, prog: f64) -> (BezPath, KPoint) {
|
||||
use vello::kurbo::ParamCurve;
|
||||
let prog = prog.clamp(0.0, 1.0);
|
||||
let mut cubic = None;
|
||||
let mut start = KPoint::ZERO;
|
||||
for el in full.elements() {
|
||||
match el {
|
||||
vello::kurbo::PathEl::MoveTo(p) => start = *p,
|
||||
vello::kurbo::PathEl::CurveTo(c1, c2, p) => {
|
||||
cubic = Some(vello::kurbo::CubicBez::new(start, *c1, *c2, *p));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut out = BezPath::new();
|
||||
let mut head = start;
|
||||
if let Some(cb) = cubic {
|
||||
out.move_to(cb.p0);
|
||||
let steps = 96;
|
||||
for i in 1..=steps {
|
||||
let u = (i as f64 / steps as f64) * prog;
|
||||
let pt = cb.eval(u);
|
||||
out.line_to(pt);
|
||||
head = pt;
|
||||
}
|
||||
}
|
||||
(out, head)
|
||||
}
|
||||
|
||||
// ───────────────────────── la escena por frame ─────────────────────────
|
||||
|
||||
fn render_frame(scene: &mut vello::Scene, ts: &mut Typesetter, t: f32, cw: f64, ch: f64, s: &Skin) {
|
||||
// Fondo (gradiente sutil).
|
||||
let bg_rect = vello::kurbo::Rect::new(0.0, 0.0, cw, ch);
|
||||
let grad = Gradient::new_linear(KPoint::new(0.0, 0.0), KPoint::new(0.0, ch))
|
||||
.with_stops([s.panel_lo, s.bg].as_slice());
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, &grad, None, &bg_rect);
|
||||
|
||||
// Geometría del stage central (gran panel donde viven los gráficos).
|
||||
let margin_x = 200.0_f64;
|
||||
let stage_top = 178.0_f64;
|
||||
let stage_bottom = 120.0_f64;
|
||||
let stage = KurboRectLite {
|
||||
x: margin_x,
|
||||
y: stage_top,
|
||||
w: cw - 2.0 * margin_x,
|
||||
h: ch - stage_top - stage_bottom,
|
||||
};
|
||||
|
||||
// Aparición del chrome (panel) en el cold-open; desaparición antes del wordmark.
|
||||
let chrome_in = ease_out_cubic(seg(t, 0.06, 0.16));
|
||||
let chrome_out = 1.0 - ease_in_out_cubic(seg(t, 0.86, 0.93));
|
||||
let chrome_a = (chrome_in * chrome_out).clamp(0.0, 1.0);
|
||||
|
||||
// Ventana de los beats en la timeline.
|
||||
let beats_lo = 0.12_f32;
|
||||
let beats_hi = 0.86_f32;
|
||||
|
||||
if chrome_a > 0.001 {
|
||||
// Panel del stage (card con borde + gradiente + sombra simulada).
|
||||
let r = vello::kurbo::RoundedRect::new(
|
||||
stage.x,
|
||||
stage.y,
|
||||
stage.x + stage.w,
|
||||
stage.y + stage.h,
|
||||
18.0,
|
||||
);
|
||||
// Sombra simple.
|
||||
let shadow = vello::kurbo::RoundedRect::new(
|
||||
stage.x,
|
||||
stage.y + 10.0,
|
||||
stage.x + stage.w,
|
||||
stage.y + stage.h + 10.0,
|
||||
18.0,
|
||||
);
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, palpha(PColor::BLACK, 0.45 * chrome_a), None, &shadow);
|
||||
let pgrad = Gradient::new_linear(KPoint::new(0.0, stage.y), KPoint::new(0.0, stage.y + stage.h))
|
||||
.with_stops([palpha(s.panel_hi, chrome_a), palpha(s.panel_lo, chrome_a)].as_slice());
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, &pgrad, None, &r);
|
||||
scene.stroke(&Stroke::new(1.2), Affine::IDENTITY, palpha(s.border, chrome_a), None, &r);
|
||||
|
||||
// ── beats: cross-fade entre gráfico saliente y entrante ──
|
||||
let phase = seg(t, beats_lo, beats_hi); // 0..1 sobre todos los beats
|
||||
let scaled = phase * N_BEATS as f32;
|
||||
let cur = (scaled.floor() as usize).min(N_BEATS - 1);
|
||||
let frac = scaled - cur as f32; // 0..1 dentro del beat actual
|
||||
// Cross-fade en el último 22% de cada beat hacia el siguiente.
|
||||
let xf = seg(frac, 0.78, 1.0);
|
||||
|
||||
let plot = plot_rect_of(stage, 18.0);
|
||||
let clip = vello::kurbo::RoundedRect::new(
|
||||
plot.x as f64,
|
||||
plot.y as f64,
|
||||
(plot.x + plot.w) as f64,
|
||||
(plot.y + plot.h) as f64,
|
||||
10.0,
|
||||
);
|
||||
|
||||
// Progreso local "vivo" del beat actual: 0..1 a lo largo de su tramo.
|
||||
let lp_cur = frac;
|
||||
// Gráfico actual (se desvanece durante el cross-fade final).
|
||||
let a_cur = (1.0 - xf) * chrome_a;
|
||||
if a_cur > 0.004 {
|
||||
scene.push_layer(Fill::NonZero, peniko::Mix::Normal, a_cur, Affine::IDENTITY, &clip);
|
||||
{
|
||||
let mut canvas = SceneCanvas::new(scene, ts);
|
||||
paint_beat(cur, lp_cur, &mut canvas, plot, s.plot_bg);
|
||||
}
|
||||
scene.pop_layer();
|
||||
}
|
||||
// Gráfico entrante (aparece durante el cross-fade).
|
||||
if xf > 0.004 && cur + 1 < N_BEATS {
|
||||
let a_next = xf * chrome_a;
|
||||
scene.push_layer(Fill::NonZero, peniko::Mix::Normal, a_next, Affine::IDENTITY, &clip);
|
||||
{
|
||||
let mut canvas = SceneCanvas::new(scene, ts);
|
||||
// El entrante arranca su animación desde 0.
|
||||
paint_beat(cur + 1, 0.0, &mut canvas, plot, s.plot_bg);
|
||||
}
|
||||
scene.pop_layer();
|
||||
}
|
||||
|
||||
// ── chrome textual: título del beat + subtítulo + barra de progreso ──
|
||||
let (name, subtitle) = beat_label(cur);
|
||||
let head_a = chrome_a * (1.0 - seg(frac, 0.86, 1.0)); // pequeño parpadeo al cambiar
|
||||
let head_a = head_a.max(chrome_a * 0.0);
|
||||
// Título arriba del stage.
|
||||
let tl = ts.layout(name, 30.0, None, Alignment::Start, 1.0, false, None, 800.0, false, false, 0.0, 0.0);
|
||||
let m = measurement(&tl);
|
||||
let tx = stage.x + 6.0;
|
||||
let ty = stage.y - 48.0;
|
||||
// Punto teal de acento a la izquierda del título.
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
palpha(s.accent, head_a),
|
||||
None,
|
||||
&Circle::new(KPoint::new(tx + 6.0, ty + m.height as f64 * 0.5), 6.0),
|
||||
);
|
||||
let brush = peniko::Brush::Solid(palpha(s.fg, head_a));
|
||||
draw_layout_brush_xf(scene, &tl, &brush, Affine::translate((tx + 22.0, ty)));
|
||||
// Subtítulo a la derecha del título.
|
||||
let sl = ts.layout(subtitle, 15.0, None, Alignment::Start, 1.0, false, None, 400.0, false, false, 0.0, 0.0);
|
||||
let sbrush = peniko::Brush::Solid(palpha(s.fg_muted, head_a));
|
||||
draw_layout_brush_xf(
|
||||
scene,
|
||||
&sl,
|
||||
&sbrush,
|
||||
Affine::translate((tx + 28.0 + m.width as f64, ty + 12.0)),
|
||||
);
|
||||
|
||||
// Barra de progreso de la timeline (debajo del stage).
|
||||
let bar_y = stage.y + stage.h + 30.0;
|
||||
let bar_x = stage.x;
|
||||
let bar_w = stage.w;
|
||||
let track = vello::kurbo::RoundedRect::new(bar_x, bar_y, bar_x + bar_w, bar_y + 4.0, 2.0);
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, palpha(s.border, chrome_a), None, &track);
|
||||
let fillw = bar_w * phase as f64;
|
||||
if fillw > 1.0 {
|
||||
let fr = vello::kurbo::RoundedRect::new(bar_x, bar_y, bar_x + fillw, bar_y + 4.0, 2.0);
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, palpha(s.accent, chrome_a), None, &fr);
|
||||
}
|
||||
// Marcas de los beats (tics).
|
||||
for k in 0..=N_BEATS {
|
||||
let mx = bar_x + bar_w * (k as f64 / N_BEATS as f64);
|
||||
let on = (k as f32 / N_BEATS as f32) <= phase + 0.001;
|
||||
let col = if on { s.accent } else { s.border };
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
palpha(col, chrome_a),
|
||||
None,
|
||||
&Circle::new(KPoint::new(mx, bar_y + 2.0), 3.0),
|
||||
);
|
||||
}
|
||||
|
||||
// Wordmark pequeño persistente arriba a la izquierda (marca).
|
||||
let wm = ts.layout("pineal", 22.0, None, Alignment::Start, 1.0, false, None, 800.0, false, false, 0.0, 0.0);
|
||||
let wmb = peniko::Brush::Solid(palpha(s.fg, chrome_a * 0.9));
|
||||
draw_layout_brush_xf(scene, &wm, &wmb, Affine::translate((margin_x, 60.0)));
|
||||
let tagl = ts.layout(
|
||||
"data visualization, in Rust",
|
||||
13.0, None, Alignment::Start, 1.0, false, None, 400.0, false, false, 0.0, 0.0,
|
||||
);
|
||||
let tagb = peniko::Brush::Solid(palpha(s.fg_muted, chrome_a * 0.9));
|
||||
draw_layout_brush_xf(scene, &tagl, &tagb, Affine::translate((margin_x + 86.0, 68.0)));
|
||||
}
|
||||
|
||||
// ── COLD OPEN: trazo bezier draw-on (0–14%) ──
|
||||
let line_vis = 1.0 - seg(t, 0.13, 0.20);
|
||||
if line_vis > 0.001 && t < 0.21 {
|
||||
let path = signature_path(cw, ch);
|
||||
let draw_on = ease_out_cubic(seg(t, 0.0, 0.12)) as f64;
|
||||
let (trimmed, head) = trim_path(&path, draw_on);
|
||||
scene.stroke(
|
||||
&Stroke::new(2.2),
|
||||
Affine::IDENTITY,
|
||||
palpha(s.accent, 0.9 * line_vis),
|
||||
None,
|
||||
&trimmed,
|
||||
);
|
||||
let pop = ease_out_back(seg(t, 0.0, 0.1));
|
||||
let r = (4.0 + 7.0 * pop as f64).max(0.0);
|
||||
let dot_a = (seg(t, 0.0, 0.1) * line_vis).clamp(0.0, 1.0);
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, palpha(s.accent, 0.18 * dot_a), None, &Circle::new(head, r * 3.2));
|
||||
scene.fill(Fill::NonZero, Affine::IDENTITY, palpha(s.accent, dot_a), None, &Circle::new(head, r));
|
||||
}
|
||||
|
||||
// ── WORDMARK final (88–100%) ──
|
||||
let word_a = ease_out_cubic(seg(t, 0.90, 0.98));
|
||||
if word_a > 0.001 {
|
||||
let size = 150.0_f32;
|
||||
let layout = ts.layout("pineal", size, None, Alignment::Start, 1.0, false, None, 800.0, false, false, 0.0, 0.0);
|
||||
let m = measurement(&layout);
|
||||
let rise = lerp(28.0, 0.0, word_a as f64);
|
||||
let ox = (cw - m.width as f64) / 2.0;
|
||||
let oy = (ch - m.height as f64) / 2.0 - 24.0 + rise;
|
||||
let brush = peniko::Brush::Solid(palpha(s.fg, word_a));
|
||||
draw_layout_brush_xf(scene, &layout, &brush, Affine::translate((ox, oy)));
|
||||
|
||||
let sub_a = ease_out_cubic(seg(t, 0.93, 1.0));
|
||||
if sub_a > 0.001 {
|
||||
let sy = oy + m.height as f64 + 16.0;
|
||||
// Subtítulo con punto teal a la izquierda.
|
||||
let sl = ts.layout(
|
||||
"data visualization, in Rust",
|
||||
28.0, None, Alignment::Start, 1.0, false, None, 400.0, false, false, 0.0, 0.0,
|
||||
);
|
||||
let sm = measurement(&sl);
|
||||
let dot_r = 6.0;
|
||||
let block_w = sm.width as f64 + dot_r * 2.0 + 14.0;
|
||||
let sx = (cw - block_w) / 2.0;
|
||||
scene.fill(
|
||||
Fill::NonZero,
|
||||
Affine::IDENTITY,
|
||||
palpha(s.accent, sub_a),
|
||||
None,
|
||||
&Circle::new(KPoint::new(sx + dot_r, sy + 28.0 * 0.5), dot_r),
|
||||
);
|
||||
let sbrush = peniko::Brush::Solid(palpha(s.fg_muted, sub_a));
|
||||
draw_layout_brush_xf(scene, &sl, &sbrush, Affine::translate((sx + dot_r * 2.0 + 14.0, sy)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ───────────────────────── main: N frames headless → PNG ─────────────────────────
|
||||
|
||||
fn main() {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let out_dir = args.next().unwrap_or_else(|| "showreel_frames_pineal".to_string());
|
||||
let n: usize = args.next().and_then(|v| v.parse().ok()).unwrap_or(300);
|
||||
let w: u32 = args.next().and_then(|v| v.parse().ok()).unwrap_or(1600);
|
||||
let h: u32 = args.next().and_then(|v| v.parse().ok()).unwrap_or(900);
|
||||
create_dir_all(&out_dir).expect("mkdir out_dir");
|
||||
|
||||
let s = skin();
|
||||
let [br, bgc, bb, _] = s.bg.components;
|
||||
let base = PColor::from_rgba8((br * 255.0) as u8, (bgc * 255.0) as u8, (bb * 255.0) as u8, 255);
|
||||
|
||||
// GPU una sola vez; reusar device/renderer/target para los N frames.
|
||||
let hal = pollster::block_on(Hal::new(None)).expect("hal");
|
||||
let mut renderer = Renderer::new(&hal).expect("renderer");
|
||||
let target = hal.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("showreel-pineal"),
|
||||
size: wgpu::Extent3d { width: w, height: h, depth_or_array_layers: 1 },
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: FMT,
|
||||
usage: wgpu::TextureUsages::STORAGE_BINDING
|
||||
| wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
| wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = target.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let mut ts = Typesetter::new();
|
||||
let cw = w as f64;
|
||||
let ch = h as f64;
|
||||
|
||||
for i in 0..n {
|
||||
let t = if n <= 1 { 0.0 } else { i as f32 / (n as f32 - 1.0) };
|
||||
let mut scene = vello::Scene::new();
|
||||
render_frame(&mut scene, &mut ts, t, cw, ch, &s);
|
||||
renderer
|
||||
.render_to_view(&hal, &scene, &view, w, h, base)
|
||||
.expect("render_to_view");
|
||||
let path = format!("{out_dir}/frame_{i:04}.png");
|
||||
write_png(&hal, &target, &path, w, h);
|
||||
if i % 30 == 0 || i == n - 1 {
|
||||
eprintln!("pineal_showreel: frame {}/{} (t={:.3})", i + 1, n, t);
|
||||
}
|
||||
}
|
||||
eprintln!("pineal_showreel: {n} frames en {out_dir}/ ({w}x{h})");
|
||||
}
|
||||
|
||||
fn write_png(hal: &Hal, target: &wgpu::Texture, path: &str, w: u32, h: u32) {
|
||||
let unpadded = (w * 4) as usize;
|
||||
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize;
|
||||
let padded = unpadded.div_ceil(align) * align;
|
||||
let buf = hal.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("readback"),
|
||||
size: (padded * h as usize) as u64,
|
||||
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let mut enc = hal
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
enc.copy_texture_to_buffer(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: target,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &buf,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(padded as u32),
|
||||
rows_per_image: Some(h),
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d { width: w, height: h, depth_or_array_layers: 1 },
|
||||
);
|
||||
hal.queue.submit(std::iter::once(enc.finish()));
|
||||
let slice = buf.slice(..);
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
slice.map_async(wgpu::MapMode::Read, move |r| {
|
||||
let _ = tx.send(r);
|
||||
});
|
||||
let _ = hal.device.poll(wgpu::PollType::wait_indefinitely());
|
||||
rx.recv().unwrap().unwrap();
|
||||
let data = slice.get_mapped_range();
|
||||
let mut pixels = Vec::with_capacity((w * h * 4) as usize);
|
||||
for r in 0..h as usize {
|
||||
let sidx = r * padded;
|
||||
pixels.extend_from_slice(&data[sidx..sidx + unpadded]);
|
||||
}
|
||||
drop(data);
|
||||
buf.unmap();
|
||||
let file = File::create(path).expect("png");
|
||||
let mut enc = png::Encoder::new(BufWriter::new(file), w, h);
|
||||
enc.set_color(png::ColorType::Rgba);
|
||||
enc.set_depth(png::BitDepth::Eight);
|
||||
let mut wr = enc.write_header().unwrap();
|
||||
wr.write_image_data(&pixels).unwrap();
|
||||
}
|
||||
@@ -43,8 +43,11 @@ use pineal_treemap::{paint_treemap, Tile};
|
||||
// Modelo y mensajes
|
||||
// =====================================================================
|
||||
|
||||
// `pub(crate)` (aquí y en `Model`/`GaleriaDemo`): el example
|
||||
// `pantallazo_pineal` incluye este archivo por `#[path]` para montar la
|
||||
// MISMA view de la galería sin ventana. Para el binario no cambia nada.
|
||||
#[derive(Clone)]
|
||||
enum Msg {
|
||||
pub(crate) enum Msg {
|
||||
/// Barra de menú principal: abrir/cerrar un menú raíz (`None` cierra).
|
||||
MenuOpen(Option<usize>),
|
||||
/// Comando elegido en la barra → se traduce al `Msg` real.
|
||||
@@ -53,7 +56,7 @@ enum Msg {
|
||||
CycleTheme,
|
||||
}
|
||||
|
||||
struct Model {
|
||||
pub(crate) struct Model {
|
||||
theme: Theme,
|
||||
menu_open: Option<usize>,
|
||||
/// Grafo del tile mesh, ya relajado en el init (posiciones fijas).
|
||||
@@ -64,7 +67,7 @@ struct Model {
|
||||
field: Arc<HeatmapMatrix>,
|
||||
}
|
||||
|
||||
struct GaleriaDemo;
|
||||
pub(crate) struct GaleriaDemo;
|
||||
|
||||
impl App for GaleriaDemo {
|
||||
type Model = Model;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# pineal-gpu-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Starfield warp 3D sobre el camino GPU directo.
|
||||
|
||||
Es el **primer consumidor real de `GpuSceneCanvas`** (Fase 4 del SDD
|
||||
de pineal). El resto del catálogo sólo tenía el backend GPU
|
||||
documentado y testeado; aquí se pinta de verdad: el demo emite hasta
|
||||
1 M de `fill_rect` por frame contra el trait `Canvas`, pero detrás
|
||||
del trait está `GpuSceneCanvas` empujando a un `GpuBatch` que despacha
|
||||
todo en **una sola draw call instanciada** (P3 del SDD).
|
||||
|
||||
Reparto de responsabilidades (Elm + el split CPU/GPU del SDD):
|
||||
|
||||
- `update(Tick)` avanza la simulación en CPU: cada estrella vuela
|
||||
hacia el observador (`z -= speed`) y se recicla al fondo al cruzar
|
||||
el plano cercano. Estado en un `Vec<f32>` plano interleaved
|
||||
`[x,y,z, ...]`, mutado in-place (P1 + P2: zero boxing, zero alloc
|
||||
en hot path).
|
||||
- `gpu_paint_with(...)` proyecta perspectiva y dibuja: lee el campo
|
||||
de estrellas, calcula el pixel de cada una contra el rect del nodo
|
||||
y llama `canvas.fill_rect(...)`. Ni el demo ni el painter saben de
|
||||
`wgpu` — sólo hablan el trait `Canvas`.
|
||||
|
||||
El campo se comparte entre `update` (escribe) y el painter (lee) por
|
||||
`Arc<Mutex<StarField>>`. Ambos corren en el hilo de UI, así que el
|
||||
mutex nunca se disputa; el `Arc` existe sólo porque la closure GPU
|
||||
debe ser `'static` y no puede tomar prestado el `Model`.
|
||||
|
||||
Las `GpuPipelines` (shaders + render pipelines) se compilan una vez y
|
||||
se cachean en un `OnceLock` que vive en el `Model`, no en `view()` —
|
||||
recompilarlas por frame mataría el framerate.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-gpu-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-gpu-demo
|
||||
|
||||
A 3D starfield warp over the direct GPU path.
|
||||
|
||||
It is the **first real consumer of `GpuSceneCanvas`** (Phase 4 of pineal's SDD).
|
||||
The rest of the catalog only had the GPU backend documented and tested; here it
|
||||
actually paints: the demo emits up to 1M `fill_rect` calls per frame against the
|
||||
`Canvas` trait, but behind it the GPU path takes over.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -0,0 +1,24 @@
|
||||
# pineal-heatmap-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Campo 2D con onda viajera.
|
||||
|
||||
Matriz 48×32 que se reescribe cada 33 ms (≈ 30 Hz). El valor de
|
||||
cada celda combina dos sinusoides con desplazamiento de fase
|
||||
ligado al tick: `sin(x·0.25 - t·0.1) + cos(y·0.30 + t·0.07)`.
|
||||
El ramp Viridis mapea `[min, max]` de la matriz a color.
|
||||
|
||||
Cableado de UI: barra de menú principal (Archivo / Ver / Ayuda) +
|
||||
menú contextual sobre el plot (right-click). Como es un canvas sin
|
||||
texto editable no hay menú Editar ni clipboard.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-heatmap-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-heatmap-demo
|
||||
|
||||
A 2D field with a travelling wave.
|
||||
|
||||
A 48×32 matrix rewritten every 33 ms (≈ 30 Hz). Each cell's value combines two
|
||||
sinusoids with a phase shift tied to the tick:
|
||||
`sin(x·0.25 - t·0.1) + cos(y·0.30 + t·0.07)`. The Viridis ramp maps the matrix's
|
||||
`[min, max]` to colour.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -0,0 +1,24 @@
|
||||
# pineal-hexbin-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
5 000 puntos sintéticos bineados.
|
||||
|
||||
Generador determinista (LCG sobre `t`) que produce dos clusters
|
||||
gaussianos solapados. El hexbin revela la densidad — cada celda se
|
||||
colorea con Viridis según count. Sin animación: el chart se computa
|
||||
una vez al iniciar.
|
||||
|
||||
Cableado de UI: barra de menú principal (Archivo / Ver / Ayuda) +
|
||||
menú contextual sobre el plot (right-click). Como es un canvas sin
|
||||
texto editable no hay menú Editar ni clipboard.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-hexbin-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
# pineal-hexbin-demo
|
||||
|
||||
5,000 synthetic points, binned.
|
||||
|
||||
A deterministic generator (an LCG over `t`) producing two overlapping Gaussian
|
||||
clusters. The hexbin reveals the density — each cell is coloured with Viridis by
|
||||
count. No animation: the chart is computed once at startup.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -0,0 +1,26 @@
|
||||
# pineal-mesh-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Grafo de 24 nodos relajándose en vivo.
|
||||
|
||||
Topología: ciclo de 12 nodos + cordales aleatorios + 12 nodos
|
||||
satélites enganchados al exterior. La simulación Fruchterman-Reingold
|
||||
corre un paso por tick (≈ 60 Hz) hasta enfriarse; el panel muestra
|
||||
aristas (gris) y nodos (círculos de discos rellenos) sobre fondo
|
||||
oscuro. Cuando la temperatura cae bajo el umbral, el sistema queda
|
||||
estacionario hasta que un reset lo recalienta.
|
||||
|
||||
Cableado de UI: barra de menú principal (Archivo / Ver / Ayuda) +
|
||||
menú contextual sobre el plot (right-click). Como es un canvas sin
|
||||
texto editable no hay menú Editar ni clipboard.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-mesh-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
# pineal-mesh-demo
|
||||
|
||||
A 24-node graph relaxing live.
|
||||
|
||||
Topology: a 12-node cycle + random chords + 12 satellite nodes hooked to the
|
||||
outside. The Fruchterman-Reingold simulation runs one step per tick (≈ 60 Hz)
|
||||
until it cools; the panel shows edges (grey) and nodes (filled discs).
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-phosphor-demo
|
||||
|
||||
> Demo del backend fósforo de [pineal](../README.md).
|
||||
> Demo del backend fósforo de [pineal](../../README.md).
|
||||
|
||||
Genera waveforms (seno, lissajous, ruido) y los pasa por [`pineal-phosphor`](../pineal-phosphor/README.md) con distintos `decay`. Slider para ajustar decay en vivo. Útil para entender qué hace el parámetro antes de usarlo en una app real.
|
||||
Genera waveforms (seno, lissajous, ruido) y los pasa por [`pineal-phosphor`](../../pineal-phosphor/README.md) con distintos `decay`. Slider para ajustar decay en vivo. Útil para entender qué hace el parámetro antes de usarlo en una app real.
|
||||
|
||||
## Uso
|
||||
|
||||
@@ -12,4 +12,4 @@ cargo run --release -p pineal-phosphor-demo
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-phosphor`](../pineal-phosphor/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-phosphor`](../../pineal-phosphor/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-phosphor-demo
|
||||
|
||||
> Phosphor backend demo for [pineal](../README.md).
|
||||
> Phosphor backend demo for [pineal](../../README.md).
|
||||
|
||||
Generates waveforms (sine, lissajous, noise) and pipes them through [`pineal-phosphor`](../pineal-phosphor/README.md) with various `decay` values. Slider to tune decay live. Useful to understand the parameter before using it in a real app.
|
||||
Generates waveforms (sine, lissajous, noise) and pipes them through [`pineal-phosphor`](../../pineal-phosphor/README.md) with various `decay` values. Slider to tune decay live. Useful to understand the parameter before using it in a real app.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -12,4 +12,4 @@ cargo run --release -p pineal-phosphor-demo
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-phosphor`](../pineal-phosphor/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-phosphor`](../../pineal-phosphor/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# pineal-polar-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Pie/donut + radar sobre Llimphi.
|
||||
|
||||
Dos paneles uno al lado del otro:
|
||||
- **Pie chart (donut)** — 6 porciones de un presupuesto sintético.
|
||||
- **Radar (spider)** — perfil de 6 atributos contra un máximo común.
|
||||
|
||||
Ambos se ajustan al rect del panel: el centro y el radio se calculan
|
||||
en el closure de `paint_with` a partir del `PaintRect` recibido.
|
||||
|
||||
Lleva barra de menú principal (Archivo/Ver/Ayuda) + un menú
|
||||
contextual sobre los plots. Son canvas estáticos sin edición ni
|
||||
clipboard — el contextual sólo ofrece cambiar tema.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-polar-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-polar-demo
|
||||
|
||||
Pie/donut + radar over Llimphi.
|
||||
|
||||
Two panels side by side:
|
||||
|
||||
- **Pie chart (donut)** — six slices of a synthetic budget.
|
||||
- **Radar (spider)** — a profile of six attributes against a common maximum.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-stream-demo
|
||||
|
||||
> Demo del backend streaming de [pineal](../README.md).
|
||||
> Demo del backend streaming de [pineal](../../README.md).
|
||||
|
||||
Genera muestras a 60 Hz (varias series simultáneas) y las pushea a [`pineal-stream`](../pineal-stream/README.md). Demuestra el scroll suave y la composición de múltiples series sobre el mismo eje de tiempo.
|
||||
Genera muestras a 60 Hz (varias series simultáneas) y las pushea a [`pineal-stream`](../../pineal-stream/README.md). Demuestra el scroll suave y la composición de múltiples series sobre el mismo eje de tiempo.
|
||||
|
||||
## Uso
|
||||
|
||||
@@ -12,4 +12,4 @@ cargo run --release -p pineal-stream-demo
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-stream`](../pineal-stream/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-stream`](../../pineal-stream/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# pineal-stream-demo
|
||||
|
||||
> Streaming backend demo for [pineal](../README.md).
|
||||
> Streaming backend demo for [pineal](../../README.md).
|
||||
|
||||
Generates samples at 60 Hz (several simultaneous series) and pushes them to [`pineal-stream`](../pineal-stream/README.md). Demonstrates smooth scrolling and composition of multiple series on the same time axis.
|
||||
Generates samples at 60 Hz (several simultaneous series) and pushes them to [`pineal-stream`](../../pineal-stream/README.md). Demonstrates smooth scrolling and composition of multiple series on the same time axis.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -12,4 +12,4 @@ cargo run --release -p pineal-stream-demo
|
||||
|
||||
## Deps
|
||||
|
||||
- [`pineal-stream`](../pineal-stream/README.md), [`pineal-render`](../pineal-render/README.md)
|
||||
- [`pineal-stream`](../../pineal-stream/README.md), [`pineal-render`](../../pineal-render/README.md)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# pineal-treemap-demo
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Treemap squarified con 12 tiles.
|
||||
|
||||
Pesos escogidos a mano para mostrar el algoritmo cuando hay
|
||||
mezcla de tiles grandes y chicas. El squarified minimiza el
|
||||
peor aspect ratio en cada fila/columna; las tiles chicas
|
||||
quedan amontonadas en una banda angosta.
|
||||
|
||||
Lleva barra de menú principal (Archivo/Ver/Ayuda) + un menú
|
||||
contextual sobre el plot. No hay edición ni clipboard — el treemap
|
||||
es un canvas estático, así que el contextual sólo ofrece cambiar
|
||||
tema.
|
||||
|
||||
## Uso
|
||||
|
||||
```sh
|
||||
cargo run --release -p pineal-treemap-demo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../../LEEME.md).
|
||||
@@ -0,0 +1,11 @@
|
||||
# pineal-treemap-demo
|
||||
|
||||
A squarified treemap with 12 tiles.
|
||||
|
||||
Weights chosen by hand to show the algorithm when there is a mix of large and
|
||||
small tiles. Squarifying minimizes the worst aspect ratio in each row or column;
|
||||
the small tiles end up crowded into a narrow band.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../../README.md).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 248 KiB |
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — barras: columnas/barras simples, agrupadas y apiladas (vertical u horizontal) + histograma. Painter agnóstico sobre el trait Canvas."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — barras: columnas/barras simples, agrupadas y apiladas (vertical u horizontal) + histograma. Painter agnóstico sobre el trait Canvas."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# pineal-bars
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
El painter de barras del catálogo.
|
||||
|
||||
El gráfico más común que faltaba: columnas/barras. Como todo en
|
||||
pineal, es agnóstico del backend — sólo emite `fill_rect` contra el
|
||||
trait `pineal_render::Canvas`, así que sirve igual sobre
|
||||
vello/llimphi, PNG, SVG, PDF o el camino GPU directo.
|
||||
|
||||
- `paint_bars` — una serie: barras desde un baseline, vertical u
|
||||
horizontal, con soporte para valores negativos.
|
||||
- `paint_grouped` — varias series por categoría, agrupadas
|
||||
(clustered) lado a lado.
|
||||
- `paint_stacked` — segmentos apilados sobre un baseline común.
|
||||
- `Histogram` — bineado de una muestra `&[f32]` en conteos, listo
|
||||
para pasar a `paint_bars` como histograma.
|
||||
|
||||
El eje, los ticks y las etiquetas no son responsabilidad del painter
|
||||
(regla del SDD: el texto va por una pasada vello hermana). Aquí sólo
|
||||
viven los rectángulos.
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-bars
|
||||
|
||||
The catalog's bar painter.
|
||||
|
||||
The most common chart that was missing: columns and bars. Like everything in
|
||||
pineal it is backend-agnostic — it only emits `fill_rect` against the
|
||||
`pineal_render::Canvas` trait, so it works equally over vello/llimphi, PNG, SVG,
|
||||
PDF or the direct GPU path.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../README.md).
|
||||
@@ -14,7 +14,7 @@
|
||||
//! para pasar a `paint_bars` como histograma.
|
||||
//!
|
||||
//! El eje, los ticks y las etiquetas no son responsabilidad del painter
|
||||
//! (regla del SDD: el texto va por una pasada vello hermana). Acá sólo
|
||||
//! (regla del SDD: el texto va por una pasada vello hermana). Aquí sólo
|
||||
//! viven los rectángulos.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
@@ -33,7 +33,7 @@ pub struct BarStyle {
|
||||
/// Fracción del slot de cada categoría que va a separación, en
|
||||
/// `[0, 1)`. `0.0` = barras pegadas; `0.2` = 20 % de aire.
|
||||
pub gap_ratio: f32,
|
||||
/// Valor del cero. Las barras nacen acá; valores por debajo crecen
|
||||
/// Valor del cero. Las barras nacen aquí; valores por debajo crecen
|
||||
/// en sentido contrario. Normalmente `0.0`.
|
||||
pub baseline: f64,
|
||||
/// Override del rango de valor. `None` = automático a partir de los
|
||||
|
||||
@@ -4,10 +4,18 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — gráficos cartesianos: LineSeries / BarSeries / AreaSeries, viewport con pan/zoom, picture cache, ejes con decimación, tooltips."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — gráficos cartesianos: LineSeries / BarSeries / AreaSeries, viewport con pan/zoom, picture cache, ejes con decimación, tooltips."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
llimphi-ui = { workspace = true }
|
||||
pineal-core = { path = "../pineal-core", version = "0.1.0" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0", default-features = false }
|
||||
llimphi-ui = { workspace = true, optional = true }
|
||||
|
||||
# `llimphi` (default) habilita `ChartView` (el `View<Msg>` declarativo).
|
||||
# Sin él quedan los painters puros (axis/series/coord_system/viewport),
|
||||
# consumibles headless contra cualquier `Canvas` (p. ej. `PlanRecorder`).
|
||||
[features]
|
||||
default = ["llimphi"]
|
||||
llimphi = ["dep:llimphi-ui", "pineal-render/llimphi"]
|
||||
|
||||
@@ -67,7 +67,7 @@ pub fn ticks_nice(min: f64, max: f64, target_ticks: usize) -> Vec<f64> {
|
||||
///
|
||||
/// `min_spacing_px` es la distancia mínima entre el borde
|
||||
/// derecho de un label aprobado y el borde izquierdo del
|
||||
/// siguiente. Si no tenés el ancho del label, pasá un valor
|
||||
/// siguiente. Si no tienes el ancho del label, pasa un valor
|
||||
/// conservador (≈ 48 px del Flutter doc).
|
||||
pub fn decimate_labels(
|
||||
positions_px: &[f32],
|
||||
|
||||
@@ -21,12 +21,14 @@ pub mod viewport;
|
||||
pub mod coord_system;
|
||||
pub mod series;
|
||||
pub mod axis;
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub mod view;
|
||||
|
||||
pub use viewport::ChartViewport;
|
||||
pub use coord_system::CoordinateSystem;
|
||||
pub use series::{LineSeries, PaintCtx, RenderMode, Series};
|
||||
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub use view::{
|
||||
chart_cache, lapaloma_chart_view, ChartCache, ChartCacheHandle, ChartSeriesItem, ChartView,
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! El viewport NO conoce pixeles. Sólo describe qué rango de
|
||||
//! valores X/Y es visible. La proyección a píxeles la hace
|
||||
//! [`crate::coord_system::CoordinateSystem`] cuando le pasás
|
||||
//! [`crate::coord_system::CoordinateSystem`] cuando le pasas
|
||||
//! el `plot_rect`.
|
||||
//!
|
||||
//! Pan y zoom mutan el viewport, no los datos. Esto preserva el
|
||||
|
||||
@@ -4,9 +4,10 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — contour: marching squares sobre matriz escalar → polilíneas por isolínea."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — contour: marching squares sobre matriz escalar → polilíneas por isolínea."
|
||||
|
||||
[dependencies]
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-heatmap = { path = "../pineal-heatmap" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
pineal-heatmap = { path = "../pineal-heatmap", version = "0.1.0" }
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# pineal-contour
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Isolíneas vía marching squares.
|
||||
|
||||
Dada una `HeatmapMatrix` y un nivel `iso`, extrae los segmentos
|
||||
donde la función vale exactamente `iso` aproximada por interpolación
|
||||
lineal en los bordes de cada celda. Compone con `pineal-cartesian`
|
||||
para mapas topográficos, líneas de presión, equipotenciales, etc.
|
||||
|
||||
- `extract_contour` — un nivel → `Vec` de segmentos `[x0,y0,x1,y1]`.
|
||||
- `extract_contours` — N niveles equiespaciados.
|
||||
- `paint_contours` — pinta cada nivel como polilínea contra `Canvas`.
|
||||
|
||||
Implementación: marching squares clásico — para cada celda 2×2 se
|
||||
computa un índice 4-bit a partir del signo de cada esquina respecto
|
||||
a `iso`; un lookup table de 16 casos da los 0/1/2 segmentos. Sin
|
||||
ambigüedad resolution (los casos 5 y 10 saddle se rompen siempre
|
||||
del mismo lado — suficiente para charts).
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-contour
|
||||
|
||||
Isolines through marching squares.
|
||||
|
||||
Given a `HeatmapMatrix` and an `iso` level, it extracts the segments where the
|
||||
function is exactly `iso`, approximated by linear interpolation on each cell's
|
||||
edges. It composes with `pineal-cartesian` for topographic maps, pressure lines,
|
||||
equipotentials and so on.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../README.md).
|
||||
@@ -4,8 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — primitivas agnósticas: DataBuffer interleaved, RingBuffer streaming, SpatialIndex, LTTB, escalas. Cero deps de UI, cero alloc en hot path."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — primitivas agnósticas: DataBuffer interleaved, RingBuffer streaming, SpatialIndex, LTTB, escalas. Cero deps de UI, cero alloc en hot path."
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ impl DataBuffer {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Reserva espacio para `n` puntos sin agregarlos. Usalo al
|
||||
/// Reserva espacio para `n` puntos sin agregarlos. Úsalo al
|
||||
/// montar el widget para que `push` no realloque después.
|
||||
pub fn with_capacity(n: usize) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! `pineal-core` — primitivas agnósticas de Lapaloma.
|
||||
//!
|
||||
//! Cero `gpui`, cero `wgpu`, cero I/O. Todo lo que vive acá puede
|
||||
//! Cero `gpui`, cero `wgpu`, cero I/O. Todo lo que vive aquí puede
|
||||
//! correr en un test unitario, en un worker thread o en un export
|
||||
//! a SVG. Las tres reglas del documento de arquitectura aplican:
|
||||
//!
|
||||
@@ -10,7 +10,7 @@
|
||||
//! - **P2 Zero alloc en hot path.** Buffers se reservan al construir,
|
||||
//! se mutan in-place para siempre. Helpers escriben a `&mut Vec`
|
||||
//! provistos por el caller, no devuelven `Vec` nuevos.
|
||||
//! - **P3 Una draw call por capa.** Acá no se dibuja; pero los
|
||||
//! - **P3 Una draw call por capa.** Aquí no se dibuja; pero los
|
||||
//! tipos exponen slices contiguos listos para mandar al GPU
|
||||
//! sin copia.
|
||||
//!
|
||||
@@ -28,7 +28,7 @@ pub mod lttb;
|
||||
pub mod scale;
|
||||
|
||||
// Algoritmos de layout: cada uno vive en el crate de la viz que lo
|
||||
// usa, no acá. Esto es deliberado — `pineal-core` no debe arrastrar
|
||||
// usa, no aquí. Esto es deliberado — `pineal-core` no debe arrastrar
|
||||
// dependencias de visualización.
|
||||
//
|
||||
// - Barnes-Hut + Sugiyama + tree layout: `pineal-mesh`.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! temporales) un binary search basta y es O(log n) sin estructuras
|
||||
//! auxiliares. Para nodos que se mueven cada frame (mesh graph)
|
||||
//! corresponde un spatial hash uniforme — ese va en `pineal-mesh`,
|
||||
//! no acá.
|
||||
//! no aquí.
|
||||
|
||||
/// View sobre un buffer interleaved `[x0,y0,x1,y1,…]` sorted-asc por X.
|
||||
///
|
||||
|
||||
@@ -4,10 +4,11 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — exporters. SVG primero, PDF después. Decimación contextual por DPI: target = width_inches × dpi × vertices_per_pixel."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — exporters. SVG primero, PDF después. Decimación contextual por DPI: target = width_inches × dpi × vertices_per_pixel."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-core = { path = "../pineal-core", version = "0.1.0" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0", default-features = false }
|
||||
png = { workspace = true }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! codifica como PNG.
|
||||
//!
|
||||
//! La estrategia es la misma que `svg.rs`: el painter grabó cada comando
|
||||
//! en un plan; acá lo replayeamos contra un rasterizador software
|
||||
//! en un plan; aquí lo replayeamos contra un rasterizador software
|
||||
//! propio. No depende de `tiny-skia` ni `cairo` — sólo `png` (ya en el
|
||||
//! workspace) y aritmética f32. Esto mantiene la cadena
|
||||
//! `core → render → export` libre de stack gráfico nativo.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Exporter SVG: un [`RenderPlan`] → documento SVG completo.
|
||||
//!
|
||||
//! El mismo painter que dibuja en pantalla (vía el trait `Canvas`) se
|
||||
//! graba con un `PlanRecorder` y el plan resultante se vuelca acá. Un
|
||||
//! graba con un `PlanRecorder` y el plan resultante se vuelca aquí. Un
|
||||
//! solo camino de código para screen y export.
|
||||
//!
|
||||
//! v1: los comandos de clip (`PushClip`/`PopClip`) se ignoran — el
|
||||
|
||||
@@ -4,11 +4,11 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — gráficos financieros. OHLC / candlesticks con agregación que preserva volatilidad (no LTTB, time-bucketing con max/min de wicks)."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — gráficos financieros. OHLC / candlesticks con agregación que preserva volatilidad (no LTTB, time-bucketing con max/min de wicks)."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-cartesian = { path = "../pineal-cartesian" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
pineal-cartesian = { path = "../pineal-cartesian", version = "0.1.0" }
|
||||
llimphi-ui = { workspace = true }
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//! - `volume` = sum(`volume`) del bucket.
|
||||
//! - `t` = timestamp del primer bar del bucket (canónico para
|
||||
//! ploteo; el doc original sugiere usar el inicio del bucket
|
||||
//! pero acá preferimos el sample real para no introducir bias).
|
||||
//! pero aquí preferimos el sample real para no introducir bias).
|
||||
//!
|
||||
//! Buckets vacíos no se emiten — el length de salida es ≤ inputs.
|
||||
//! Fallback a index-bucketing si el span temporal es cero (todos
|
||||
|
||||
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — diagramas de flujo Sankey: columnas topológicas + barycenter ordering + ribbons como triangle strips de béziers."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — diagramas de flujo Sankey: columnas topológicas + barycenter ordering + ribbons como triangle strips de béziers."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — heatmap. Matriz [width × height] de f32 → imagen pre-encodeada que se rendea con un sólo drawImageRect."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — heatmap. Matriz [width × height] de f32 → imagen pre-encodeada que se rendea con un sólo drawImageRect."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -4,9 +4,10 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — hexbin: bineado hexagonal pointy-top de un dataset 2D + painter."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — hexbin: bineado hexagonal pointy-top de un dataset 2D + painter."
|
||||
|
||||
[dependencies]
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-heatmap = { path = "../pineal-heatmap" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
pineal-heatmap = { path = "../pineal-heatmap", version = "0.1.0" }
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# pineal-hexbin
|
||||
|
||||
*Read this in English: [README.md](README.md).*
|
||||
|
||||
Bineado hexagonal de scatter densos.
|
||||
|
||||
Cuando un scatter tiene tantos puntos que la nube tapa el patrón,
|
||||
binear sobre una rejilla hexagonal pointy-top y colorear por
|
||||
densidad es la forma estándar de revelar la distribución. La
|
||||
topología hexagonal evita los "estrías" rectangulares de un binning
|
||||
cuadrado y respeta mejor la isotropía de la nube.
|
||||
|
||||
- `HexGrid` — calcula el bin de cada `(x, y)` con la rejilla
|
||||
pointy-top (hex con dos vértices arriba/abajo). Cell size = radio
|
||||
del circumcírculo.
|
||||
- `paint_hexbin` — pinta los bins no vacíos como hexágonos
|
||||
rellenos coloreados por densidad vía `pineal_heatmap::Ramp`.
|
||||
|
||||
---
|
||||
|
||||
Parte de **pineal** — ver [pineal](../LEEME.md).
|
||||
@@ -0,0 +1,12 @@
|
||||
# pineal-hexbin
|
||||
|
||||
Hexagonal binning of dense scatters.
|
||||
|
||||
When a scatter has so many points that the cloud hides the pattern, binning over a
|
||||
pointy-top hexagonal grid and colouring by density is the standard way to reveal
|
||||
the distribution. The hexagonal topology avoids the rectangular "striping" of a
|
||||
square binning.
|
||||
|
||||
---
|
||||
|
||||
Part of **pineal** — see [pineal](../README.md).
|
||||
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — grafos. NodeBuffer / EdgeBuffer + layouts (force-directed con Barnes-Hut, Sugiyama-lite jerárquico, subtree-width)."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — grafos. NodeBuffer / EdgeBuffer + layouts (force-directed con Barnes-Hut, Sugiyama-lite jerárquico, subtree-width)."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> Canvas de triángulos arbitrarios para [pineal](../README.md).
|
||||
|
||||
Backend para geometría libre: tomá una malla `(vertices, indices, colors)` y se dibuja con shader-like flexibility. Útil para terrenos, geometría 2D compleja, ilustraciones generativas.
|
||||
Backend para geometría libre: toma una malla `(vertices, indices, colors)` y se dibuja con shader-like flexibility. Útil para terrenos, geometría 2D compleja, ilustraciones generativas.
|
||||
|
||||
## API
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//! Theta típico: 0.5 — más bajo = más preciso, más lento.
|
||||
//!
|
||||
//! Representación: `Vec<QuadNode>` indexado. El doc original de
|
||||
//! `pineal-core::barnes_hut` propone stride 7 plano; acá optamos por la
|
||||
//! `pineal-core::barnes_hut` propone stride 7 plano; aquí optamos por la
|
||||
//! versión idiomática — clara y suficiente para los rangos en que el
|
||||
//! force-directed corre interactivo (hasta ~50 K nodos).
|
||||
|
||||
@@ -22,7 +22,7 @@ struct QuadNode {
|
||||
/// Center of mass acumulado.
|
||||
cm_x: f32,
|
||||
cm_y: f32,
|
||||
/// Masa total (suma de pesos — acá usamos 1.0 por nodo).
|
||||
/// Masa total (suma de pesos — aquí usamos 1.0 por nodo).
|
||||
mass: f32,
|
||||
/// Hoja con exactamente 1 cuerpo: índice del cuerpo en `positions`.
|
||||
body: Option<usize>,
|
||||
|
||||
@@ -4,10 +4,11 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — decoración CRT sobre lapaloma-stream: trail con alpha decay por edad, ghost, anotaciones magnéticas ancladas a sample index."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — decoración CRT sobre lapaloma-stream: trail con alpha decay por edad, ghost, anotaciones magnéticas ancladas a sample index."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-core = { path = "../pineal-core", version = "0.1.0" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
llimphi-ui = { workspace = true }
|
||||
|
||||
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — gráficos polares: pie chart, donut, radar."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — gráficos polares: pie chart, donut, radar."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -4,9 +4,16 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — abstracción de painter: trait Canvas + RenderPlan + color helpers. Backend Llimphi (vello/wgpu) consumido por demos y consumidores upstream sin tocar a los painters."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — abstracción de painter: trait Canvas + RenderPlan + color helpers. Backend Llimphi (vello/wgpu) consumido por demos y consumidores upstream sin tocar a los painters."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
llimphi-ui = { workspace = true }
|
||||
llimphi-ui = { workspace = true, optional = true }
|
||||
|
||||
# `llimphi` (default) habilita los backends SceneCanvas/GpuSceneCanvas.
|
||||
# Sin él queda el núcleo agnóstico (Canvas + RenderPlan + PlanRecorder),
|
||||
# consumible headless sin arrastrar el stack gráfico.
|
||||
[features]
|
||||
default = ["llimphi"]
|
||||
llimphi = ["dep:llimphi-ui"]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//! `pineal-render` — abstracción de painter.
|
||||
//!
|
||||
//! Los crates de visualización (cartesian, mesh, polar…) no conocen
|
||||
//! el runtime de UI: hablan contra el trait [`Canvas`] definido acá.
|
||||
//! el runtime de UI: hablan contra el trait [`Canvas`] definido aquí.
|
||||
//! Eso deja a la cadena `core → render → painter` agnóstica.
|
||||
//!
|
||||
//! Backends activos:
|
||||
//!
|
||||
//! - **Llimphi/vello** ([`llimphi_backend::SceneCanvas`]) — canónico
|
||||
//! para apps gioser; pinta dentro de un `paint_with` del `View<Msg>`
|
||||
//! para apps tawasuyu; pinta dentro de un `paint_with` del `View<Msg>`
|
||||
//! declarativo.
|
||||
//! - **PlanRecorder** ([`recorder::PlanRecorder`]) — graba cada llamada
|
||||
//! como `RenderCmd`. Consumido por `pineal-export` para emitir SVG,
|
||||
@@ -18,7 +18,7 @@
|
||||
//! en lugar de `paint_with`. Los painters no cambian. Sin texto y sin
|
||||
//! AA fino — ver doc del módulo para trade-offs.
|
||||
//!
|
||||
//! Tipos primitivos (`Color`, `Point`, `Rect`) viven acá para no
|
||||
//! Tipos primitivos (`Color`, `Point`, `Rect`) viven aquí para no
|
||||
//! atarlos al tipo de color/punto de ningún runtime.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
@@ -29,7 +29,9 @@ pub mod canvas;
|
||||
pub mod plan;
|
||||
pub mod recorder;
|
||||
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub mod llimphi_backend;
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub mod gpu_canvas;
|
||||
|
||||
pub use color::Color;
|
||||
@@ -38,5 +40,7 @@ pub use canvas::{Canvas, StrokeStyle};
|
||||
pub use plan::{RenderCmd, RenderPlan};
|
||||
pub use recorder::PlanRecorder;
|
||||
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub use llimphi_backend::SceneCanvas;
|
||||
#[cfg(feature = "llimphi")]
|
||||
pub use gpu_canvas::GpuSceneCanvas;
|
||||
|
||||
@@ -4,10 +4,11 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — widget de telemetría tipo osciloscopio. Ring buffer + envelope min/max por columna + render en dos segmentos (split at head)."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — widget de telemetría tipo osciloscopio. Ring buffer + envelope min/max por columna + render en dos segmentos (split at head)."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-core = { path = "../pineal-core", version = "0.1.0" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
llimphi-ui = { workspace = true }
|
||||
|
||||
@@ -4,9 +4,9 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — treemap con algoritmo squarified (Bruls / d3-hierarchy formulation)."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — treemap con algoritmo squarified (Bruls / d3-hierarchy formulation)."
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core" }
|
||||
pineal-render = { path = "../pineal-render" }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0" }
|
||||
|
||||
@@ -4,25 +4,28 @@ version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
license = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
publish = { workspace = true }
|
||||
description = "Lapaloma — paraguas: re-exporta los módulos para prototipos. En producción importar los crates hoja directamente para que tree-shaking descarte lo no usado."
|
||||
repository = { workspace = true }
|
||||
publish = true
|
||||
description = "Pineal — paraguas: re-exporta los módulos para prototipos. En producción importar los crates hoja directamente para que tree-shaking descarte lo no usado."
|
||||
keywords = ["visualization", "charts", "plotting", "graph", "svg"]
|
||||
categories = ["visualization", "graphics", "rendering"]
|
||||
|
||||
[dependencies]
|
||||
pineal-core = { path = "../pineal-core", optional = true }
|
||||
pineal-render = { path = "../pineal-render", optional = true }
|
||||
pineal-cartesian = { path = "../pineal-cartesian", optional = true }
|
||||
pineal-stream = { path = "../pineal-stream", optional = true }
|
||||
pineal-mesh = { path = "../pineal-mesh", optional = true }
|
||||
pineal-financial = { path = "../pineal-financial", optional = true }
|
||||
pineal-polar = { path = "../pineal-polar", optional = true }
|
||||
pineal-heatmap = { path = "../pineal-heatmap", optional = true }
|
||||
pineal-treemap = { path = "../pineal-treemap", optional = true }
|
||||
pineal-flow = { path = "../pineal-flow", optional = true }
|
||||
pineal-phosphor = { path = "../pineal-phosphor", optional = true }
|
||||
pineal-export = { path = "../pineal-export", optional = true }
|
||||
pineal-hexbin = { path = "../pineal-hexbin", optional = true }
|
||||
pineal-contour = { path = "../pineal-contour", optional = true }
|
||||
pineal-bars = { path = "../pineal-bars", optional = true }
|
||||
pineal-core = { path = "../pineal-core", version = "0.1.0", optional = true }
|
||||
pineal-render = { path = "../pineal-render", version = "0.1.0", optional = true }
|
||||
pineal-cartesian = { path = "../pineal-cartesian", version = "0.1.0", optional = true }
|
||||
pineal-stream = { path = "../pineal-stream", version = "0.1.0", optional = true }
|
||||
pineal-mesh = { path = "../pineal-mesh", version = "0.1.0", optional = true }
|
||||
pineal-financial = { path = "../pineal-financial", version = "0.1.0", optional = true }
|
||||
pineal-polar = { path = "../pineal-polar", version = "0.1.0", optional = true }
|
||||
pineal-heatmap = { path = "../pineal-heatmap", version = "0.1.0", optional = true }
|
||||
pineal-treemap = { path = "../pineal-treemap", version = "0.1.0", optional = true }
|
||||
pineal-flow = { path = "../pineal-flow", version = "0.1.0", optional = true }
|
||||
pineal-phosphor = { path = "../pineal-phosphor", version = "0.1.0", optional = true }
|
||||
pineal-export = { path = "../pineal-export", version = "0.1.0", optional = true }
|
||||
pineal-hexbin = { path = "../pineal-hexbin", version = "0.1.0", optional = true }
|
||||
pineal-contour = { path = "../pineal-contour", version = "0.1.0", optional = true }
|
||||
pineal-bars = { path = "../pineal-bars", version = "0.1.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["full"]
|
||||
|
||||
Generated
+1615
-351
File diff suppressed because it is too large
Load Diff
+301
-107
@@ -1,7 +1,13 @@
|
||||
# Cargo.toml raíz STANDALONE de pineal — front-door sobre Llimphi.
|
||||
# Solo el código de pineal; Llimphi y lo fundacional por git-dep del monorepo gioser.git.
|
||||
# Cargo.toml raíz STANDALONE de pineal — front-door público.
|
||||
# GENERADO por scripts/actualizar-standalone.py desde el monorepo tawasuyu.git
|
||||
# (v0.2.0). No editar a mano: se regenera. Lo fundacional se consume por
|
||||
# git-dep al tag; sólo el código del dominio vive en este repo.
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
# ============================================================
|
||||
# Cuadrantes — agregar a medida que se migran
|
||||
# ============================================================
|
||||
members = [
|
||||
"00_unanchay/pineal/demos/pineal-bars-demo",
|
||||
"00_unanchay/pineal/demos/pineal-contour-demo",
|
||||
@@ -35,6 +41,11 @@ members = [
|
||||
"00_unanchay/pineal/pineal-umbrella",
|
||||
]
|
||||
|
||||
# `wawa/` se excluye del workspace global porque corre en target
|
||||
# `x86_64-unknown-none` y `panic = "abort"`, incompatibles con los
|
||||
# perfiles globales. Los crates compartidos se referencian por `path`
|
||||
# cruzando la frontera.
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
@@ -45,9 +56,32 @@ publish = false
|
||||
repository = "https://git.tawasuyu.net/tawasuyu/pineal"
|
||||
|
||||
[workspace.dependencies]
|
||||
|
||||
# === Configuración declarativa (vocabulario de esquemas) ===
|
||||
allichay = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
marca = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# Telemetría local de desarrollo (stderr+panics+tracing → $XDG_STATE_HOME/tawasuyu/<dominio>/<bin>.log)
|
||||
bitacora = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# default = [] (núcleo liviano sin vello); `bake` es opt-in. Declaramos
|
||||
# default-features = false aquí para que el `default-features = false` de los
|
||||
# consumidores (splash/greeter/compositor) se honre y no quede el warning.
|
||||
mirada-fondo = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
mirada-teclado-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
mirada-teclado-widget = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# === Registro de apps / menú global ===
|
||||
app-bus = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
app-bus = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
app-iconset = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# === Centro de eventos (notificaciones + capturas + clipboard + …) ===
|
||||
willay-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
willay-checkpoint = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
willay-hilo = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
willay-store = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
willay-emit = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
rag-motor = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
churay-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
churay-welcome = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
churay-welcome-runner = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# === Puente de drag-and-drop compositor → app (suple winit en Wayland) ===
|
||||
drop-bridge = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# === Serialización ===
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -74,8 +108,12 @@ tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
||||
|
||||
# === Linux primitives (arje) ===
|
||||
nix = { version = "0.29", features = ["signal", "process", "sched", "mount", "fs", "socket", "net", "user"] }
|
||||
nix = { version = "0.29", features = ["signal", "process", "sched", "mount", "fs", "socket", "net", "user", "reboot"] }
|
||||
libc = "0.2"
|
||||
# DRM/KMS legacy (dumb buffer) para el splash nativo del arranque sin parpadeo.
|
||||
# Misma versión que reexporta smithay (mirada-compositor) — el lock ya la fija.
|
||||
drm = "0.14"
|
||||
font8x8 = { version = "0.3", default-features = false }
|
||||
|
||||
# === IDs / Hash / Crypto ===
|
||||
ulid = { version = "1", features = ["serde"] }
|
||||
@@ -89,10 +127,15 @@ argon2 = "0.5"
|
||||
rand = "0.8"
|
||||
|
||||
# === WASM (arje) ===
|
||||
# wasmi 1.0: unifica la versión con renaser (su kernel ya corre 1.0), para
|
||||
# wasmi 1.0: unifica la versión con wawa (su kernel ya corre 1.0), para
|
||||
# que el ABI WASM del host sea idéntico en Linux y en bare-metal.
|
||||
wasmi = "1.0"
|
||||
wat = "1"
|
||||
# wasmtime 46 (Fase 1 del pipeline JS): tier 0 de puriy-js pasa de wasmi
|
||||
# (intérprete) a Wasmtime AOT (Cranelift → nativo) en Linux — quita la doble
|
||||
# interpretación de QuickJS.wasm. En wawa bare-metal el runtime es Pulley (spike
|
||||
# Q1 cerrado); mismo crate, distinto backend.
|
||||
wasmtime = "46"
|
||||
|
||||
# === Storage / DB ===
|
||||
sled = "0.34"
|
||||
@@ -107,6 +150,10 @@ bzip2 = "0.4"
|
||||
|
||||
# === Compresión (minga multi-bundle) ===
|
||||
zstd = "0.13"
|
||||
xz2 = "0.1"
|
||||
# Contenedores adicionales del visor Archive de nahual (sólo listado).
|
||||
sevenz-rust = "0.6"
|
||||
unrar = "0.5"
|
||||
|
||||
# === HTTP server (iniy-server) ===
|
||||
axum = "0.7"
|
||||
@@ -116,7 +163,7 @@ tower = "0.5"
|
||||
instant-distance = "0.6"
|
||||
|
||||
# === P2P (minga) ===
|
||||
libp2p = { version = "0.56", features = ["tokio", "tcp", "noise", "yamux", "macros", "kad", "identify", "relay", "dcutr", "autonat", "mdns"] }
|
||||
libp2p = { version = "0.56", features = ["tokio", "tcp", "dns", "noise", "yamux", "macros", "kad", "identify", "relay", "dcutr", "autonat", "mdns"] }
|
||||
libp2p-stream = "=0.4.0-alpha"
|
||||
libp2p-allow-block-list = "0.6"
|
||||
|
||||
@@ -131,7 +178,11 @@ libm = "0.2"
|
||||
midly = "0.5"
|
||||
|
||||
# === Code parsing (minga) ===
|
||||
arboard = "3"
|
||||
# `wayland-data-control` trae el backend wl-clipboard-rs: bajo mirada (Wayland
|
||||
# propio, sin Xwayland para apps nativas) arboard-x11 fallaba a no-op silencioso
|
||||
# y el clipboard de los text-editor quedaba muerto. Con la feature habla
|
||||
# zwlr_data_control_manager_v1 (que mirada expone) y cae a X11 si no hay Wayland.
|
||||
arboard = { version = "3", features = ["wayland-data-control"] }
|
||||
ropey = "1.6"
|
||||
tree-sitter = "0.24"
|
||||
tree-sitter-rust = "0.23"
|
||||
@@ -150,7 +201,19 @@ petgraph = "0.6"
|
||||
# default-features = false: nos quedamos con PNG + JPEG + WebP (lossless).
|
||||
# tullpu-render exporta a las tres; AVIF/TIFF/… los habilitamos si una app
|
||||
# los pide específicamente.
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp"] }
|
||||
# Decoders puro-Rust baratos; avif queda fuera (arrastra dav1d/rav1e).
|
||||
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp", "gif", "bmp", "ico", "tiff", "tga", "qoi"] }
|
||||
# ONNX Runtime para los proveedores de píxel reales (pixel-verbo-onnx: segmentación
|
||||
# u2net/isnet, inpaint, restyle…). `download-binaries` (default) baja el runtime nativo
|
||||
# solo; ya lo arrastraba fastembed (rimay-verbo) transitivo — aquí lo declaramos directo.
|
||||
ort = "2.0.0-rc.9"
|
||||
|
||||
# Rasterizador vectorial CPU (relleno/trazo anti-aliased) para capas vectoriales de tullpu.
|
||||
tiny-skia = "0.11"
|
||||
# Booleanos de polígonos robustos (union/intersection/difference/xor) para el
|
||||
# clipper vectorial de tullpu — restar/intersecar paths que se solapan
|
||||
# parcialmente, que la regla de relleno no expresa. Ya estaba en el lock.
|
||||
geo = "0.28"
|
||||
|
||||
# === FUSE (minga-vfs) ===
|
||||
# default-features = false: prescinde de pkg-config/libfuse-dev en build.
|
||||
@@ -172,91 +235,164 @@ tempfile = "3"
|
||||
|
||||
# === Llimphi (motor gráfico soberano) ===
|
||||
# wgpu sobre Vulkan/Metal/DX12, winit para ventana en dev Linux.
|
||||
# raw-window-handle 0.6 alinea winit 0.30 con wgpu 24.
|
||||
# vello 0.5 = rasterizador vectorial sobre wgpu 24.
|
||||
# raw-window-handle 0.6 alinea winit 0.30 con wgpu 27.
|
||||
# vello 0.7 = rasterizador vectorial sobre wgpu 27 (renderer GPU "wgpu" + opt-in "hybrid" CPU+GPU).
|
||||
# taffy 0.9 = motor Flexbox/Grid puro Rust (ya pulled por transitivos, lo alineamos).
|
||||
# parley 0.2 = shaping/layout de texto compatible con peniko 0.4 (que vello 0.5 expone).
|
||||
wgpu = "24"
|
||||
# parley 0.6 = shaping/layout de texto compatible con peniko 0.6 (que vello 0.7 expone).
|
||||
wgpu = "27"
|
||||
winit = "0.30"
|
||||
raw-window-handle = "0.6"
|
||||
pollster = "0.4"
|
||||
vello = "0.5"
|
||||
vello = "0.7"
|
||||
# Renderer hybrid CPU+GPU sin compute shaders (mejor compat WebGL2/Adreno viejas).
|
||||
# Opt-in; el renderer "wgpu" sigue siendo el default.
|
||||
vello_hybrid = "0.0.9"
|
||||
# foreign-lottie = fork vendorizado de velato 0.9 (Lottie → vello::Scene),
|
||||
# completado para no paniquear ante features no soportadas. Lo consume
|
||||
# llimphi-lottie. Ver shared/foreign-lottie.
|
||||
foreign-lottie = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# Árbol de accesibilidad para lectores de pantalla (NVDA/VoiceOver/Orca/TalkBack).
|
||||
# Lo consume el runtime de Llimphi (iter 2/3 del plan AccessKit); el modelo
|
||||
# `SemanticsSpec` del compositor es independiente de estas crates.
|
||||
accesskit = "0.24"
|
||||
accesskit_winit = "0.33"
|
||||
taffy = "0.9"
|
||||
# parley = shaping completo (bidi, ligatures, fallback CJK/emoji vía fontique, line break).
|
||||
parley = "0.4"
|
||||
parley = "0.6"
|
||||
# Bucle Elm (input→update→view→layout→raster→present). Lo consumen las apps.
|
||||
llimphi-ui = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-ui = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Tier 3 — apps WASM con UI Llimphi real. El guest pinta un WireNode (IR
|
||||
# serializable), el host (runner) lo materializa en View<Msg> y rebota los
|
||||
# eventos al update del guest. SDK = lado guest, runner = lado host.
|
||||
llimphi-wire-view = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-wasm-app-sdk = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-wasm-runner = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Núcleo puro de distribución (CAS + verificación + resolve), SIN runner/GPU.
|
||||
llimphi-wasm-core = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Cara con baterías: re-exporta core + puente al runner para correr la app.
|
||||
llimphi-wasm-dist = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-wasm-open = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-wasm-registry = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-wasm-wasi = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Transporte P2P del bytecode por hash sobre BrahmanNet (card-net).
|
||||
llimphi-wasm-net = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-3d = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Runner wlr-layer-shell: corre un `App` de Llimphi como barra anclada a un
|
||||
# borde (no como ventana), reusando la plumbing sctk+wgpu que pata probó.
|
||||
llimphi-layer = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Paleta semántica compartida por las apps y los widgets.
|
||||
llimphi-theme = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-theme = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Tweens y helpers de animación sobre el bucle Elm.
|
||||
llimphi-motion = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-motion = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Máquina de estados de animación (estilo Rive) clip-agnóstica. Núcleo puro;
|
||||
# el render lo cablea el consumidor (llimphi-lottie). Escalón sobre el playback.
|
||||
llimphi-anim = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Studio de animación «rive»: además del editor (bin), expone como lib los
|
||||
# documentos serializables (Doc + RigDoc + Project) que carga mirada-fondo.
|
||||
llimphi-anim-studio = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Render de mallas deformables (skel::Mesh) a vello Scene: vectorial y texturizada.
|
||||
llimphi-mesh = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Iconos vectoriales (BezPath en grid 24×24) compartidos por todas las apps.
|
||||
llimphi-icons = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-icons = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Puente fino vello_svg → Llimphi para SVG arbitrario (íconos .desktop, logos).
|
||||
llimphi-svg = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Puente fino velato (Lottie) → Llimphi para animación vectorial autorada (.json).
|
||||
llimphi-lottie = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-image = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Decodificador de protocolos de gráficos de terminal (kitty/sixel) → RGBA.
|
||||
llimphi-term-graphics = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Widgets reusables sobre llimphi-ui — uno por crate.
|
||||
llimphi-widget-app-header = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-banner = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-button = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-card = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-clipboard = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-context-menu = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-edit-menu = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-menubar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-list = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-grid = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-slider = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-scroll = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-splitter = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-stat-card = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-tabs = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-command-palette = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-diff-viewer = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-fif = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-file-picker = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-bookmarks = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-mini-map = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-shuma-term = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-symbol-outline = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-plugin-host = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-theme-switcher = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-text-area = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-text-editor-core = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-text-editor = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-text-editor-lsp = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-text-input = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-tiled = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-nodegraph = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-tree = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-navigator = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-app-header = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-banner = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-button = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-rive-button = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-card = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-clipboard = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-context-menu = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-edit-menu = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-menubar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-list = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-grid = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-table = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-color-picker = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-slider = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-scroll = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-lazy-list = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-splitter = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-stat-card = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-tabs = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-allichay = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-command-palette = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-diff-viewer = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-fif = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-file-picker = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-bookmarks = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-mini-map = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-shuma-term = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-module-symbol-outline = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-plugin-host = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-theme-switcher = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-text-area = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-text-editor-core = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-text-editor = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-text-editor-lsp = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-text-input = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-tiled = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-nodegraph = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-tree = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
grafo-nav = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
llimphi-widget-navigator = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-detail-table = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-select = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-terminal = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Sello vectorial wawa (rombo + W implícita + Merkle Core).
|
||||
llimphi-widget-wawa-mark = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-wawa-mark = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Widgets de elegancia transversal (tooltip, spinner, progress, toast,
|
||||
# modal, empty, status-bar, shortcuts-help, splash).
|
||||
llimphi-widget-tooltip = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-spinner = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-progress = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-toast = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-modal = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-empty = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-status-bar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-shortcuts-help = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-timeline = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-splash = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-tooltip = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-spinner = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-progress = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-toast = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-modal = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-empty = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-status-bar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-shortcuts-help = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-timeline = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-transport = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-waveform = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-splash = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Controles de formulario y signaling (switch, segmented, breadcrumb,
|
||||
# badge, avatar, skeleton, field).
|
||||
llimphi-widget-switch = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-segmented = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-dock-rail = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-breadcrumb = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-badge = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-avatar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-skeleton = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-field = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-switch = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-segmented = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-rag-sidebar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-dock-rail = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-toolbar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-breadcrumb = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-badge = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-avatar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-skeleton = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-field = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Firma visual transversal (gradient sutil + hairline accent).
|
||||
llimphi-widget-panel = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-panes = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-workspace = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-widget-panel = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-panes = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Widgets Flutter-like — composición sobre primitivas Tier 1/3 ya
|
||||
# expuestas (sombra, gradient, animated, ripple).
|
||||
llimphi-widget-chip = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-fab = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-wrap = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-range-slider = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-calendar = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-fitted-box = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-carousel = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-rating = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-gauge = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-scaffold = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-hero = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-widget-router = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
llimphi-workspace = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
# Abstracción Selector — host (paths) + wawa (khipus).
|
||||
llimphi-module-selector = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.1.0" }
|
||||
llimphi-module-selector = { git = "https://git.tawasuyu.net/tawasuyu/llimphi.git", tag = "v0.2.0" }
|
||||
|
||||
# === Filesystem helpers ===
|
||||
directories = "5"
|
||||
@@ -290,7 +426,7 @@ hex = "0.4"
|
||||
portable-pty = "0.9"
|
||||
vt100 = "0.16"
|
||||
|
||||
# === WASM web (gioser) ===
|
||||
# === WASM web (tawasuyu) ===
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
js-sys = "0.3"
|
||||
@@ -315,23 +451,46 @@ ttf-parser = "0.25"
|
||||
# ============================================================
|
||||
# Intra-workspace deps de nahual (referenciadas por workspace = true)
|
||||
# ============================================================
|
||||
nahual-text-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-image-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-thumb-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-gallery-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-video-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-card-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-audio-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-tree-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-hex-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-table-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-markdown-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-archive-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-font-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-map-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-geo-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-viewer-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-file-explorer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
nahual-text-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-image-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-pdf-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-cbz-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-thumb-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-gallery-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-video-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-card-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-audio-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
media-module = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-module = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-icon-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-icon-cli = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-icon-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-icon-llm = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
foreign-svg = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
foreign-pdf = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-render = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-render-gpu = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-ops = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
tullpu-paint = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-tree-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-hex-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-svg-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-sheet-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-dbf-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-table-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-markdown-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-pluma-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-cotejo-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-deck-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-archive-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-font-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-map-viewer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-geo-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-geo-voxel = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-iconos = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-viewer-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
nahual-file-explorer-llimphi = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
|
||||
# ============================================================
|
||||
# Intra-workspace deps de pineal (módulo de gráficos)
|
||||
@@ -356,20 +515,28 @@ pineal = { path = "00_unanchay/pineal/pineal-umbrella" }
|
||||
# ============================================================
|
||||
# Intra-workspace deps de iniy (laboratorio semántico de creencias)
|
||||
# ============================================================
|
||||
iniy-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-ingest = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-extract = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-nli = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-nli-llm = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-graph = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-store = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
iniy-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-evidencia = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-derive = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-emisores = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-cache = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-daemon = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-ingest = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-extract = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-nli = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-nli-llm = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-graph = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
iniy-store = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
# la física de decaimiento de khipu la importa iniy-derive (SDD iniy §3)
|
||||
khipu-gravity = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
|
||||
# === auto: declarados por crates internos faltantes ===
|
||||
cosmos-coords = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
cosmos-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
cosmos-ephemeris = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
cosmos-time = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
cosmos-wcs = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.1.0" }
|
||||
cosmos-coords = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
cosmos-cities = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
cosmos-core = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
cosmos-ephemeris = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
cosmos-time = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
cosmos-wcs = { git = "https://git.tawasuyu.net/tawasuyu/tawasuyu.git", tag = "v0.2.0" }
|
||||
|
||||
# === auto: externas de eternal ===
|
||||
celestial-eop-data = { version = "0.1"}
|
||||
@@ -377,6 +544,7 @@ approx = "0.5"
|
||||
byteorder = "1.5"
|
||||
cc = "1.0"
|
||||
chrono = "0.4"
|
||||
chrono-tz = "0.10"
|
||||
crc32fast = "1.4"
|
||||
criterion = "0.5"
|
||||
csv = "1.4"
|
||||
@@ -385,6 +553,11 @@ glob = "0.3"
|
||||
indicatif = "0.18"
|
||||
lz4_flex = "0.11"
|
||||
memmap2 = "0.9"
|
||||
# Cliente Wayland (lado cliente) — lo usa hapiy para hablar zwlr_screencopy
|
||||
# contra mirada (u otro compositor wlroots) y capturar la pantalla.
|
||||
wayland-client = "0.31"
|
||||
wayland-protocols-wlr = { version = "0.3", features = ["client"] }
|
||||
wayland-protocols-misc = { version = "0.3", features = ["client"] }
|
||||
mockito = "1.0"
|
||||
ndarray = "0.15"
|
||||
num-traits = "0.2"
|
||||
@@ -418,6 +591,9 @@ markup5ever_rcdom = "0.39"
|
||||
cssparser = "0.35"
|
||||
url = "2"
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
# Charset de la web real: no todo es UTF-8 (google.com sirve ISO-8859-1).
|
||||
# Ya venía transitivo por el stack de Servo — aquí se hace explícito.
|
||||
encoding_rs = "0.8"
|
||||
|
||||
# === takiy-synth (SoundFont MIDI) ===
|
||||
# rustysynth = sintetizador SF2 puro Rust, MIT. Reemplaza el oscilador
|
||||
@@ -446,7 +622,7 @@ hound = "3.5"
|
||||
symphonia = { version = "0.5", default-features = false, features = ["mp3", "flac", "vorbis", "ogg"] }
|
||||
|
||||
# === media-source-opus (decoder Opus NATIVO puro-Rust) ===
|
||||
# Opus es el formato de audio nativo de gioser (par del video AV1). ogg
|
||||
# Opus es el formato de audio nativo de tawasuyu (par del video AV1). ogg
|
||||
# demuxea las páginas Ogg; opus-wave es un port puro-Rust de libopus
|
||||
# (SILK+CELT, sin C ni FFI) — par del rav1d del lado video.
|
||||
ogg = "0.9"
|
||||
@@ -457,3 +633,21 @@ opus-wave = "3"
|
||||
# paquetes de los tracks V_AV1 y A_OPUS para alimentar a media-source-av1
|
||||
# y media-source-opus — un .webm AV1+Opus se reproduce 100% nativo.
|
||||
matroska-demuxer = "0.7"
|
||||
|
||||
# === Perfil `dist`: binarios de reparto livianos (equipos chicos / poca RAM) ===
|
||||
# Hereda de `release` pero prioriza HUELLA sobre tiempo de compilación: LTO thin
|
||||
# (poda código muerto entre crates), un solo codegen-unit (mejor inlining/DCE) y
|
||||
# `strip` de símbolos. Reduce el tamaño en disco Y el segmento de código mapeado
|
||||
# en RAM de cada binario (mirada, pata, apps Llimphi). No toca `cargo build
|
||||
# --release` de iteración diaria; se usa sólo al empaquetar:
|
||||
# cargo build --profile dist -p mirada-compositor -p pata-host …
|
||||
# `panic = "unwind"` se mantiene a propósito: mirada-plugin-host aísla plugins
|
||||
# con `catch_unwind`, así que `abort` rompería el sandbox.
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
strip = "symbols"
|
||||
panic = "unwind"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user