From c6be8d38c123a97d0306bec1713e6b2d4d284f8d Mon Sep 17 00:00:00 2001 From: benoitlx Date: Wed, 12 Nov 2025 14:29:38 +0100 Subject: [PATCH 01/20] wip: ratzilla compilation --- Cargo.lock | 281 +++++++++++++++++++++++++++++++++-- kanash-components/Cargo.toml | 19 ++- kanash-ratzilla/.gitignore | 1 + kanash-ratzilla/Cargo.toml | 33 ++-- kanash-ratzilla/index.html | 43 ++++++ kanash-ratzilla/src/main.rs | 39 ++++- 6 files changed, 378 insertions(+), 38 deletions(-) create mode 100644 kanash-ratzilla/.gitignore create mode 100644 kanash-ratzilla/index.html diff --git a/Cargo.lock b/Cargo.lock index dc616ea..2beab8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,32 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "beamterm-data" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9440270ceba7fccbd5aab22ffba8abafd13b63d30bc42c417b622fcc9643d7" +dependencies = [ + "compact_str 0.9.0", + "miniz_oxide", +] + +[[package]] +name = "beamterm-renderer" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100e6159f2cd12ca83f89adaa812966d221616510c0a09afd4e1ea8e0f704bfb" +dependencies = [ + "beamterm-data", + "compact_str 0.9.0", + "console_error_panic_hook", + "js-sys", + "thiserror 2.0.17", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "bit_field" version = "0.10.3" @@ -122,6 +148,18 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "bon" version = "3.8.1" @@ -147,6 +185,12 @@ dependencies = [ "syn", ] +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "bytemuck" version = "1.24.0" @@ -272,6 +316,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "convert_case" version = "0.7.1" @@ -434,6 +488,15 @@ dependencies = [ "syn", ] +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_builder" version = "0.20.2" @@ -569,6 +632,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.31" @@ -665,9 +734,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasip2", + "wasm-bindgen", ] [[package]] @@ -802,6 +873,16 @@ dependencies = [ "rayon", ] +[[package]] +name = "js-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "kanash" version = "0.1.4" @@ -831,8 +912,8 @@ dependencies = [ "ansi-to-tui", "anyhow", "clap", - "crossterm 0.29.0", "futures", + "getrandom", "rand 0.9.2", "rand_core 0.6.4", "rand_pcg 0.9.0", @@ -849,22 +930,8 @@ dependencies = [ name = "kanash-ratzilla" version = "0.1.0" dependencies = [ - "ansi-to-tui", - "anyhow", - "clap", - "crossterm 0.29.0", - "futures", "kanash-components", - "rand 0.9.2", - "rand_core 0.6.4", - "rand_pcg 0.9.0", - "rascii_art", - "ratatui", - "tachyonfx", - "tokio", - "tui-big-text", - "tui-rain", - "wana_kana", + "ratzilla", ] [[package]] @@ -971,6 +1038,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -980,6 +1053,21 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "once_cell_polyfill" version = "1.70.2" @@ -1040,6 +1128,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1092,6 +1186,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -1182,11 +1282,27 @@ dependencies = [ "lru", "paste", "strum", + "time", "unicode-segmentation", "unicode-truncate", "unicode-width 0.2.0", ] +[[package]] +name = "ratzilla" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958f4bf83094f5e2cce7f8d90a853f76d7254b6763d25b9cdfe11d0e76e16522" +dependencies = [ + "beamterm-renderer", + "bitvec", + "compact_str 0.9.0", + "console_error_panic_hook", + "ratatui", + "thiserror 2.0.17", + "web-sys", +] + [[package]] name = "rayon" version = "1.11.0" @@ -1260,6 +1376,35 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "signal-hook" version = "0.3.18" @@ -1390,6 +1535,12 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.69" @@ -1441,6 +1592,27 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + [[package]] name = "tokio" version = "1.48.0" @@ -1559,6 +1731,74 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "weezl" version = "0.1.10" @@ -1755,6 +1995,15 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zerocopy" version = "0.8.27" diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 0571696..1737863 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -12,11 +12,10 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] anyhow = "1.0.97" rand = "0.9.0" rand_core = "0.6.4" -ratatui = "0.29.0" wana_kana = "4.0.0" tachyonfx = "0.13.0" tui-rain = "1.0.1" -tokio = { version = "1.44.2", features = ["full"] } +tokio = { version = "1.44.2" }#, features = ["full"] } futures = "0.3.31" tui-big-text = "0.7.1" #ratatui-image = "5.0.0" @@ -26,5 +25,17 @@ ansi-to-tui = "7.0.0" rascii_art = "0.4.5" clap = { version = "4.5.37", features = ["derive"] } -[dev-dependencies] -crossterm = "0.29.0" +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.3", features = ["wasm_js"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +ratatui = "0.29.0" + +# [target.'cfg(target_arch = "wasm32")'.dependencies.tokio] +# version = "1" +# default-features = false +# features = ["rt"] + + +# [dev-dependencies] +# crossterm = "0.29.0" diff --git a/kanash-ratzilla/.gitignore b/kanash-ratzilla/.gitignore new file mode 100644 index 0000000..849ddff --- /dev/null +++ b/kanash-ratzilla/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index e5beb5f..eb482a7 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -10,22 +10,23 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } -anyhow = "1.0.97" -rand = "0.9.0" -rand_core = "0.6.4" -ratatui = "0.29.0" -wana_kana = "4.0.0" -tachyonfx = "0.13.0" -tui-rain = "1.0.1" -tokio = { version = "1.44.2", features = ["full"] } -futures = "0.3.31" -tui-big-text = "0.7.1" +# anyhow = "1.0.97" +# rand = "0.9.0" +# rand_core = "0.6.4" +# ratatui = "0.29.0" +# wana_kana = "4.0.0" +# tachyonfx = "0.13.0" +# tui-rain = "1.0.1" +# tokio = { version = "1.44.2", features = ["full"] } +# futures = "0.3.31" +# tui-big-text = "0.7.1" #ratatui-image = "5.0.0" #image = "0.25.6" -rand_pcg = "0.9.0" -ansi-to-tui = "7.0.0" -rascii_art = "0.4.5" -clap = { version = "4.5.37", features = ["derive"] } +# rand_pcg = "0.9.0" +# ansi-to-tui = "7.0.0" +ratzilla = "0.2.0" +# rascii_art = "0.4.5" +# clap = { version = "4.5.37", features = ["derive"] } -[dev-dependencies] -crossterm = "0.29.0" +# [dev-dependencies] +# crossterm = "0.29.0" diff --git a/kanash-ratzilla/index.html b/kanash-ratzilla/index.html new file mode 100644 index 0000000..1265bf8 --- /dev/null +++ b/kanash-ratzilla/index.html @@ -0,0 +1,43 @@ + + + + + + + + Ratzilla + + + + + + + diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index e7a11a9..6cf364d 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,3 +1,38 @@ -fn main() { - println!("Hello, world!"); +use kanash_components::{app::App, Components}; + +use std::{cell::RefCell, io, rc::Rc}; + +use ratzilla::ratatui::{ + layout::Alignment, + style::Color, + widgets::{Block, Paragraph}, + Terminal, +}; + +use ratzilla::{event::KeyCode, DomBackend, WebRenderer}; + +use std::time::{Duration, Instant}; + +fn main() -> io::Result<()> { + let backend = DomBackend::new()?; + let terminal = Terminal::new(backend)?; + + let mut app = App::new(); + let start_time = Instant::now(); + + let _ = terminal.draw_web(move |f| { + f.render_widget( + Paragraph::new(format!("Hey there")) + .alignment(Alignment::Center) + .block( + Block::bordered() + .title("Ratzilla") + .title_alignment(Alignment::Center) + .border_style(Color::Yellow), + ), + f.area(), + ); + }); + + Ok(()) } From d6569de6d7dd2fc98908c19c0fe357c748992953 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 10:55:10 +0100 Subject: [PATCH 02/20] feat: basic wasm compilation with no input events --- Cargo.lock | 12 ++++++++++ kanash-components/Cargo.toml | 20 +++++------------ kanash-components/src/app.rs | 14 ++++++++++++ kanash-components/src/helper/mod.rs | 8 +++++-- kanash-components/src/home.rs | 11 ++++++---- kanash-components/src/kana.rs | 11 ++++++---- kanash-components/src/lib.rs | 14 ++++++++++++ kanash-ratzilla/Cargo.toml | 20 +---------------- kanash-ratzilla/src/main.rs | 34 ++++++++++------------------- 9 files changed, 77 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2beab8a..2a91835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,6 +919,7 @@ dependencies = [ "rand_pcg 0.9.0", "rascii_art", "ratatui", + "ratzilla", "tachyonfx", "tokio", "tui-big-text", @@ -932,6 +933,7 @@ version = "0.1.0" dependencies = [ "kanash-components", "ratzilla", + "web-time", ] [[package]] @@ -1799,6 +1801,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "weezl" version = "0.1.10" diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 1737863..80237f3 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -13,29 +13,19 @@ anyhow = "1.0.97" rand = "0.9.0" rand_core = "0.6.4" wana_kana = "4.0.0" -tachyonfx = "0.13.0" -tui-rain = "1.0.1" tokio = { version = "1.44.2" }#, features = ["full"] } futures = "0.3.31" -tui-big-text = "0.7.1" -#ratatui-image = "5.0.0" -#image = "0.25.6" rand_pcg = "0.9.0" -ansi-to-tui = "7.0.0" rascii_art = "0.4.5" clap = { version = "4.5.37", features = ["derive"] } [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } +ratzilla = "0.2.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ratatui = "0.29.0" - -# [target.'cfg(target_arch = "wasm32")'.dependencies.tokio] -# version = "1" -# default-features = false -# features = ["rt"] - - -# [dev-dependencies] -# crossterm = "0.29.0" +tachyonfx = "0.13.0" +tui-rain = "1.0.1" +tui-big-text = "0.7.1" +ansi-to-tui = "7.0.0" diff --git a/kanash-components/src/app.rs b/kanash-components/src/app.rs index f13a5f1..df23b32 100644 --- a/kanash-components/src/app.rs +++ b/kanash-components/src/app.rs @@ -1,8 +1,16 @@ use super::{home::HomeModel, kana::KanaModel, *}; + +#[cfg(not(target_arch = "wasm32"))] use crate::helper::rain; +#[cfg(not(target_arch = "wasm32"))] use ansi_to_tui::IntoText; +#[cfg(not(target_arch = "wasm32"))] use rascii_art::{render_to, RenderOptions}; + +#[cfg(not(target_arch = "wasm32"))] use ratatui::text::Text; +#[cfg(target_arch = "wasm32")] +use ratzilla::ratatui::text::Text; #[derive(Debug, PartialEq, Eq)] enum AppPage { @@ -119,12 +127,17 @@ impl Components for App { } fn view(&mut self, frame: &mut Frame, elapsed: Duration) { + + #[cfg(not(target_arch = "wasm32"))] if !self.disable_background { self.background(frame); } + + #[cfg(not(target_arch = "wasm32"))] if !self.disable_rain { rain::view(frame, elapsed); } + match &mut self.page { AppPage::Home(ref mut h) => h.view(frame, elapsed), AppPage::Kana(ref mut k) => k.view(frame, elapsed), @@ -132,6 +145,7 @@ impl Components for App { } } +#[cfg(not(target_arch = "wasm32"))] impl App { fn background(&mut self, frame: &mut Frame) { let actual_height = frame.area().height; diff --git a/kanash-components/src/helper/mod.rs b/kanash-components/src/helper/mod.rs index a51f5f7..1699f5f 100644 --- a/kanash-components/src/helper/mod.rs +++ b/kanash-components/src/helper/mod.rs @@ -1,4 +1,8 @@ -pub mod background; -// pub mod image; pub mod ja; + +#[cfg(not(target_arch = "wasm32"))] +pub mod background; +#[cfg(not(target_arch = "wasm32"))] pub mod rain; + +// pub mod image; diff --git a/kanash-components/src/home.rs b/kanash-components/src/home.rs index c9280a4..beefbc4 100644 --- a/kanash-components/src/home.rs +++ b/kanash-components/src/home.rs @@ -61,9 +61,10 @@ impl Components for HomeModel { /// Handle Event (Mostly convert key event to message) fn handle_event(&self) -> Option { + #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { - match key.code { + return match key.code { KeyCode::Esc => Some(Message::Back), KeyCode::Enter => { if let Some(i) = self.state.selected() { @@ -82,13 +83,15 @@ impl Components for HomeModel { KeyCode::Char('x') => Some(Message::Home(HomeMessage::RainFx)), KeyCode::Char('b') => Some(Message::Home(HomeMessage::Background)), _ => None, - } + }; } else { - None + return None; } } else { - None + return None; } + + None } fn update(&mut self, msg: Message) -> Option { diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index 3596e23..75a3f72 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -64,21 +64,24 @@ impl Components for KanaModel { /// Handle Event (Mostly convert key event to message) fn handle_event(&self) -> Option { + #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { - match key.code { + return match key.code { KeyCode::Esc => Some(Message::Back), KeyCode::Backspace => Some(Message::Kana(KanaMessage::DeleteRoma)), KeyCode::Char(' ') => Some(Message::Kana(KanaMessage::Answer)), KeyCode::Char(c) => Some(Message::Kana(KanaMessage::TypingRoma(c))), _ => None, - } + }; } else { - None + return None; } } else { - None + return None; } + + None } fn update(&mut self, msg: Message) -> Option { diff --git a/kanash-components/src/lib.rs b/kanash-components/src/lib.rs index 5f1e8d3..2779314 100644 --- a/kanash-components/src/lib.rs +++ b/kanash-components/src/lib.rs @@ -3,6 +3,7 @@ pub mod helper; pub mod home; pub mod kana; +#[cfg(not(target_arch = "wasm32"))] pub use ratatui::{ crossterm::event::{self, Event, KeyCode}, layout::{Constraint, Layout}, @@ -14,6 +15,19 @@ pub use ratatui::{ Frame, }; +#[cfg(target_arch = "wasm32")] +pub use ratzilla::ratatui::{ + layout::{Constraint, Layout}, + style::Stylize, + style::{palette::tailwind::SLATE, Color, Modifier, Style}, + text::Line, + widgets::{Block, Paragraph}, + widgets::{BorderType, Borders, Clear, HighlightSpacing, List, ListItem, ListState, Padding}, + Frame, +}; +#[cfg(target_arch = "wasm32")] +use ratzilla::event::KeyCode; + use std::time::Duration; use home::{BackgroundMode, HomeMessage, Mode}; diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index eb482a7..71812bb 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -10,23 +10,5 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } -# anyhow = "1.0.97" -# rand = "0.9.0" -# rand_core = "0.6.4" -# ratatui = "0.29.0" -# wana_kana = "4.0.0" -# tachyonfx = "0.13.0" -# tui-rain = "1.0.1" -# tokio = { version = "1.44.2", features = ["full"] } -# futures = "0.3.31" -# tui-big-text = "0.7.1" -#ratatui-image = "5.0.0" -#image = "0.25.6" -# rand_pcg = "0.9.0" -# ansi-to-tui = "7.0.0" ratzilla = "0.2.0" -# rascii_art = "0.4.5" -# clap = { version = "4.5.37", features = ["derive"] } - -# [dev-dependencies] -# crossterm = "0.29.0" +web-time = "1.1.0" diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 6cf364d..95dba98 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,17 +1,10 @@ use kanash_components::{app::App, Components}; -use std::{cell::RefCell, io, rc::Rc}; - -use ratzilla::ratatui::{ - layout::Alignment, - style::Color, - widgets::{Block, Paragraph}, - Terminal, -}; - +use ratzilla::ratatui::Terminal; use ratzilla::{event::KeyCode, DomBackend, WebRenderer}; -use std::time::{Duration, Instant}; +use std::io; +use web_time::Instant; fn main() -> io::Result<()> { let backend = DomBackend::new()?; @@ -20,19 +13,14 @@ fn main() -> io::Result<()> { let mut app = App::new(); let start_time = Instant::now(); - let _ = terminal.draw_web(move |f| { - f.render_widget( - Paragraph::new(format!("Hey there")) - .alignment(Alignment::Center) - .block( - Block::bordered() - .title("Ratzilla") - .title_alignment(Alignment::Center) - .border_style(Color::Yellow), - ), - f.area(), - ); - }); + terminal.draw_web(move |f| { + app.view(f, start_time.elapsed()); + let mut current_msg = app.handle_event(); + + while current_msg.is_some() { + current_msg = app.update(current_msg.unwrap()); + } + }); Ok(()) } From 09e0743ef917c60c7cfe7aba352aa5a28b9a7234 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 11:20:41 +0100 Subject: [PATCH 03/20] feat: change backend to webgl2 --- kanash-components/src/home.rs | 9 +++++---- kanash-components/src/kana.rs | 9 +++++---- kanash-ratzilla/src/main.rs | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/kanash-components/src/home.rs b/kanash-components/src/home.rs index beefbc4..fd1e4ab 100644 --- a/kanash-components/src/home.rs +++ b/kanash-components/src/home.rs @@ -64,7 +64,7 @@ impl Components for HomeModel { #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { - return match key.code { + match key.code { KeyCode::Esc => Some(Message::Back), KeyCode::Enter => { if let Some(i) = self.state.selected() { @@ -83,14 +83,15 @@ impl Components for HomeModel { KeyCode::Char('x') => Some(Message::Home(HomeMessage::RainFx)), KeyCode::Char('b') => Some(Message::Home(HomeMessage::Background)), _ => None, - }; + } } else { - return None; + None } } else { - return None; + None } + #[cfg(target_arch = "wasm32")] None } diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index 75a3f72..71c694c 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -67,20 +67,21 @@ impl Components for KanaModel { #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { - return match key.code { + match key.code { KeyCode::Esc => Some(Message::Back), KeyCode::Backspace => Some(Message::Kana(KanaMessage::DeleteRoma)), KeyCode::Char(' ') => Some(Message::Kana(KanaMessage::Answer)), KeyCode::Char(c) => Some(Message::Kana(KanaMessage::TypingRoma(c))), _ => None, - }; + } } else { - return None; + None } } else { - return None; + None } + #[cfg(target_arch = "wasm32")] None } diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 95dba98..2aa745a 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,13 +1,13 @@ use kanash_components::{app::App, Components}; use ratzilla::ratatui::Terminal; -use ratzilla::{event::KeyCode, DomBackend, WebRenderer}; +use ratzilla::{WebGl2Backend, WebRenderer}; use std::io; use web_time::Instant; fn main() -> io::Result<()> { - let backend = DomBackend::new()?; + let backend = WebGl2Backend::new()?; let terminal = Terminal::new(backend)?; let mut app = App::new(); From 16165b20254dcb1ae239a95e7342e5019ea2177e Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 17:09:52 +0100 Subject: [PATCH 04/20] wip: input event The actual implementation needs two apps. One hand ling input event, the other one in charge of rendering. I still need to synchronize the app state (in particular the page) I also need to find a seed that does not require std::time so it does not cause runtime exception when targetting wasm --- Cargo.lock | 1 + kanash-components/src/app.rs | 13 ++++++++++++- kanash-components/src/home.rs | 29 ++++++++++++++++++++++++++--- kanash-components/src/kana.rs | 27 ++++++++++++++++++++++----- kanash-components/src/lib.rs | 7 ++++++- kanash-ratzilla/Cargo.toml | 1 + kanash-ratzilla/src/main.rs | 35 +++++++++++++++++++++++++++++++---- 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a91835..8e989d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -933,6 +933,7 @@ version = "0.1.0" dependencies = [ "kanash-components", "ratzilla", + "web-sys", "web-time", ] diff --git a/kanash-components/src/app.rs b/kanash-components/src/app.rs index df23b32..edb753b 100644 --- a/kanash-components/src/app.rs +++ b/kanash-components/src/app.rs @@ -46,6 +46,7 @@ impl Components for App { } } + #[cfg(not(target_arch = "wasm32"))] fn handle_event(&self) -> Option { match &self.page { AppPage::Home(h) => h.handle_event(), @@ -53,6 +54,14 @@ impl Components for App { } } + #[cfg(target_arch = "wasm32")] + fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option { + match &self.page { + AppPage::Home(h) => h.handle_event(event), + AppPage::Kana(k) => k.handle_event(event), + } + } + fn update(&mut self, msg: Message) -> Option { match &mut self.page { AppPage::Home(ref mut h) => { @@ -101,10 +110,13 @@ impl Components for App { // transform self en App::Kana(new_kana(selected)) if msg == Message::Home(Enter) if let Message::Home(HomeMessage::Enter(mode)) = msg { + console::log_1(&format!("hellow there").into()); let mut new_kana = KanaModel::new(); + console::log_1(&format!("w there").into()); new_kana.mode = mode; new_kana.update(Message::Kana(KanaMessage::Pass)); + console::log_1(&format!("hell there").into()); self.page = AppPage::Kana(new_kana); } @@ -127,7 +139,6 @@ impl Components for App { } fn view(&mut self, frame: &mut Frame, elapsed: Duration) { - #[cfg(not(target_arch = "wasm32"))] if !self.disable_background { self.background(frame); diff --git a/kanash-components/src/home.rs b/kanash-components/src/home.rs index fd1e4ab..6305c95 100644 --- a/kanash-components/src/home.rs +++ b/kanash-components/src/home.rs @@ -60,8 +60,8 @@ impl Components for HomeModel { } /// Handle Event (Mostly convert key event to message) + #[cfg(not(target_arch = "wasm32"))] fn handle_event(&self) -> Option { - #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { match key.code { @@ -90,9 +90,32 @@ impl Components for HomeModel { } else { None } + } - #[cfg(target_arch = "wasm32")] - None + #[cfg(target_arch = "wasm32")] + fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option { + use ratzilla::event::KeyCode; + + match event.code { + KeyCode::Esc => Some(Message::Back), + KeyCode::Enter => { + if let Some(i) = self.state.selected() { + match i { + 0 => Some(Message::Home(HomeMessage::Enter(Mode::Hira))), + 1 => Some(Message::Home(HomeMessage::Enter(Mode::Kata))), + 2 => Some(Message::Home(HomeMessage::Enter(Mode::Both))), + _ => None, + } + } else { + None + } + } + KeyCode::Char('j') | KeyCode::Down => Some(Message::Home(HomeMessage::Down)), + KeyCode::Char('k') | KeyCode::Up => Some(Message::Home(HomeMessage::Up)), + KeyCode::Char('x') => Some(Message::Home(HomeMessage::RainFx)), + KeyCode::Char('b') => Some(Message::Home(HomeMessage::Background)), + _ => None, + } } fn update(&mut self, msg: Message) -> Option { diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index 71c694c..0aa9e41 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -45,12 +45,16 @@ pub enum KanaMessage { impl Components for KanaModel { /// Create a new kana model fn new() -> Self { + console::log_1(&format!("hellow miaou").into()); let mut r = Pcg64Mcg::seed_from_u64( - std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), + // TODO) Non std seed + // std::time::SystemTime::now() + // .duration_since(UNIX_EPOCH) + // .unwrap() + // .as_secs(), + 63, ); + console::log_1(&format!("miaou ?").into()); Self { shown: 0, correct: 0, @@ -63,8 +67,8 @@ impl Components for KanaModel { } /// Handle Event (Mostly convert key event to message) + #[cfg(not(target_arch = "wasm32"))] fn handle_event(&self) -> Option { - #[cfg(not(target_arch = "wasm32"))] if event::poll(Duration::from_millis(10)).unwrap() { if let Event::Key(key) = event::read().unwrap() { match key.code { @@ -85,6 +89,19 @@ impl Components for KanaModel { None } + #[cfg(target_arch = "wasm32")] + fn handle_event(&self, key_event: &ratzilla::event::KeyEvent) -> Option { + use ratzilla::event::KeyCode; + + match key_event.code { + KeyCode::Esc => Some(Message::Back), + KeyCode::Backspace => Some(Message::Kana(KanaMessage::DeleteRoma)), + KeyCode::Char(' ') => Some(Message::Kana(KanaMessage::Answer)), + KeyCode::Char(c) => Some(Message::Kana(KanaMessage::TypingRoma(c))), + _ => None, + } + } + fn update(&mut self, msg: Message) -> Option { if let Message::Kana(kana_msg) = msg { return match kana_msg { diff --git a/kanash-components/src/lib.rs b/kanash-components/src/lib.rs index 2779314..f2a9d8d 100644 --- a/kanash-components/src/lib.rs +++ b/kanash-components/src/lib.rs @@ -25,8 +25,9 @@ pub use ratzilla::ratatui::{ widgets::{BorderType, Borders, Clear, HighlightSpacing, List, ListItem, ListState, Padding}, Frame, }; + #[cfg(target_arch = "wasm32")] -use ratzilla::event::KeyCode; +pub use ratzilla::web_sys::console; use std::time::Duration; @@ -57,8 +58,12 @@ pub enum Message { pub trait Components { fn new() -> Self; + #[cfg(not(target_arch = "wasm32"))] fn handle_event(&self) -> Option; + #[cfg(target_arch = "wasm32")] + fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option; + fn update(&mut self, msg: Message) -> Option; fn view(&mut self, frame: &mut Frame, elapsed: Duration); diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 71812bb..2655bee 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -11,4 +11,5 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } ratzilla = "0.2.0" +web-sys = "0.3.82" web-time = "1.1.0" diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 2aa745a..a303bb4 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,26 +1,53 @@ use kanash_components::{app::App, Components}; use ratzilla::ratatui::Terminal; -use ratzilla::{WebGl2Backend, WebRenderer}; +use ratzilla::{DomBackend, WebGl2Backend, WebRenderer}; use std::io; use web_time::Instant; +use web_sys::console; + +use std::{cell::RefCell, rc::Rc}; + +type Outbox = Rc>>; + +fn new_outbox() -> Outbox { + Rc::new(RefCell::new(None)) +} + fn main() -> io::Result<()> { - let backend = WebGl2Backend::new()?; + let backend = DomBackend::new()?; let terminal = Terminal::new(backend)?; let mut app = App::new(); + let new_app = App::new(); let start_time = Instant::now(); + let outbox: Outbox = new_outbox(); + let outbox_cb = Rc::clone(&outbox); + + // TODO) synchronise two apps state + + terminal.on_key_event({ + move |key_event| { + let current_msg = new_app.handle_event(&key_event); + console::log_1(&format!("{:?}", current_msg).into()); + + if let Some(msg) = current_msg { + *outbox_cb.borrow_mut() = Some(msg); + } + } + }); + terminal.draw_web(move |f| { app.view(f, start_time.elapsed()); - let mut current_msg = app.handle_event(); - + let mut current_msg = outbox.borrow_mut().take(); while current_msg.is_some() { current_msg = app.update(current_msg.unwrap()); } }); + Ok(()) } From 665e2757242b8fae9b44a941f7e7d33a11a0a2d9 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 17:26:46 +0100 Subject: [PATCH 05/20] feat(wasm): update both apps simultaneously by copying message --- kanash-components/src/home.rs | 4 ++-- kanash-components/src/kana.rs | 2 +- kanash-components/src/lib.rs | 2 +- kanash-ratzilla/src/main.rs | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/kanash-components/src/home.rs b/kanash-components/src/home.rs index 6305c95..777f68a 100644 --- a/kanash-components/src/home.rs +++ b/kanash-components/src/home.rs @@ -9,7 +9,7 @@ const SELECTED_STYLE: Style = Style::new() .bg(ColorPalette::SELECTION) .add_modifier(Modifier::BOLD); -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Mode { Hira, Kata, @@ -30,7 +30,7 @@ pub struct HomeModel { pub key_helper_state: BackgroundMode, } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum HomeMessage { /// Launch a Page Enter(Mode), diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index 0aa9e41..bc82800 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -27,7 +27,7 @@ pub struct KanaModel { pub mode: Mode, } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum KanaMessage { /// reveal the answer Answer, diff --git a/kanash-components/src/lib.rs b/kanash-components/src/lib.rs index f2a9d8d..9e0a441 100644 --- a/kanash-components/src/lib.rs +++ b/kanash-components/src/lib.rs @@ -46,7 +46,7 @@ impl ColorPalette { // #99ff33 } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum Message { /// Go to the previous page or quit the app Back, diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index a303bb4..729ff63 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -21,7 +21,7 @@ fn main() -> io::Result<()> { let terminal = Terminal::new(backend)?; let mut app = App::new(); - let new_app = App::new(); + let mut new_app = App::new(); let start_time = Instant::now(); let outbox: Outbox = new_outbox(); @@ -36,6 +36,7 @@ fn main() -> io::Result<()> { if let Some(msg) = current_msg { *outbox_cb.borrow_mut() = Some(msg); + new_app.update(current_msg.unwrap()); } } }); From 016d87a7b4e619c652fdbfdf86b64826c86165eb Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 20:45:49 +0100 Subject: [PATCH 06/20] refactor(wasm): move web-sys to dev dependencies, renaming app vars --- Cargo.lock | 1 + kanash-components/Cargo.toml | 3 +++ kanash-components/src/app.rs | 3 --- kanash-components/src/kana.rs | 2 -- kanash-ratzilla/Cargo.toml | 4 +++- kanash-ratzilla/src/main.rs | 21 ++++++++------------- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e989d8..0fadb4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -925,6 +925,7 @@ dependencies = [ "tui-big-text", "tui-rain", "wana_kana", + "web-sys", ] [[package]] diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 80237f3..595966b 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -19,6 +19,9 @@ rand_pcg = "0.9.0" rascii_art = "0.4.5" clap = { version = "4.5.37", features = ["derive"] } +[dev-dependencies] +web-sys = "0.3.82" + [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } ratzilla = "0.2.0" diff --git a/kanash-components/src/app.rs b/kanash-components/src/app.rs index edb753b..0dadf7c 100644 --- a/kanash-components/src/app.rs +++ b/kanash-components/src/app.rs @@ -110,13 +110,10 @@ impl Components for App { // transform self en App::Kana(new_kana(selected)) if msg == Message::Home(Enter) if let Message::Home(HomeMessage::Enter(mode)) = msg { - console::log_1(&format!("hellow there").into()); let mut new_kana = KanaModel::new(); - console::log_1(&format!("w there").into()); new_kana.mode = mode; new_kana.update(Message::Kana(KanaMessage::Pass)); - console::log_1(&format!("hell there").into()); self.page = AppPage::Kana(new_kana); } diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index bc82800..d573def 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -45,7 +45,6 @@ pub enum KanaMessage { impl Components for KanaModel { /// Create a new kana model fn new() -> Self { - console::log_1(&format!("hellow miaou").into()); let mut r = Pcg64Mcg::seed_from_u64( // TODO) Non std seed // std::time::SystemTime::now() @@ -54,7 +53,6 @@ impl Components for KanaModel { // .as_secs(), 63, ); - console::log_1(&format!("miaou ?").into()); Self { shown: 0, correct: 0, diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 2655bee..5034dab 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -11,5 +11,7 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } ratzilla = "0.2.0" -web-sys = "0.3.82" web-time = "1.1.0" + +[dev-dependencies] +web-sys = "0.3.82" diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 729ff63..58f654c 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -6,8 +6,6 @@ use ratzilla::{DomBackend, WebGl2Backend, WebRenderer}; use std::io; use web_time::Instant; -use web_sys::console; - use std::{cell::RefCell, rc::Rc}; type Outbox = Rc>>; @@ -20,33 +18,30 @@ fn main() -> io::Result<()> { let backend = DomBackend::new()?; let terminal = Terminal::new(backend)?; - let mut app = App::new(); - let mut new_app = App::new(); + let mut render_app = App::new(); + let mut event_app = App::new(); let start_time = Instant::now(); let outbox: Outbox = new_outbox(); - let outbox_cb = Rc::clone(&outbox); - - // TODO) synchronise two apps state + let outbox_event = Rc::clone(&outbox); terminal.on_key_event({ move |key_event| { - let current_msg = new_app.handle_event(&key_event); - console::log_1(&format!("{:?}", current_msg).into()); + let current_msg = event_app.handle_event(&key_event); if let Some(msg) = current_msg { - *outbox_cb.borrow_mut() = Some(msg); - new_app.update(current_msg.unwrap()); + *outbox_event.borrow_mut() = Some(msg); + event_app.update(current_msg.unwrap()); } } }); terminal.draw_web(move |f| { - app.view(f, start_time.elapsed()); + render_app.view(f, start_time.elapsed()); let mut current_msg = outbox.borrow_mut().take(); while current_msg.is_some() { - current_msg = app.update(current_msg.unwrap()); + current_msg = render_app.update(current_msg.unwrap()); } }); From 325699661293177a62563375f4d1de82827a7eeb Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 21:02:26 +0100 Subject: [PATCH 07/20] feat(wasm): absolute time seed for web --- Cargo.lock | 1 + kanash-components/Cargo.toml | 1 + kanash-components/src/kana.rs | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fadb4a..acf2da9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -926,6 +926,7 @@ dependencies = [ "tui-rain", "wana_kana", "web-sys", + "web-time", ] [[package]] diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 595966b..16496f3 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -25,6 +25,7 @@ web-sys = "0.3.82" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } ratzilla = "0.2.0" +web-time = "1.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ratatui = "0.29.0" diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index d573def..3e8ccd7 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -1,5 +1,3 @@ -use std::time::UNIX_EPOCH; - // use crate::components::helper::image; use crate::helper::ja::random_kana; use rand::SeedableRng; @@ -46,12 +44,16 @@ impl Components for KanaModel { /// Create a new kana model fn new() -> Self { let mut r = Pcg64Mcg::seed_from_u64( - // TODO) Non std seed - // std::time::SystemTime::now() - // .duration_since(UNIX_EPOCH) - // .unwrap() - // .as_secs(), - 63, + #[cfg(not(target_arch = "wasm32"))] + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + #[cfg(target_arch = "wasm32")] + web_time::SystemTime::now() + .duration_since(web_time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), ); Self { shown: 0, From 82334a2331bfb348c205b5fe43c02d7e8b29c70a Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 14 Nov 2025 21:26:18 +0100 Subject: [PATCH 08/20] build(wasm): changing default target when compiling inside kanash-ratzilla --- kanash-ratzilla/.cargo/config.toml | 2 ++ kanash-ratzilla/build.rs | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 kanash-ratzilla/.cargo/config.toml create mode 100644 kanash-ratzilla/build.rs diff --git a/kanash-ratzilla/.cargo/config.toml b/kanash-ratzilla/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/kanash-ratzilla/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/kanash-ratzilla/build.rs b/kanash-ratzilla/build.rs new file mode 100644 index 0000000..bd3f3ea --- /dev/null +++ b/kanash-ratzilla/build.rs @@ -0,0 +1,6 @@ +fn main() { + let target = std::env::var("TARGET").unwrap_or_default(); + if !target.starts_with("wasm32") { + panic!("kanash-ratzilla must be built for a wasm32 target (e.g. wasm32-unknown-unknown)."); + } +} From 1b1b0e960a0191959e7d3f9ea7f3f547f36da271 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Sat, 15 Nov 2025 12:19:20 +0100 Subject: [PATCH 09/20] refactor: share handle_event function between native and wasm Implemented with a PlatformKeyEvent generic type --- kanash-components/src/app.rs | 11 +---------- kanash-components/src/home.rs | 37 +---------------------------------- kanash-components/src/kana.rs | 27 +------------------------ kanash-components/src/lib.rs | 14 +++++++------ kanash/src/main.rs | 28 +++++++++++++++----------- 5 files changed, 28 insertions(+), 89 deletions(-) diff --git a/kanash-components/src/app.rs b/kanash-components/src/app.rs index 0dadf7c..fd68a84 100644 --- a/kanash-components/src/app.rs +++ b/kanash-components/src/app.rs @@ -46,16 +46,7 @@ impl Components for App { } } - #[cfg(not(target_arch = "wasm32"))] - fn handle_event(&self) -> Option { - match &self.page { - AppPage::Home(h) => h.handle_event(), - AppPage::Kana(k) => k.handle_event(), - } - } - - #[cfg(target_arch = "wasm32")] - fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option { + fn handle_event(&self, event: &PlatformKeyEvent) -> Option { match &self.page { AppPage::Home(h) => h.handle_event(event), AppPage::Kana(k) => k.handle_event(event), diff --git a/kanash-components/src/home.rs b/kanash-components/src/home.rs index 777f68a..cb7c38c 100644 --- a/kanash-components/src/home.rs +++ b/kanash-components/src/home.rs @@ -60,42 +60,7 @@ impl Components for HomeModel { } /// Handle Event (Mostly convert key event to message) - #[cfg(not(target_arch = "wasm32"))] - fn handle_event(&self) -> Option { - if event::poll(Duration::from_millis(10)).unwrap() { - if let Event::Key(key) = event::read().unwrap() { - match key.code { - KeyCode::Esc => Some(Message::Back), - KeyCode::Enter => { - if let Some(i) = self.state.selected() { - match i { - 0 => Some(Message::Home(HomeMessage::Enter(Mode::Hira))), - 1 => Some(Message::Home(HomeMessage::Enter(Mode::Kata))), - 2 => Some(Message::Home(HomeMessage::Enter(Mode::Both))), - _ => None, - } - } else { - None - } - } - KeyCode::Char('j') | KeyCode::Down => Some(Message::Home(HomeMessage::Down)), - KeyCode::Char('k') | KeyCode::Up => Some(Message::Home(HomeMessage::Up)), - KeyCode::Char('x') => Some(Message::Home(HomeMessage::RainFx)), - KeyCode::Char('b') => Some(Message::Home(HomeMessage::Background)), - _ => None, - } - } else { - None - } - } else { - None - } - } - - #[cfg(target_arch = "wasm32")] - fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option { - use ratzilla::event::KeyCode; - + fn handle_event(&self, event: &PlatformKeyEvent) -> Option { match event.code { KeyCode::Esc => Some(Message::Back), KeyCode::Enter => { diff --git a/kanash-components/src/kana.rs b/kanash-components/src/kana.rs index 3e8ccd7..2b37a12 100644 --- a/kanash-components/src/kana.rs +++ b/kanash-components/src/kana.rs @@ -67,32 +67,7 @@ impl Components for KanaModel { } /// Handle Event (Mostly convert key event to message) - #[cfg(not(target_arch = "wasm32"))] - fn handle_event(&self) -> Option { - if event::poll(Duration::from_millis(10)).unwrap() { - if let Event::Key(key) = event::read().unwrap() { - match key.code { - KeyCode::Esc => Some(Message::Back), - KeyCode::Backspace => Some(Message::Kana(KanaMessage::DeleteRoma)), - KeyCode::Char(' ') => Some(Message::Kana(KanaMessage::Answer)), - KeyCode::Char(c) => Some(Message::Kana(KanaMessage::TypingRoma(c))), - _ => None, - } - } else { - None - } - } else { - None - } - - #[cfg(target_arch = "wasm32")] - None - } - - #[cfg(target_arch = "wasm32")] - fn handle_event(&self, key_event: &ratzilla::event::KeyEvent) -> Option { - use ratzilla::event::KeyCode; - + fn handle_event(&self, key_event: &PlatformKeyEvent) -> Option { match key_event.code { KeyCode::Esc => Some(Message::Back), KeyCode::Backspace => Some(Message::Kana(KanaMessage::DeleteRoma)), diff --git a/kanash-components/src/lib.rs b/kanash-components/src/lib.rs index 9e0a441..1f18603 100644 --- a/kanash-components/src/lib.rs +++ b/kanash-components/src/lib.rs @@ -15,6 +15,9 @@ pub use ratatui::{ Frame, }; +#[cfg(not(target_arch = "wasm32"))] +pub type PlatformKeyEvent = ratatui::crossterm::event::KeyEvent; + #[cfg(target_arch = "wasm32")] pub use ratzilla::ratatui::{ layout::{Constraint, Layout}, @@ -27,7 +30,10 @@ pub use ratzilla::ratatui::{ }; #[cfg(target_arch = "wasm32")] -pub use ratzilla::web_sys::console; +pub type PlatformKeyEvent = ratzilla::event::KeyEvent; + +#[cfg(target_arch = "wasm32")] +pub use ratzilla::{event::KeyCode, web_sys::console}; use std::time::Duration; @@ -58,11 +64,7 @@ pub enum Message { pub trait Components { fn new() -> Self; - #[cfg(not(target_arch = "wasm32"))] - fn handle_event(&self) -> Option; - - #[cfg(target_arch = "wasm32")] - fn handle_event(&self, event: &ratzilla::event::KeyEvent) -> Option; + fn handle_event(&self, event: &PlatformKeyEvent) -> Option; fn update(&mut self, msg: Message) -> Option; diff --git a/kanash/src/main.rs b/kanash/src/main.rs index a045e00..cc0e14a 100644 --- a/kanash/src/main.rs +++ b/kanash/src/main.rs @@ -1,6 +1,7 @@ use kanash_components::app::App; use kanash_components::{ColorPalette, Components}; +use ratatui::crossterm::event::{self, *}; use ratatui::layout::{Constraint, Layout}; use ratatui::text::Line; use ratatui::{restore, style::Style}; @@ -24,19 +25,10 @@ fn main() { let mut terminal = ratatui::init(); - let mut app = App::new(); - if let Some(path) = arg.path { - let assets = std::fs::read_dir(path) - .unwrap() - .map(|entry| entry.unwrap().path().to_str().unwrap().to_string()) - .collect::>(); - app.background_paths = assets; - } + let mut fade_effect = fx::dissolve((20000, Interpolation::QuadOut)); let start_time = Instant::now(); - let mut fade_effect = fx::dissolve((20000, Interpolation::QuadOut)); - // Splash Screen Rendering while start_time.elapsed() < Duration::from_millis(2000) { // let p = Paragraph::new(Line::from("~ Kana SH ~")).centered(); @@ -76,11 +68,25 @@ fn main() { }); } + let mut app = App::new(); + if let Some(path) = arg.path { + let assets = std::fs::read_dir(path) + .unwrap() + .map(|entry| entry.unwrap().path().to_str().unwrap().to_string()) + .collect::>(); + app.background_paths = assets; + } + // Main app rendering while !app.exit { let _ = terminal.draw(|frame| app.view(frame, start_time.elapsed())); - let mut current_msg = app.handle_event(); + let mut current_msg = None; + if event::poll(Duration::from_millis(10)).unwrap() { + if let Event::Key(key) = event::read().unwrap() { + current_msg = app.handle_event(&key); + } + } while current_msg.is_some() { current_msg = app.update(current_msg.unwrap()); From 749df636273596948341ec2c4fa00b7de6b2cf9d Mon Sep 17 00:00:00 2001 From: benoitlx Date: Tue, 18 Nov 2025 16:46:15 +0100 Subject: [PATCH 10/20] chore: handy recipe and changing lsp target for helix --- .helix/languages.toml | 2 ++ justfile | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .helix/languages.toml create mode 100644 justfile diff --git a/.helix/languages.toml b/.helix/languages.toml new file mode 100644 index 0000000..4e50d77 --- /dev/null +++ b/.helix/languages.toml @@ -0,0 +1,2 @@ +[language-server.rust-analyzer.config] +rust-analyzer.cargo.target = "wasm32-unknown-unknown" diff --git a/justfile b/justfile new file mode 100644 index 0000000..5ff8d65 --- /dev/null +++ b/justfile @@ -0,0 +1,27 @@ +native-crate := "kanash" +wasm-crate := "kanash-ratzilla" + +[private] +default: + @just --list --justfile {{justfile()}} + +# target only native package +[group("build")] +build-native: + cargo build -p {{native-crate}} + +# target only wasm package +[group("build")] +build-wasm: + cargo build --target wasm32-unknown-unknown -p {{wasm-crate}} + +# build all +[group("build")] +build: + @just build-native + @just build-wasm + +# Find TODOs and comments silencing lints +[group('tooling')] +todo: + grep --recursive --extended-regexp --ignore-case --line-number --color=always 'noqa|todo' --exclude-dir target From 717c3dc0005bb358bbd72f8b7512b69117cb1291 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Tue, 18 Nov 2025 16:48:41 +0100 Subject: [PATCH 11/20] ci: new build command --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 344be6e..1ecf328 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,5 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - - run: cargo test --verbose + - run: cargo build -p kanash + - run: cargo build --target wasm32-unknown-unknown -p kanash-ratzilla + - run: cargo test --verbose --exclude kanash-ratzilla - run: cargo fmt --check From db18a9d1ba837a07b96b70c063af300596cee16e Mon Sep 17 00:00:00 2001 From: benoitlx Date: Tue, 18 Nov 2025 16:49:44 +0100 Subject: [PATCH 12/20] feat(wasm): splash screen --- Cargo.lock | 21 +++++++++- kanash-components/src/helper/ja.rs | 4 +- kanash-ratzilla/Cargo.toml | 3 ++ kanash-ratzilla/src/main.rs | 63 ++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acf2da9..946e863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -898,7 +898,7 @@ dependencies = [ "rand_pcg 0.9.0", "rascii_art", "ratatui", - "tachyonfx", + "tachyonfx 0.13.0", "tokio", "tui-big-text", "tui-rain", @@ -920,7 +920,7 @@ dependencies = [ "rascii_art", "ratatui", "ratzilla", - "tachyonfx", + "tachyonfx 0.13.0", "tokio", "tui-big-text", "tui-rain", @@ -935,6 +935,9 @@ version = "0.1.0" dependencies = [ "kanash-components", "ratzilla", + "tachyonfx 0.20.1", + "tui-big-text", + "wasm-bindgen", "web-sys", "web-time", ] @@ -1540,6 +1543,20 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "tachyonfx" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8d12f9a009654ae418254aa361dd61d9f9a581bcc27d024f39cb7ccaee33f" +dependencies = [ + "bon", + "compact_str 0.9.0", + "ratatui", + "thiserror 2.0.17", + "unicode-width 0.2.0", + "web-time", +] + [[package]] name = "tap" version = "1.0.1" diff --git a/kanash-components/src/helper/ja.rs b/kanash-components/src/helper/ja.rs index cdd8f70..eba08c7 100644 --- a/kanash-components/src/helper/ja.rs +++ b/kanash-components/src/helper/ja.rs @@ -2,7 +2,7 @@ use rand::{seq::IndexedRandom, Rng}; use rand_pcg::Mcg128Xsl64; const HIRAGANA_NUMBER: usize = 71; -const WANTED_KANA: [u16; HIRAGANA_NUMBER] = [ +pub const WANTED_KANA: [u16; HIRAGANA_NUMBER] = [ 12354, 12356, 12358, 12360, 12362, 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383, 12384, 12385, 12386, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, @@ -11,7 +11,7 @@ const WANTED_KANA: [u16; HIRAGANA_NUMBER] = [ 12427, 12428, 12429, 12431, 12434, 12435, ]; const KATAKANA_NUMBER: usize = 81; -const WANTED_KATAKANA: [u16; KATAKANA_NUMBER] = [ +pub const WANTED_KATAKANA: [u16; KATAKANA_NUMBER] = [ 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, 12482, 12484, 12485, 12486, 12487, 12488, diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 5034dab..3ad9b45 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -11,6 +11,9 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } ratzilla = "0.2.0" +tachyonfx = { version = "0.20.1", default-features = false, features = ["wasm"] } +tui-big-text = "0.7.3" +wasm-bindgen = "0.2.105" web-time = "1.1.0" [dev-dependencies] diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 58f654c..1fa6c36 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,7 +1,16 @@ -use kanash_components::{app::App, Components}; +use kanash_components::{app::App, ColorPalette, Components}; -use ratzilla::ratatui::Terminal; -use ratzilla::{DomBackend, WebGl2Backend, WebRenderer}; +use ratzilla::backend::webgl2::WebGl2BackendOptions; +use ratzilla::ratatui::{ + layout::{Constraint, Layout}, + style::Style, + text::Line, + Terminal, +}; +use ratzilla::{CanvasBackend, DomBackend, WebGl2Backend, WebRenderer}; + +use tachyonfx::{fx, EffectRenderer}; +use tui_big_text::{BigText, PixelSize}; use std::io; use web_time::Instant; @@ -15,13 +24,16 @@ fn new_outbox() -> Outbox { } fn main() -> io::Result<()> { - let backend = DomBackend::new()?; + let webgl2_options = WebGl2BackendOptions::new().fallback_glyph("@"); + let backend = WebGl2Backend::new_with_options(webgl2_options)?; let terminal = Terminal::new(backend)?; let mut render_app = App::new(); let mut event_app = App::new(); let start_time = Instant::now(); + let mut fade_effect = fx::dissolve(2000); //(20000, Interpolation::QuadOut)); + let outbox: Outbox = new_outbox(); let outbox_event = Rc::clone(&outbox); @@ -37,11 +49,46 @@ fn main() -> io::Result<()> { }); terminal.draw_web(move |f| { - render_app.view(f, start_time.elapsed()); + let p = BigText::builder() + .pixel_size(PixelSize::HalfHeight) + .lines(vec![">> Kana SH <<".into()]) + .centered() + .style(Style::fg(Style::new(), ColorPalette::TITLE)) + .build(); + + let credit = Line::from("@benoitlx") + .centered() + .style(Style::fg(Style::new(), ColorPalette::SUBTITLE)); + + let [_, area, _, bottom] = Layout::vertical([ + Constraint::Min(0), + Constraint::Length(4), + Constraint::Min(0), + Constraint::Length(1), + ]) + .areas(f.area()); - let mut current_msg = outbox.borrow_mut().take(); - while current_msg.is_some() { - current_msg = render_app.update(current_msg.unwrap()); + let [_, creds_area, _] = Layout::horizontal([ + Constraint::Min(0), + Constraint::Percentage(10), + Constraint::Min(0), + ]) + .areas(bottom); + + if start_time.elapsed() < web_time::Duration::from_millis(1000) { + f.render_widget(p, area); + f.render_widget(credit, creds_area); + } else if start_time.elapsed() < web_time::Duration::from_millis(1800) { + f.render_widget(p, area); + f.render_widget(credit, creds_area); + f.render_effect(&mut fade_effect, area, tachyonfx::Duration::from_millis(33)); + } else { + render_app.view(f, start_time.elapsed()); + + let mut current_msg = outbox.borrow_mut().take(); + while current_msg.is_some() { + current_msg = render_app.update(current_msg.unwrap()); + } } }); From 7145218f9b980f5868154183e544bc30ec430085 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 09:44:30 +0100 Subject: [PATCH 13/20] feat(wasm): rain effect --- Cargo.lock | 692 ++++++++++++++++++++- kanash-components/Cargo.toml | 5 +- kanash-components/src/app.rs | 4 +- kanash-components/src/helper/background.rs | 667 -------------------- kanash-components/src/helper/mod.rs | 5 +- kanash-components/src/helper/rain.rs | 13 +- kanash-ratzilla/Cargo.toml | 5 +- kanash-ratzilla/bitmap_font.atlas | Bin 0 -> 179160 bytes kanash-ratzilla/src/main.rs | 16 +- 9 files changed, 714 insertions(+), 693 deletions(-) delete mode 100644 kanash-components/src/helper/background.rs create mode 100644 kanash-ratzilla/bitmap_font.atlas diff --git a/Cargo.lock b/Cargo.lock index 946e863..3a43863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,30 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -104,11 +122,47 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "beamterm-atlas" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d831c97a6045c889c5ed7c8cb7eb8645b83633f6f6ac5c1aef772f7e0549aa" +dependencies = [ + "beamterm-data", + "clap", + "color-eyre", + "colored", + "compact_str 0.9.0", + "cosmic-text", + "directories", + "emojis", + "itertools 0.14.0", + "tracing", + "tracing-appender", + "tracing-subscriber", + "unicode-segmentation", +] + [[package]] name = "beamterm-data" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9440270ceba7fccbd5aab22ffba8abafd13b63d30bc42c417b622fcc9643d7" +checksum = "03a460829990fe27b44ebdd2864258078955b0181a3d0d0ca32014d098eb756b" dependencies = [ "compact_str 0.9.0", "miniz_oxide", @@ -116,9 +170,9 @@ dependencies = [ [[package]] name = "beamterm-renderer" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100e6159f2cd12ca83f89adaa812966d221616510c0a09afd4e1ea8e0f704bfb" +checksum = "11d0f031d2e6c679e46cfcd03c6443b760338467d2191423e8d7e663153ca670" dependencies = [ "beamterm-data", "compact_str 0.9.0", @@ -196,6 +250,20 @@ name = "bytemuck" version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "byteorder" @@ -270,6 +338,33 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +[[package]] +name = "color-eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -282,6 +377,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "colorsys" version = "0.6.7" @@ -335,6 +439,29 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cosmic-text" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" +dependencies = [ + "bitflags 2.10.0", + "fontdb", + "log", + "rangemap", + "rustc-hash", + "rustybuzz", + "self_cell", + "smol_str", + "swash", + "sys-locale", + "ttf-parser 0.21.1", + "unicode-bidi", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -344,6 +471,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -549,6 +685,27 @@ dependencies = [ "syn", ] +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + [[package]] name = "document-features" version = "0.2.12" @@ -564,6 +721,15 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "emojis" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52f3d011046a013bdefbc63a5523b06ad0c0f1e227941baf98475496229d634" +dependencies = [ + "phf", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -595,6 +761,16 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -626,12 +802,44 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "font-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +dependencies = [ + "bytemuck", +] + [[package]] name = "font8x8" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e" +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.20.0", +] + [[package]] name = "funty" version = "2.0.0" @@ -727,6 +935,17 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -751,6 +970,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "half" version = "2.7.1" @@ -803,6 +1028,12 @@ dependencies = [ "tiff", ] +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + [[package]] name = "indoc" version = "2.0.7" @@ -913,7 +1144,7 @@ dependencies = [ "anyhow", "clap", "futures", - "getrandom", + "getrandom 0.3.4", "rand 0.9.2", "rand_core 0.6.4", "rand_pcg 0.9.0", @@ -933,6 +1164,7 @@ dependencies = [ name = "kanash-ratzilla" version = "0.1.0" dependencies = [ + "beamterm-atlas", "kanash-components", "ratzilla", "tachyonfx 0.20.1", @@ -960,6 +1192,22 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.10.0", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1002,12 +1250,30 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1046,6 +1312,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1070,6 +1345,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -1082,6 +1366,18 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + [[package]] name = "parking_lot" version = "0.12.5" @@ -1111,6 +1407,24 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1241,7 +1555,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] @@ -1262,6 +1576,12 @@ dependencies = [ "rand_core 0.9.3", ] +[[package]] +name = "rangemap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c" + [[package]] name = "rascii_art" version = "0.4.5" @@ -1299,8 +1619,7 @@ dependencies = [ [[package]] name = "ratzilla" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f4bf83094f5e2cce7f8d90a853f76d7254b6763d25b9cdfe11d0e76e16522" +source = "git+https://github.com/benoitlx/ratzilla.git#c46f010384a19a949078a8934d213875dca4e394" dependencies = [ "beamterm-renderer", "bitvec", @@ -1308,6 +1627,7 @@ dependencies = [ "console_error_panic_hook", "ratatui", "thiserror 2.0.17", + "unicode-width 0.2.0", "web-sys", ] @@ -1331,6 +1651,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "read-fonts" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +dependencies = [ + "bytemuck", + "font-types", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1340,6 +1670,52 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.17", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.44" @@ -1372,6 +1748,23 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rustybuzz" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" +dependencies = [ + "bitflags 2.10.0", + "bytemuck", + "libm", + "smallvec", + "ttf-parser 0.21.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.20" @@ -1384,6 +1777,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "self_cell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" + [[package]] name = "serde" version = "1.0.228" @@ -1413,6 +1812,28 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.18" @@ -1461,18 +1882,49 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "832ddd7df0d98d6fd93b973c330b7c8e0742d5cb8f1afc7dea89dba4d2531aa1" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "skrifa" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts", +] + [[package]] name = "slab" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" + [[package]] name = "socket2" version = "0.6.1" @@ -1517,6 +1969,17 @@ dependencies = [ "syn", ] +[[package]] +name = "swash" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47846491253e976bdd07d0f9cc24b7daf24720d11309302ccbbc6e6b6e53550a" +dependencies = [ + "skrifa", + "yazi", + "zeno", +] + [[package]] name = "syn" version = "2.0.108" @@ -1528,6 +1991,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "libc", +] + [[package]] name = "tachyonfx" version = "0.13.0" @@ -1603,6 +2075,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tiff" version = "0.9.1" @@ -1621,12 +2102,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", + "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -1635,6 +2118,31 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.48.0" @@ -1663,6 +2171,114 @@ dependencies = [ "syn", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror 1.0.69", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + [[package]] name = "tui-big-text" version = "0.7.3" @@ -1686,12 +2302,48 @@ dependencies = [ "ratatui", ] +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" + +[[package]] +name = "unicode-ccc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -1727,6 +2379,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wana_kana" version = "4.0.0" @@ -2036,6 +2700,18 @@ dependencies = [ "tap", ] +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + [[package]] name = "zerocopy" version = "0.8.27" diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 16496f3..3ce39b8 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -18,13 +18,16 @@ futures = "0.3.31" rand_pcg = "0.9.0" rascii_art = "0.4.5" clap = { version = "4.5.37", features = ["derive"] } +tui-rain = "1.0.1" [dev-dependencies] web-sys = "0.3.82" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } -ratzilla = "0.2.0" +# ratzilla = "0.2.0" +# ratzilla = { path = "../../ratzilla/" } +ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } web-time = "1.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/kanash-components/src/app.rs b/kanash-components/src/app.rs index fd68a84..affd8b8 100644 --- a/kanash-components/src/app.rs +++ b/kanash-components/src/app.rs @@ -1,7 +1,6 @@ use super::{home::HomeModel, kana::KanaModel, *}; - -#[cfg(not(target_arch = "wasm32"))] use crate::helper::rain; + #[cfg(not(target_arch = "wasm32"))] use ansi_to_tui::IntoText; #[cfg(not(target_arch = "wasm32"))] @@ -132,7 +131,6 @@ impl Components for App { self.background(frame); } - #[cfg(not(target_arch = "wasm32"))] if !self.disable_rain { rain::view(frame, elapsed); } diff --git a/kanash-components/src/helper/background.rs b/kanash-components/src/helper/background.rs deleted file mode 100644 index 0bae4d3..0000000 --- a/kanash-components/src/helper/background.rs +++ /dev/null @@ -1,667 +0,0 @@ -#![allow(dead_code)] - -/// From https://github.com/Levilutz/tui-rain/blob/main/src/lib.rs -/// Thanks to Levi Lutz -use std::{cmp::Ordering, time::Duration}; - -use rand::{RngCore, SeedableRng}; -use rand_pcg::Pcg64Mcg; -use ratatui::{ - buffer::Buffer, - layout::Rect, - style::{Color, Style, Stylize}, - widgets::Widget, -}; - -/// A configuration for the density of the rain effect. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum RainDensity { - /// An absolute target number of drops to have in the frame. - Absolute { num_drops: usize }, - - /// Compute the number of drops based on the frame size. Lower value is denser. - /// - /// Is converted to an absolute value, with 1 drop per `sparseness` pixels. - Relative { sparseness: usize }, - - /// A dense rain. Equivalent to `Relative { sparseness: 20 }`. - Dense, - - /// A normal rain. Equivalent to `Relative { sparseness: 50 }`. - Normal, - - /// A sparse rain. Equivalent to `Relative { sparseness: 100 }`. - Sparse, -} - -impl RainDensity { - /// Get the absolute number of drops given an area. - fn num_drops(&self, area: Rect) -> usize { - match self { - RainDensity::Absolute { num_drops } => *num_drops, - RainDensity::Relative { sparseness } if *sparseness == 0 => 0, - RainDensity::Relative { sparseness } => { - (area.width * area.height) as usize / *sparseness - } - RainDensity::Dense => RainDensity::Relative { sparseness: 20 }.num_drops(area), - RainDensity::Normal => RainDensity::Relative { sparseness: 50 }.num_drops(area), - RainDensity::Sparse => RainDensity::Relative { sparseness: 100 }.num_drops(area), - } - } -} - -/// The speed of the rain. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub enum RainSpeed { - /// An absolute target speed in pixels / second. - Absolute { speed: f64 }, - - /// A fast rain. Equivalent to `Absolute { speed: 20.0 }`. - Fast, - - /// A normal rain. Equivalent to `Absolute { speed: 10.0 }`. - Normal, - - /// A slow rain. Equivalent to `Absolute { speed: 5.0 }`. - Slow, -} - -impl RainSpeed { - /// Get the absolute speed. - fn speed(&self) -> f64 { - match self { - RainSpeed::Absolute { speed } => *speed, - RainSpeed::Fast => 20.0, - RainSpeed::Normal => 10.0, - RainSpeed::Slow => 5.0, - } - } -} - -/// A character set for the rain. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -pub enum CharacterSet { - /// An explicit enumeration of character options. This is the least performant. - Explicit { options: Vec }, - - /// A range of unicode values. - UnicodeRange { start: u32, len: u32 }, - - /// Half-width Japanese Kana characters. This is the closest to the original. - /// - /// Equivalent to `CharacterSet::UnicodeRange { start: 0xFF66, len: 56 }`. - HalfKana, - - /// The lowercase English alphabet. - /// - /// Equivalent to `CharacterSet::UnicodeRange { start: 0x61, len: 26 }`. - Lowercase, -} - -impl CharacterSet { - fn get(&self, seed: u32) -> char { - match self { - CharacterSet::Explicit { options } => options[seed as usize % options.len()], - CharacterSet::UnicodeRange { start, len } => { - char::from_u32((seed % len) + start).unwrap() - } - CharacterSet::HalfKana => CharacterSet::UnicodeRange { - start: 0xFF66, - len: 56, - } - .get(seed), - CharacterSet::Lowercase => CharacterSet::UnicodeRange { - start: 0x61, - len: 26, - } - .get(seed), - } - } - - fn size(&self) -> usize { - match self { - CharacterSet::Explicit { options } => options.len(), - CharacterSet::UnicodeRange { start: _, len } => *len as usize, - CharacterSet::HalfKana => 56, - CharacterSet::Lowercase => 26, - } - } -} - -#[derive(Clone, PartialEq, Debug)] -pub struct Rain { - elapsed: Duration, - seed: u64, - rain_density: RainDensity, - rain_speed: RainSpeed, - rain_speed_variance: f64, - tail_lifespan: Duration, - color: Color, - head_color: Color, - bold_dim_effect: bool, - noise_interval: Duration, - character_set: CharacterSet, -} - -impl Rain { - /// Construct a new rain widget with defaults for matrix rain. - pub fn new_matrix(elapsed: Duration) -> Rain { - Rain { - elapsed, - seed: 1234, - rain_density: RainDensity::Normal, - rain_speed: RainSpeed::Slow, - rain_speed_variance: 0.5, - tail_lifespan: Duration::from_secs(2), - color: Color::LightGreen, - head_color: Color::White, - bold_dim_effect: true, - noise_interval: Duration::from_secs(5), - character_set: CharacterSet::HalfKana, - } - } - - /// Construct a new rain widget with defaults for standard rain. - pub fn new_rain(elapsed: Duration) -> Rain { - Rain { - elapsed, - seed: 1234, - rain_density: RainDensity::Dense, - rain_speed: RainSpeed::Fast, - rain_speed_variance: 0.5, - tail_lifespan: Duration::from_millis(250), - color: Color::LightBlue, - head_color: Color::White, - bold_dim_effect: true, - noise_interval: Duration::from_secs(1), - character_set: CharacterSet::UnicodeRange { - start: 0x7c, - len: 1, - }, - } - } - - /// Construct a new rain widget with defaults for snow. - pub fn new_snow(elapsed: Duration) -> Rain { - Rain { - elapsed, - seed: 1234, - rain_density: RainDensity::Dense, - rain_speed: RainSpeed::Absolute { speed: 2.0 }, - rain_speed_variance: 0.1, - tail_lifespan: Duration::from_millis(500), - color: Color::White, - head_color: Color::White, - bold_dim_effect: true, - noise_interval: Duration::from_secs(1), - character_set: CharacterSet::UnicodeRange { - start: 0x2a, - len: 1, - }, - } - } - - /// Construct a new rain widget with defaults for emoji soup. - /// - /// Terminals that render emojis as two characters wide will not enjoy this. - pub fn new_emoji_soup(elapsed: Duration) -> Rain { - Rain { - elapsed, - seed: 1234, - rain_density: RainDensity::Dense, - rain_speed: RainSpeed::Normal, - rain_speed_variance: 0.1, - tail_lifespan: Duration::from_millis(500), - color: Color::White, - head_color: Color::White, - bold_dim_effect: true, - noise_interval: Duration::from_secs(1), - character_set: CharacterSet::UnicodeRange { - start: 0x1f600, - len: 80, - }, - } - } - - /// Set the random seed for the generation. - /// - /// The random seed can be configured. Given a constant screen size, results should - /// be reproducible across executions, operating systems, and architectures. - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_seed(1234); - /// ``` - pub fn with_seed(mut self, seed: u64) -> Rain { - self.seed = seed; - self - } - - /// Set the target density for the rain. - /// - /// This can be configured as an absolute number of drops: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::{Rain, RainDensity}; - /// - /// Rain::new_matrix(Duration::from_secs(0)) - /// .with_rain_density(RainDensity::Absolute { - /// num_drops: 100, - /// }); - /// ``` - /// Or a ratio of screen pixels to drops (lower is more dense): - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::{Rain, RainDensity}; - /// - /// Rain::new_matrix(Duration::from_secs(0)) - /// .with_rain_density(RainDensity::Relative { - /// sparseness: 50, - /// }); - /// ``` - /// - /// The actual number of drops on the screen at any time is randomly distributed - /// between 0 and twice the target. - /// - /// Preset relative options include: - /// - /// - `RainDensity::Sparse` - /// - `RainDensity::Normal` - /// - `RainDensity::Dense` - pub fn with_rain_density(mut self, rain_density: RainDensity) -> Rain { - self.rain_density = rain_density; - self - } - - /// Set the target speed for the rain. - /// - /// Speed can be configured as an absolute value of pixels per second, or as a - /// preset. - /// - /// For an absolute speed in pixels per second: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::{Rain, RainSpeed}; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_rain_speed(RainSpeed::Absolute { - /// speed: 10.0, - /// }); - /// ``` - /// - /// Preset options include: - /// - /// - `RainSpeed::Slow` - /// - `RainSpeed::Normal` - /// - `RainSpeed::Fast` - pub fn with_rain_speed(mut self, rain_speed: RainSpeed) -> Rain { - self.rain_speed = rain_speed; - self - } - - /// Set the rain speed variance. - /// - /// To avoid perfectly consistent patterns, you can configure some variance in the - /// speed of each drop. This can also give an impression of parallax (depth). - /// - /// For example, a value of `0.1` will cause each drop's speed to be uniformly - /// distrbuted within ±10% of the target speed: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_rain_speed_variance(0.1); - /// ``` - /// - /// The speed of an individual drop will never go below 0.001 pixels / second, but - /// can vary arbitrarily high. - pub fn with_rain_speed_variance(mut self, rain_speed_variance: f64) -> Rain { - self.rain_speed_variance = rain_speed_variance; - self - } - - /// Set the tail lifespan for the rain. - /// - /// You can make the rain drop tails appear shorter / longer by configuring how long - /// the tail effect lasts: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_tail_lifespan(Duration::from_secs(5)); - /// ``` - /// - /// The drop length is capped at the screen height to avoid strange wraparound - /// effects. - pub fn with_tail_lifespan(mut self, tail_lifespan: Duration) -> Rain { - self.tail_lifespan = tail_lifespan; - self - } - - /// Set the color for the rain. - /// - /// You can change the tail color for each drop: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_color(ratatui::style::Color::LightGreen); - /// ``` - /// - /// The color of the head is [independently configured](Rain::with_head_color). The - /// bold / dim effects that automatically get applied over a drop's length may tweak - /// the color inadvertently, but [this can be disabled](Rain::with_bold_dim_effect). - pub fn with_color(mut self, color: Color) -> Rain { - self.color = color; - self - } - - /// Set the head color for the rain. - /// - /// You can change the head color for each drop: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_head_color(ratatui::style::Color::Green); - /// ``` - /// - /// The color of the tail is [independently configured](Rain::with_color). The - /// bold / dim effects that automatically get applied over a drop's length may tweak - /// the color inadvertently, but [this can be disabled](Rain::with_bold_dim_effect). - pub fn with_head_color(mut self, head_color: Color) -> Rain { - self.head_color = head_color; - self - } - - /// Set whether to apply the bold / dim effect. - /// - /// By default, the lower third of each drop has the bold effect applied, and the - /// upper third has the dim effect applied. This produces an impression of the drop - /// fading instead of abruptly ending. - /// - /// This may tweak the color of glyphs away from the base color on some terminals, - /// so it can be disabled if desired: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_bold_dim_effect(false); - ///``` - pub fn with_bold_dim_effect(mut self, bold_dim_effect: bool) -> Rain { - self.bold_dim_effect = bold_dim_effect; - self - } - - /// Set the interval between random character changes. - /// - /// A more subtle effect is that glyphs already rendered in a drop occasionally - /// switch characters before dissapearing. The time interval between each character - /// switch is per-glyph, and can be adjusted: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::Rain; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_noise_interval(Duration::from_secs(10)); - /// ``` - pub fn with_noise_interval(mut self, noise_interval: Duration) -> Rain { - self.noise_interval = noise_interval; - self - } - - /// Set the character set for the drops. - /// - /// The simplest option is to provide an explicit set of characters to choose from: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::{CharacterSet, Rain}; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_character_set(CharacterSet::Explicit { - /// options: vec!['a', 'b', 'c'], - /// }); - /// ``` - /// - /// More performant is to provide a unicode range: - /// - /// ``` - /// use std::time::Duration; - /// use tui_rain::{CharacterSet, Rain}; - /// - /// let elapsed = Duration::from_secs(5); - /// - /// Rain::new_matrix(elapsed) - /// .with_character_set(CharacterSet::UnicodeRange { - /// start: 0x61, - /// len: 26, - /// }); - /// ``` - /// - /// Preset unicode ranges include: - /// - /// - `CharacterSet::HalfKana` is the half-width Japanese kana character set (used - /// in the classic matrix rain) - /// - `CharacterSet::Lowercase` is the lowercase English character set - pub fn with_character_set(mut self, character_set: CharacterSet) -> Rain { - self.character_set = character_set; - self - } - - /// Build the rng. Uses a fast but portable and reproducible rng. - fn build_rng(&self) -> impl RngCore { - Pcg64Mcg::seed_from_u64(self.seed) - } - - /// Build a drop from the given consistent initial entropy state. - /// - /// The entropy vector's length becomes the drop's track length, so ensure it's at - /// least the window height. - fn build_drop(&self, entropy: Vec, width: u16, height: u16) -> Vec { - let elapsed = self.elapsed.as_secs_f64(); - let rain_speed = self.rain_speed.speed(); - let tail_lifespan = self.tail_lifespan.as_secs_f64(); - let noise_interval = self.noise_interval.as_secs_f64(); - - // A single drop can expect to be called with the exact same entropy vec on each - // frame. This means we can sample the entropy vec to reproducibly generate - // features every frame (e.g. speed). - - // Later code assumes at least 1 entry in the entropy vec, so break early if not. - if entropy.is_empty() { - return vec![]; - } - - // The length of the entropy vec becomes the length of the drop's track. - // This track is usually longer than the screen height by a random amount. - let track_len = entropy.len() as u16; - - // Use some entropy to compute the drop's actual speed. - // n.b. since the entropy vec is stable, the drop's speed will not vary over time. - let rain_speed = uniform( - entropy[0], - rain_speed * (1.0 - self.rain_speed_variance), - rain_speed * (1.0 + self.rain_speed_variance), - ) - .max(1e-3); // Prevent speed from hitting 0 (if user specifies high variance) - - // Compute how long our drop will take to make 1 cycle given our track len and speed - let cycle_time_secs = entropy.len() as f64 / rain_speed; - - // Use some entropy to compute a stable random time offset for this drop. - // If this value were 0, every drop would start falling with an identical y value. - let initial_cycle_offset_secs = uniform(entropy[0], 0.0, cycle_time_secs); - - // Compute how far we are into the current cycle and current drop head height. - let current_cycle_offset_secs = (elapsed + initial_cycle_offset_secs) % cycle_time_secs; - let head_y = (current_cycle_offset_secs * rain_speed) as u16; - - // Compute drop length given speed and tail lifespan. - // Cap at screen height to avoid weird wraparound when tail length is long. - let drop_len = ((rain_speed * tail_lifespan) as u16).min(height); - - // Render each glyph in the drop. - (0..drop_len) - .filter_map(|y_offset| { - // Compute how long ago this glyph would have first appeared - let age = y_offset as f64 / rain_speed; - - // If it would have first appeared before the rendering began, don't render. - if age > elapsed { - return None; - } - - // Compute which cycle this particular glyph is a member of - let cycle_num = - ((elapsed + initial_cycle_offset_secs - age) / cycle_time_secs) as usize; - - // Don't render glyphs from cycle 0 - // (prevents drops from appearing to spawn in the middle of the screen) - if cycle_num == 0 { - return None; - } - - // Get stable entropy to decide what column cycle X is rendered in. - // This must be per-glyph to prevent drops from jumping side-to-side when they wrap around. - let x_entropy = entropy[cycle_num % entropy.len()]; - let x = (x_entropy % width as u64) as u16; - - // Compute the y value for this glyph, and don't render if off the screen. - let y = (head_y + track_len - y_offset) % track_len; - if y >= height { - return None; - } - - // The 'noise' of glyphs randomly changing is actually modeled as every glyph in the track - // just cycling through possible values veeeery slowly. We need a random offset for this - // cycling so every glyph doesn't change at the same time. - let time_offset = uniform( - entropy[y as usize], - 0.0, - noise_interval * self.character_set.size() as f64, - ); - - // Decide what character is rendered based on noise. - let content = self - .character_set - .get(((time_offset + elapsed) / noise_interval) as u32); - - // Compute the styling for the glyph - let mut style = Style::default(); - - // Color appropriately depending on whether this glyph is the head. - if age > 0.0 { - style = style.fg(self.color) - } else { - style = style.fg(self.head_color) - } - - // The lowest third of glyphs is bold, the highest third is dim - if self.bold_dim_effect { - if y_offset < drop_len / 3 { - style = style.bold().not_dim() - } else if y_offset > drop_len * 2 / 3 { - style = style.dim().not_bold() - } else { - style = style.not_bold().not_dim() - } - } - - Some(Glyph { - x, - y, - age, - content, - style, - }) - }) - .collect() - } -} - -impl Widget for Rain { - fn render(self, area: Rect, buf: &mut Buffer) { - let mut rng = self.build_rng(); - - // We don't actually have n drops with tracks equal to the screen height. - // We actually have 2n drops with tracks ranging from 1.5 to 2.5 the screen height. - // This introduces more randomness to the apparent n and reduces cyclic appearance. - let num_drops = self.rain_density.num_drops(area) * 2; - let drop_track_lens: Vec = (0..num_drops) - .map(|_| (area.height as u64 * 3 / 2 + rng.next_u64() % area.height as u64) as usize) - .collect(); - - // We construct entropy consistently every frame to mimic statefulness. - // This is not a performance bottleneck, so caching wouldn't deliver much benefit. - let entropy: Vec> = drop_track_lens - .iter() - .map(|track_len| (0..*track_len).map(|_| rng.next_u64()).collect()) - .collect(); - - // For every entropy vec, construct a single drop (vertical line of glyphs). - let mut glyphs: Vec = entropy - .into_iter() - .flat_map(|drop_entropy| self.build_drop(drop_entropy, area.width, area.height)) - .collect(); - - // Sort all the glyphs by age so drop heads always render on top. - // This is a moderate bottleneck when the screen is large / there's a lot of glyphs. - glyphs.sort_by(|a, b| a.age.partial_cmp(&b.age).unwrap_or(Ordering::Equal)); - - // Actually render to the buffer. - for glyph in glyphs { - buf[(glyph.x, glyph.y)].set_char(glyph.content); - buf[(glyph.x, glyph.y)].set_style(glyph.style); - } - } -} - -/// A Glyph to be rendered on the screen. -struct Glyph { - x: u16, - y: u16, - age: f64, - content: char, - style: Style, -} - -/// Map a uniform random u64 to a uniform random f64 in the range [lower, upper). -fn uniform(seed: u64, lower: f64, upper: f64) -> f64 { - (seed as f64 / u64::MAX as f64) * (upper - lower) + lower -} diff --git a/kanash-components/src/helper/mod.rs b/kanash-components/src/helper/mod.rs index 1699f5f..2837585 100644 --- a/kanash-components/src/helper/mod.rs +++ b/kanash-components/src/helper/mod.rs @@ -1,8 +1,5 @@ pub mod ja; +pub mod rain; #[cfg(not(target_arch = "wasm32"))] pub mod background; -#[cfg(not(target_arch = "wasm32"))] -pub mod rain; - -// pub mod image; diff --git a/kanash-components/src/helper/rain.rs b/kanash-components/src/helper/rain.rs index aba9557..8d9bf7a 100644 --- a/kanash-components/src/helper/rain.rs +++ b/kanash-components/src/helper/rain.rs @@ -1,7 +1,16 @@ +#[cfg(not(target_arch = "wasm32"))] use ratatui::{style::Color, Frame}; + +#[cfg(not(target_arch = "wasm32"))] use std::time::Duration; -use super::background::{CharacterSet, Rain, RainDensity, RainSpeed}; +#[cfg(target_arch = "wasm32")] +use ratzilla::ratatui::{style::Color, Frame}; + +#[cfg(target_arch = "wasm32")] +use web_time::Duration; + +use tui_rain::{CharacterSet, Rain, RainDensity, RainSpeed}; const TAIL_COLOR: Color = Color::from_u32(0x0008dbbe); @@ -17,7 +26,7 @@ pub fn view(frame: &mut Frame, elapsed: Duration) { .clone() .with_character_set(CharacterSet::HalfKana) .with_tail_lifespan(Duration::from_millis(120)) - .with_color(ratatui::style::Color::LightGreen); + .with_color(Color::LightGreen); frame.render_widget(rain, frame.area()); frame.render_widget(kana_tail, frame.area()); diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 3ad9b45..8f1990d 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -9,8 +9,11 @@ license = "MIT" keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] +beamterm-atlas = "0.8.0" kanash-components = { path = "../kanash-components/" } -ratzilla = "0.2.0" +# ratzilla = "0.2.0" +# ratzilla = { path = "../../ratzilla/" } +ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } tachyonfx = { version = "0.20.1", default-features = false, features = ["wasm"] } tui-big-text = "0.7.3" wasm-bindgen = "0.2.105" diff --git a/kanash-ratzilla/bitmap_font.atlas b/kanash-ratzilla/bitmap_font.atlas new file mode 100644 index 0000000000000000000000000000000000000000..11dc5512db64a2a4ddccb557a1f8070b844dacad GIT binary patch literal 179160 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⪻!Ob#)!U@R{;! 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 XTsR|-kyIC|3;+4V?hPAOR#pBNNQ^%& literal 0 HcmV?d00001 diff --git a/kanash-ratzilla/src/main.rs b/kanash-ratzilla/src/main.rs index 1fa6c36..68c1588 100644 --- a/kanash-ratzilla/src/main.rs +++ b/kanash-ratzilla/src/main.rs @@ -1,6 +1,6 @@ use kanash_components::{app::App, ColorPalette, Components}; -use ratzilla::backend::webgl2::WebGl2BackendOptions; +use ratzilla::backend::webgl2::{FontAtlasData, WebGl2BackendOptions}; use ratzilla::ratatui::{ layout::{Constraint, Layout}, style::Style, @@ -19,13 +19,15 @@ use std::{cell::RefCell, rc::Rc}; type Outbox = Rc>>; -fn new_outbox() -> Outbox { - Rc::new(RefCell::new(None)) -} +static ATLAS_BYTES: &[u8] = include_bytes!("../bitmap_font.atlas"); fn main() -> io::Result<()> { - let webgl2_options = WebGl2BackendOptions::new().fallback_glyph("@"); - let backend = WebGl2Backend::new_with_options(webgl2_options)?; + // let webgl2_options = WebGl2BackendOptions::new() + // .fallback_glyph("@") + // .font_atlas(FontAtlasData::from_binary(ATLAS_BYTES).unwrap()); + // let backend = WebGl2Backend::new_with_options(webgl2_options)?; + let backend = DomBackend::new()?; + // let backend = CanvasBackend::new()?; let terminal = Terminal::new(backend)?; let mut render_app = App::new(); @@ -34,7 +36,7 @@ fn main() -> io::Result<()> { let mut fade_effect = fx::dissolve(2000); //(20000, Interpolation::QuadOut)); - let outbox: Outbox = new_outbox(); + let outbox: Outbox = Rc::new(RefCell::new(None)); let outbox_event = Rc::clone(&outbox); terminal.on_key_event({ From 157d9b5f2bc899767171bfc3eb82068e41a36d59 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 10:47:26 +0100 Subject: [PATCH 14/20] fix: no longer need background --- kanash-components/src/helper/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/kanash-components/src/helper/mod.rs b/kanash-components/src/helper/mod.rs index 2837585..2035d94 100644 --- a/kanash-components/src/helper/mod.rs +++ b/kanash-components/src/helper/mod.rs @@ -1,5 +1,2 @@ pub mod ja; pub mod rain; - -#[cfg(not(target_arch = "wasm32"))] -pub mod background; From e8413023217af7e0e353e75f273f1b3469935dc1 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 10:54:20 +0100 Subject: [PATCH 15/20] fix(ci): add wasm target --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1ecf328..dd94351 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,6 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - run: rustup target add wasm32-unknown-unknown - run: cargo build -p kanash - run: cargo build --target wasm32-unknown-unknown -p kanash-ratzilla - run: cargo test --verbose --exclude kanash-ratzilla From 279db45b98c99f6f8462af3b3ce7b4b8de6009a1 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 11:00:03 +0100 Subject: [PATCH 16/20] fix(ci): exclude syntax for cargo test --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dd94351..7c7087f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,5 +22,5 @@ jobs: - run: rustup target add wasm32-unknown-unknown - run: cargo build -p kanash - run: cargo build --target wasm32-unknown-unknown -p kanash-ratzilla - - run: cargo test --verbose --exclude kanash-ratzilla + - run: cargo test --verbose --workspace --exclude kanash-ratzilla - run: cargo fmt --check From 8a37442f892a26e92ecd912a114889c74010dae2 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 11:37:02 +0100 Subject: [PATCH 17/20] build: removing unused dependencies --- Cargo.lock | 1044 ++-------------------------------- kanash-components/Cargo.toml | 10 - kanash-ratzilla/Cargo.toml | 1 - kanash/Cargo.toml | 3 - 4 files changed, 51 insertions(+), 1007 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d3f4b4..92a9c3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,30 +2,12 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -92,72 +74,30 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "beamterm-atlas" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d831c97a6045c889c5ed7c8cb7eb8645b83633f6f6ac5c1aef772f7e0549aa" -dependencies = [ - "beamterm-data", - "clap", - "color-eyre", - "colored", - "compact_str 0.9.0", - "cosmic-text", - "directories", - "emojis", - "itertools 0.14.0", - "tracing", - "tracing-appender", - "tracing-subscriber", - "unicode-segmentation", -] - [[package]] name = "beamterm-data" version = "0.8.0" @@ -250,20 +190,6 @@ name = "bytemuck" version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "byteorder" @@ -271,12 +197,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - [[package]] name = "cassowary" version = "0.3.0" @@ -300,9 +220,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.52" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa8120877db0e5c011242f96806ce3c94e0737ab8108532a76a3300a01db2ab8" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -310,9 +230,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.52" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02576b399397b659c26064fbc92a75fede9d18ffd5f80ca1cd74ddab167016e1" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -338,33 +258,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "color-eyre" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "color_quant" version = "1.1.0" @@ -377,21 +270,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "colored" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "colorsys" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54261aba646433cb567ec89844be4c4825ca92a4f8afba52fc4dd88436e31bbd" - [[package]] name = "compact_str" version = "0.8.1" @@ -439,29 +317,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cosmic-text" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" -dependencies = [ - "bitflags 2.10.0", - "fontdb", - "log", - "rangemap", - "rustc-hash", - "rustybuzz", - "self_cell", - "smol_str", - "swash", - "sys-locale", - "ttf-parser 0.21.1", - "unicode-bidi", - "unicode-linebreak", - "unicode-script", - "unicode-segmentation", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -471,15 +326,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -685,27 +531,6 @@ dependencies = [ "syn", ] -[[package]] -name = "directories" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", -] - [[package]] name = "document-features" version = "0.2.12" @@ -721,15 +546,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "emojis" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52f3d011046a013bdefbc63a5523b06ad0c0f1e227941baf98475496229d634" -dependencies = [ - "phf", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -748,9 +564,9 @@ dependencies = [ [[package]] name = "exr" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", "half", @@ -761,16 +577,6 @@ dependencies = [ "zune-inflate", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fdeflate" version = "0.3.7" @@ -802,150 +608,18 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "font-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" -dependencies = [ - "bytemuck", -] - [[package]] name = "font8x8" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e" -[[package]] -name = "fontconfig-parser" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" -dependencies = [ - "roxmltree", -] - -[[package]] -name = "fontdb" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" -dependencies = [ - "fontconfig-parser", - "log", - "memmap2", - "slotmap", - "tinyvec", - "ttf-parser 0.20.0", -] - [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "getrandom" version = "0.3.4" @@ -970,12 +644,6 @@ dependencies = [ "weezl", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "half" version = "2.7.1" @@ -1028,12 +696,6 @@ dependencies = [ "tiff", ] -[[package]] -name = "indenter" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" - [[package]] name = "indoc" version = "2.0.7" @@ -1106,9 +768,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1119,18 +781,15 @@ name = "kanash" version = "0.1.4" dependencies = [ "ansi-to-tui", - "anyhow", "clap", "crossterm 0.29.0", - "futures", "kanash-components", "rand 0.9.2", "rand_core 0.9.3", "rand_pcg 0.9.0", "rascii_art", "ratatui", - "tachyonfx 0.13.0", - "tokio", + "tachyonfx", "tui-big-text", "tui-rain", "wana_kana", @@ -1141,22 +800,15 @@ name = "kanash-components" version = "0.1.4" dependencies = [ "ansi-to-tui", - "anyhow", - "clap", - "futures", - "getrandom 0.3.4", + "getrandom", "rand 0.9.2", "rand_core 0.9.3", "rand_pcg 0.9.0", "rascii_art", "ratatui", "ratzilla", - "tachyonfx 0.13.0", - "tokio", - "tui-big-text", "tui-rain", "wana_kana", - "web-sys", "web-time", ] @@ -1164,10 +816,9 @@ dependencies = [ name = "kanash-ratzilla" version = "0.1.0" dependencies = [ - "beamterm-atlas", "kanash-components", "ratzilla", - "tachyonfx 0.20.1", + "tachyonfx", "tui-big-text", "wasm-bindgen", "web-sys", @@ -1192,22 +843,6 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.10.0", - "libc", -] - [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -1250,30 +885,12 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "memmap2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" -dependencies = [ - "libc", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1312,15 +929,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1345,15 +953,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1366,18 +965,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "owo-colors" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" - [[package]] name = "parking_lot" version = "0.12.5" @@ -1407,36 +994,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "phf" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "png" version = "0.17.16" @@ -1495,9 +1052,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -1555,7 +1112,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.4", + "getrandom", ] [[package]] @@ -1576,12 +1133,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rangemap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c" - [[package]] name = "rascii_art" version = "0.4.5" @@ -1651,16 +1202,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "read-fonts" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" -dependencies = [ - "bytemuck", - "font-types", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1670,52 +1211,6 @@ dependencies = [ "bitflags 2.10.0", ] -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.17", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "roxmltree" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" - -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.38.44" @@ -1748,23 +1243,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "rustybuzz" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" -dependencies = [ - "bitflags 2.10.0", - "bytemuck", - "libm", - "smallvec", - "ttf-parser 0.21.1", - "unicode-bidi-mirroring", - "unicode-ccc", - "unicode-properties", - "unicode-script", -] - [[package]] name = "ryu" version = "1.0.20" @@ -1777,12 +1255,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "self_cell" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" - [[package]] name = "serde" version = "1.0.228" @@ -1812,28 +1284,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "signal-hook" version = "0.3.18" @@ -1857,9 +1307,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -1876,65 +1326,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "simple-easing" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832ddd7df0d98d6fd93b973c330b7c8e0742d5cb8f1afc7dea89dba4d2531aa1" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "skrifa" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" -dependencies = [ - "bytemuck", - "read-fonts", -] - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "slotmap" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" -dependencies = [ - "version_check", -] - [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "smol_str" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -1969,37 +1366,17 @@ dependencies = [ "syn", ] -[[package]] -name = "swash" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47846491253e976bdd07d0f9cc24b7daf24720d11309302ccbbc6e6b6e53550a" -dependencies = [ - "skrifa", - "yazi", - "zeno", -] - [[package]] name = "syn" -version = "2.0.108" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "sys-locale" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" -dependencies = [ - "libc", -] - [[package]] name = "tachyonfx" version = "0.20.1" @@ -2012,19 +1389,6 @@ dependencies = [ "ratatui", "thiserror 2.0.17", "unicode-width 0.2.0", -] - -[[package]] -name = "tachyonfx" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8d12f9a009654ae418254aa361dd61d9f9a581bcc27d024f39cb7ccaee33f" -dependencies = [ - "bon", - "compact_str 0.9.0", - "ratatui", - "thiserror 2.0.17", - "unicode-width 0.2.0", "web-time", ] @@ -2074,15 +1438,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "tiff" version = "0.9.1" @@ -2101,14 +1456,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde", "time-core", - "time-macros", ] [[package]] @@ -2117,167 +1470,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "ttf-parser" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" - -[[package]] -name = "ttf-parser" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" - [[package]] name = "tui-big-text" version = "0.7.3" @@ -2301,48 +1493,12 @@ dependencies = [ "ratatui", ] -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - -[[package]] -name = "unicode-bidi-mirroring" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" - -[[package]] -name = "unicode-ccc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" - [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-properties" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" - -[[package]] -name = "unicode-script" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" - [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -2378,18 +1534,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wana_kana" version = "4.0.0" @@ -2418,9 +1562,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -2431,9 +1575,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.55" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -2444,9 +1588,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2454,9 +1598,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", @@ -2467,18 +1611,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -2496,9 +1640,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "winapi" @@ -2534,16 +1678,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] @@ -2561,31 +1696,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -2594,96 +1712,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "wit-bindgen" version = "0.46.0" @@ -2699,32 +1769,20 @@ dependencies = [ "tap", ] -[[package]] -name = "yazi" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" - -[[package]] -name = "zeno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" - [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5" dependencies = [ "proc-macro2", "quote", diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index df501b3..980dc3c 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -9,19 +9,12 @@ license = "MIT" keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] -anyhow = "1.0.97" rand = "0.9.0" wana_kana = "4.0.0" -tokio = { version = "1.44.2" }#, features = ["full"] } rand_core = "0.9.3" tui-rain = "1.0.1" -futures = "0.3.31" rand_pcg = "0.9.0" rascii_art = "0.4.5" -clap = { version = "4.5.52", features = ["derive"] } - -[dev-dependencies] -web-sys = "0.3.82" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } @@ -32,7 +25,4 @@ web-time = "1.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ratatui = "0.29.0" -tachyonfx = "0.13.0" -tui-rain = "1.0.1" -tui-big-text = "0.7.1" ansi-to-tui = "7.0.0" diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 8f1990d..b09553c 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT" keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] -beamterm-atlas = "0.8.0" kanash-components = { path = "../kanash-components/" } # ratzilla = "0.2.0" # ratzilla = { path = "../../ratzilla/" } diff --git a/kanash/Cargo.toml b/kanash/Cargo.toml index 554d06f..61ccaf0 100644 --- a/kanash/Cargo.toml +++ b/kanash/Cargo.toml @@ -10,15 +10,12 @@ keywords = ["ratatui", "learning", "japanese", "TUI"] [dependencies] kanash-components = { path = "../kanash-components/" } -anyhow = "1.0.97" rand = "0.9.0" rand_core = "0.9.3" ratatui = "0.29.0" wana_kana = "4.0.0" tachyonfx = "0.20.1" tui-rain = "1.0.1" -tokio = { version = "1.44.2", features = ["full"] } -futures = "0.3.31" tui-big-text = "0.7.1" #ratatui-image = "5.0.0" #image = "0.25.6" From 15c14606b021c0b01b986c3f9fd714adb29c1691 Mon Sep 17 00:00:00 2001 From: benoitlx Date: Fri, 28 Nov 2025 11:49:11 +0100 Subject: [PATCH 18/20] fix: remove pub before kana --- kanash-components/src/helper/ja.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kanash-components/src/helper/ja.rs b/kanash-components/src/helper/ja.rs index eba08c7..77455dd 100644 --- a/kanash-components/src/helper/ja.rs +++ b/kanash-components/src/helper/ja.rs @@ -2,7 +2,7 @@ use rand::{seq::IndexedRandom, Rng}; use rand_pcg::Mcg128Xsl64; const HIRAGANA_NUMBER: usize = 71; -pub const WANTED_KANA: [u16; HIRAGANA_NUMBER] = [ +const WANTED_HIRAGANA: [u16; HIRAGANA_NUMBER] = [ 12354, 12356, 12358, 12360, 12362, 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383, 12384, 12385, 12386, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, @@ -11,7 +11,7 @@ pub const WANTED_KANA: [u16; HIRAGANA_NUMBER] = [ 12427, 12428, 12429, 12431, 12434, 12435, ]; const KATAKANA_NUMBER: usize = 81; -pub const WANTED_KATAKANA: [u16; KATAKANA_NUMBER] = [ +const WANTED_KATAKANA: [u16; KATAKANA_NUMBER] = [ 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, 12482, 12484, 12485, 12486, 12487, 12488, @@ -22,7 +22,7 @@ pub const WANTED_KATAKANA: [u16; KATAKANA_NUMBER] = [ ]; pub fn random_hiragana(rng: &mut Mcg128Xsl64) -> String { - String::from_utf16(&[*WANTED_KANA.choose(rng).unwrap()]).expect("error hiragana") + String::from_utf16(&[*WANTED_HIRAGANA.choose(rng).unwrap()]).expect("error hiragana") } pub fn random_katakana(rng: &mut Mcg128Xsl64) -> String { From dac62676ec286ed12a200b583e2422566856ddec Mon Sep 17 00:00:00 2001 From: benoitlx Date: Tue, 2 Dec 2025 10:58:51 +0100 Subject: [PATCH 19/20] feat: change package description --- kanash-components/Cargo.toml | 7 ++++--- kanash-ratzilla/Cargo.toml | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 980dc3c..57cc486 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -3,10 +3,11 @@ name = "kanash-components" version = "0.1.4" authors = ["Benoit Leroux "] edition = "2021" -description = "Learn Hiragana and Katakana in a terminal !" +description = "Core library for kanash and kanash-ratzilla" repository = "https://github.com/benoitlx/kanash" license = "MIT" keywords = ["ratatui", "learning", "japanese", "TUI"] +publish = false [dependencies] rand = "0.9.0" @@ -19,8 +20,8 @@ rascii_art = "0.4.5" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } # ratzilla = "0.2.0" -# ratzilla = { path = "../../ratzilla/" } -ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } +ratzilla = { path = "../../ratzilla/" } +# ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } web-time = "1.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index b09553c..0604e2d 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -3,16 +3,17 @@ name = "kanash-ratzilla" version = "0.1.0" authors = ["Benoit Leroux "] edition = "2021" -description = "Learn Hiragana and Katakana in a terminal !" +description = "Learn Hiragana and Katakana in a browser with terminal aesthetic!" repository = "https://github.com/benoitlx/kanash" license = "MIT" keywords = ["ratatui", "learning", "japanese", "TUI"] +publish = false [dependencies] kanash-components = { path = "../kanash-components/" } # ratzilla = "0.2.0" -# ratzilla = { path = "../../ratzilla/" } -ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } +ratzilla = { path = "../../ratzilla/" } +# ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } tachyonfx = { version = "0.20.1", default-features = false, features = ["wasm"] } tui-big-text = "0.7.3" wasm-bindgen = "0.2.105" From c58cb7d1b59012830c7663308cd149775200052f Mon Sep 17 00:00:00 2001 From: benoitlx Date: Tue, 2 Dec 2025 13:32:57 +0100 Subject: [PATCH 20/20] revert: load ratzilla from forked git repo --- kanash-components/Cargo.toml | 4 ++-- kanash-ratzilla/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kanash-components/Cargo.toml b/kanash-components/Cargo.toml index 57cc486..e83b342 100644 --- a/kanash-components/Cargo.toml +++ b/kanash-components/Cargo.toml @@ -20,8 +20,8 @@ rascii_art = "0.4.5" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.3", features = ["wasm_js"] } # ratzilla = "0.2.0" -ratzilla = { path = "../../ratzilla/" } -# ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } +# ratzilla = { path = "../../ratzilla/" } +ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } web-time = "1.1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/kanash-ratzilla/Cargo.toml b/kanash-ratzilla/Cargo.toml index 0604e2d..3dc83a1 100644 --- a/kanash-ratzilla/Cargo.toml +++ b/kanash-ratzilla/Cargo.toml @@ -12,8 +12,8 @@ publish = false [dependencies] kanash-components = { path = "../kanash-components/" } # ratzilla = "0.2.0" -ratzilla = { path = "../../ratzilla/" } -# ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } +# ratzilla = { path = "../../ratzilla/" } +ratzilla = { git = "https://github.com/benoitlx/ratzilla.git" } tachyonfx = { version = "0.20.1", default-features = false, features = ["wasm"] } tui-big-text = "0.7.3" wasm-bindgen = "0.2.105"