Try to build WASM on page 4
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
Isaac Mills 2025-07-15 14:47:46 -06:00
parent 09623f73aa
commit 953ea4e6c4
Signed by: fnmain
GPG key ID: B67D7410F33A0F61
21 changed files with 771 additions and 8 deletions

6
thecockpit/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
bin/
pkg/
wasm-pack.log

46
thecockpit/Cargo.toml Normal file
View file

@ -0,0 +1,46 @@
[package]
name = "thecockpit"
version = "0.1.0"
authors = ["Isaac Mills <rooster0055@protonmail.com>"]
edition = "2018"
[profile.dev.package."*"]
opt-level = 3
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
crossterm = ["ratatui/crossterm"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
ratatui = { version = "0.29.0", default-features = false }
[target.'cfg(target_arch = "wasm32")'.dependencies]
ratatui = { version = "0.29.0", default-features = false }
ratzilla = "0.1.0"
wasm-bindgen = "0.2.84"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.34"
[package.metadata.wasm-pack.profile.release]
wasm-opt = ['--enable-bulk-memory-opt', '--enable-mutable-globals', '--enable-nontrapping-float-to-int']
# wasm-opt = false
[profile.dev]
panic = "abort"
[profile.release]
opt-level = 2
lto = true
codegen-units = 1
strip = true
panic = "abort"

84
thecockpit/README.md Normal file
View file

@ -0,0 +1,84 @@
<div align="center">
<h1><code>wasm-pack-template</code></h1>
<strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>
<p>
<a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>
</p>
<h3>
<a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>
<span> | </span>
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
</h3>
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>
## About
[**📚 Read this template tutorial! 📚**][template-docs]
This template is designed for compiling Rust libraries into WebAssembly and
publishing the resulting package to NPM.
Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
templates and usages of `wasm-pack`.
[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
## 🚴 Usage
### 🐑 Use `cargo generate` to Clone this Template
[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
```
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
cd my-project
```
### 🛠️ Build with `wasm-pack build`
```
wasm-pack build
```
### 🔬 Test in Headless Browsers with `wasm-pack test`
```
wasm-pack test --headless --firefox
```
### 🎁 Publish to NPM with `wasm-pack publish`
```
wasm-pack publish
```
## 🔋 Batteries Included
* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
between WebAssembly and JavaScript.
* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
for logging panic messages to the developer console.
* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

8
thecockpit/package.json Normal file
View file

@ -0,0 +1,8 @@
{
"scripts": {
"build": "wasm-pack build --target web --release"
},
"devDependencies": {
"wasm-pack": "^0.13.1"
}
}

205
thecockpit/pnpm-lock.yaml generated Normal file
View file

@ -0,0 +1,205 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
devDependencies:
wasm-pack:
specifier: ^0.13.1
version: 0.13.1
packages:
axios@0.26.1:
resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
binary-install@1.1.0:
resolution: {integrity: sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==}
engines: {node: '>=10'}
brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
follow-redirects@1.15.9:
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
fs-minipass@2.1.0:
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
engines: {node: '>= 8'}
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}
minipass@5.0.0:
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
engines: {node: '>=8'}
minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
engines: {node: '>= 8'}
mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
tar@6.2.1:
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
engines: {node: '>=10'}
wasm-pack@0.13.1:
resolution: {integrity: sha512-P9exD4YkjpDbw68xUhF3MDm/CC/3eTmmthyG5bHJ56kalxOTewOunxTke4SyF8MTXV6jUtNjXggPgrGmMtczGg==}
hasBin: true
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
snapshots:
axios@0.26.1:
dependencies:
follow-redirects: 1.15.9
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {}
binary-install@1.1.0:
dependencies:
axios: 0.26.1
rimraf: 3.0.2
tar: 6.2.1
transitivePeerDependencies:
- debug
brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
chownr@2.0.0: {}
concat-map@0.0.1: {}
follow-redirects@1.15.9: {}
fs-minipass@2.1.0:
dependencies:
minipass: 3.3.6
fs.realpath@1.0.0: {}
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
inflight@1.0.6:
dependencies:
once: 1.4.0
wrappy: 1.0.2
inherits@2.0.4: {}
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
minipass@3.3.6:
dependencies:
yallist: 4.0.0
minipass@5.0.0: {}
minizlib@2.1.2:
dependencies:
minipass: 3.3.6
yallist: 4.0.0
mkdirp@1.0.4: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
path-is-absolute@1.0.1: {}
rimraf@3.0.2:
dependencies:
glob: 7.2.3
tar@6.2.1:
dependencies:
chownr: 2.0.0
fs-minipass: 2.1.0
minipass: 5.0.0
minizlib: 2.1.2
mkdirp: 1.0.4
yallist: 4.0.0
wasm-pack@0.13.1:
dependencies:
binary-install: 1.1.0
transitivePeerDependencies:
- debug
wrappy@1.0.2: {}
yallist@4.0.0: {}

42
thecockpit/src/lib.rs Normal file
View file

@ -0,0 +1,42 @@
#[cfg(not(target_arch = "wasm32"))]
pub mod native;
#[cfg(target_arch = "wasm32")]
pub mod web;
use std::cell::RefCell;
use ratatui::{
layout::Alignment,
style::{Color, Stylize},
widgets::{Block, BorderType, Paragraph},
Frame,
};
#[derive(Default)]
pub struct App {
counter: RefCell<u8>,
}
impl App {
pub fn render(&self, frame: &mut Frame) {
let counter = self.counter.borrow();
let block = Block::bordered()
.title("thecockpit")
.title_alignment(Alignment::Center)
.border_type(BorderType::Rounded);
let text = format!(
"This is a Ratzilla template.\n\
Press left and right to increment and decrement the counter respectively.\n\
Counter: {counter}",
);
let paragraph = Paragraph::new(text)
.block(block)
.fg(Color::White)
.bg(Color::Black)
.centered();
frame.render_widget(paragraph, frame.area());
}
}

23
thecockpit/src/main.rs Normal file
View file

@ -0,0 +1,23 @@
use ratatui::crossterm::event::{self, KeyCode, KeyEvent};
use thecockpit::App;
fn main() {
let mut terminal = ratatui::init();
let app = App::default();
loop {
terminal
.draw(|frame| app.render(frame))
.expect("failed to draw frame");
match event::read().expect("failed to read event") {
event::Event::Key(key) => match key {
KeyEvent {
code: KeyCode::Char('q'),
..
} => break,
key => app.handle_events(key),
},
_ => {}
}
}
ratatui::restore();
}

View file

@ -0,0 +1,14 @@
use ratatui::crossterm::event::{KeyCode, KeyEvent};
use crate::App;
impl App {
pub fn handle_events(&self, key_event: KeyEvent) {
let mut counter = self.counter.borrow_mut();
match key_event.code {
KeyCode::Left => *counter = counter.saturating_sub(1),
KeyCode::Right => *counter = counter.saturating_add(1),
_ => {}
}
}
}

60
thecockpit/src/web/mod.rs Normal file
View file

@ -0,0 +1,60 @@
mod utils;
use std::{cell::RefCell, io, rc::Rc};
use ratatui::{
layout::Alignment,
style::{Color, Stylize},
widgets::{Block, BorderType, Paragraph},
Frame, Terminal,
};
use ratzilla::{
backend::canvas::{CanvasBackend, CanvasBackendOptions},
event::{KeyCode, KeyEvent},
WebRenderer,
};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen]
pub fn cockpit(id: &str) {
utils::set_panic_hook();
start_cockpit(id).unwrap();
}
fn start_cockpit(id: &str) -> io::Result<()> {
let backend =
CanvasBackend::new_with_options(CanvasBackendOptions::new().grid_id("cockpit-canvas"))?;
let terminal = Terminal::new(backend)?;
let state = Rc::new(crate::App::default());
let event_state = Rc::clone(&state);
terminal.on_key_event(move |key_event| {
event_state.handle_events(key_event);
});
let render_state = Rc::clone(&state);
terminal.draw_web(move |frame| {
render_state.render(frame);
});
Ok(())
}
impl crate::App {
fn handle_events(&self, key_event: KeyEvent) {
// log(&format!("{:?}", key_event));
let mut counter = self.counter.borrow_mut();
match key_event.code {
KeyCode::Left => *counter = counter.saturating_sub(1),
KeyCode::Right => *counter = counter.saturating_add(1),
_ => {}
}
}
}

View file

@ -0,0 +1,10 @@
pub fn set_panic_hook() {
// When the `console_error_panic_hook` feature is enabled, we can call the
// `set_panic_hook` function at least once during initialization, and then
// we will get better error messages if our code ever panics.
//
// For more details see
// https://github.com/rustwasm/console_error_panic_hook#readme
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}