diff options
| -rw-r--r-- | .dir-locals.el | 10 | ||||
| -rw-r--r-- | .envrc | 1 | ||||
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Cargo.lock | 166 | ||||
| -rw-r--r-- | Cargo.toml | 18 | ||||
| -rw-r--r-- | LICENSE | 5 | ||||
| -rw-r--r-- | Makefile | 13 | ||||
| -rw-r--r-- | shell.nix | 31 | ||||
| -rw-r--r-- | site/favicon.ico | bin | 0 -> 1258 bytes | |||
| -rw-r--r-- | site/index.html | 25 | ||||
| -rw-r--r-- | site/main.css | 11 | ||||
| -rw-r--r-- | site/main.mjs | 140 | ||||
| -rw-r--r-- | src/lib.rs | 11 |
13 files changed, 433 insertions, 0 deletions
diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..058923b --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,10 @@ +;;; Directory Local Variables -*- no-byte-compile: t -*- +;;; For more information see (info "(emacs) Directory Variables") + +((nil . ((compile-command . "make serve") + ;; https://rust-analyzer.github.io/book/configuration.html + (eglot-workspace-configuration + . (:rust-analyzer ( :typing (:triggerChars ".=()<>")))))) + (js-base-mode . ((js-indent-level . 4) + (js-chain-indent . t) + (js-indent-first-init . dynamic)))) @@ -0,0 +1 @@ +use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce39741 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/site/wasm diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1b38286 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,166 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "polyring" +version = "0.1.0" +dependencies = [ + "console_log", + "log", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c17179b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "polyring" +version = "0.1.0" +edition = "2024" +license-file = "LICENSE" + +[lib] +# cdylib for wasm, rlib for integration tests +crate-type = ["cdylib", "rlib"] + +[dependencies] +console_log = "1.0" +log = "0.4" +wasm-bindgen = "0.2" + +[dependencies.web-sys] +features = ["Document", "Element", "HtmlElement", "Node", "Window"] +version = "0.3" @@ -0,0 +1,5 @@ +this work is granted to the public domain wherever possible. where it +is not possible, this work is licensed under the terms of the GNU +Affero General Public License version 3¹ + +¹ https://www.gnu.org/licenses/agpl-3.0.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5d17ff0 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +BUILDDIR=site +HOST=coleridge:public_html/automathon + +# the --target is currently necessary or firefox will return +# "disallowed mime type" -bjc 7-aug-2025 +build: + wasm-pack build --target web --out-dir $(BUILDDIR)/wasm + +serve: build + (cd $(BUILDDIR) && python -m http.server 8118) + +deploy: build + rsync -avz --delete --exclude='*~' "$(BUILDDIR)"/ "$(HOST)" diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..3d960fa --- /dev/null +++ b/shell.nix @@ -0,0 +1,31 @@ +{ pkgs ? import <nixpkgs> {} }: + +pkgs.mkShellNoCC { + packages = with pkgs; [ + rustc + clang # yes, it's necessary or ‘cc’ can't be found. -bjc 2025-aug-7 + lld # ibid. + cargo + wasm-pack + rust-analyzer + clippy + rustfmt + # the only thing better than needing cargo's infinite dependencies + # is needing npm's as well, just so we can use a bundler built for + # another, wildly different, registry. + nodePackages.npm + + typescript-language-server + vscode-langservers-extracted + + # for http.server + python3 + + # testing scheme wasm stuff + guile + guile-hoot + ]; + + TMPDIR = "/tmp"; # javascript lsp needs it + CARGO_HOME = "/data/bjc/cargo"; +} diff --git a/site/favicon.ico b/site/favicon.ico Binary files differnew file mode 100644 index 0000000..73de524 --- /dev/null +++ b/site/favicon.ico diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..012e301 --- /dev/null +++ b/site/index.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang='en-US'> + <head> + <meta charset='utf-8'> + <title>polyring</title> + <link rel='stylesheet' href='main.css'> + <meta name='viewport' content='width=device-width'> + </head> + + <body> + <h1>polyring</h1> + <p>benchmarking maximal convex polygon finding</p> + + <button>go</button> + <span>fps: <span id='fps'>n/a</span></span> + <br> + <canvas width='500' height='500'></canvas> + + <script src='./main.mjs' type='module'></script> + + <footer> + <address><a href='https://git.spork.org/polyring.git'>src</a></address> + </footer> + </body> +</html> diff --git a/site/main.css b/site/main.css new file mode 100644 index 0000000..f875232 --- /dev/null +++ b/site/main.css @@ -0,0 +1,11 @@ +html { + box-sizing: border-box; +} +*, *::before, *::after { + box-sizing: inherit; +} + +canvas { + border: 1px solid orangered; + background-color: rgb(200 200 200); +} diff --git a/site/main.mjs b/site/main.mjs new file mode 100644 index 0000000..0c81b41 --- /dev/null +++ b/site/main.mjs @@ -0,0 +1,140 @@ +const NUM_POINTS = 5; + +// thanks vihart +const TAU = 2 * Math.PI; + +// no more than 1% of world size per tick. +const MAX_SPEED = 0.01; + +// size of rendered points in proportion to canvas. +const POINT_RADIUS = 0.01; + +class Point { + x = Math.random(); + y = Math.random(); + #heading = Math.random() * TAU; + speed = Math.random() * MAX_SPEED; + color = randColor(); + + #speedX; + get speedX() { + if (this.#speedX === undefined) { + this.#speedX = this.speed * Math.cos(this.heading); + } + return this.#speedX; + } + + #speedY; + get speedY() { + if (this.#speedY === undefined) { + this.#speedY = this.speed * Math.sin(this.heading); + } + return this.#speedY; + } + + get heading() { + return this.#heading; + } + + set heading(val) { + this.#heading = val; + this.#speedX = this.#speedY = undefined; + } +} + +const points = [...Array(NUM_POINTS)].map(_ => new Point()); + +function randColor() { + const [r, g, b] = [...Array(3)].map(_ => Math.random() * 255); + return `rgb(${r} ${g} ${b})` +} + +function renderPoints(ctx, points) { + points.forEach(p => { + ctx.fillStyle = p.color; + ctx.beginPath(); + ctx.arc(p.x, p.y, POINT_RADIUS, 0, TAU); + ctx.fill(); + + ctx.lineWidth = 0.005; + ctx.beginPath(); + ctx.moveTo(p.x, p.y); + ctx.lineTo(p.x + p.speedX * 3, p.y + p.speedY * 3); + ctx.stroke(); + }); +} + +function movePoints(points) { + points.forEach(p => { + p.x += p.speedX; + p.y += p.speedY; + }); +} + +function bouncePoints(points) { + let didBounce = false; + points.forEach(p => { + const x = p.x + p.speedX; + const y = p.y + p.speedY; + + if (x < 0) { + p.heading = Math.PI - p.heading; + didBounce = true; + } else if (x >= 1) { + p.heading = Math.PI - p.heading; + didBounce = true; + } else if (y < 0) { + p.heading = -1 * p.heading; + didBounce = true; + } else if (y >= 1) { + p.heading = -1 * p.heading; + didBounce = true; + } + }); + return didBounce; +} + +async function loaded() { + const canvas = document.querySelector('canvas'); + const ctx = canvas.getContext('2d'); + console.debug('canvas:', canvas, 'ctx', ctx, 'points:', points); + ctx.scale(canvas.width, canvas.height); + + const fps = document.querySelector('#fps'); + + const goButton = document.querySelector('button'); + let paused = true; + goButton.onclick = e => { + paused = !paused; + if (paused) { + e.target.textContent = 'go'; + } else { + e.target.textContent = 'pause'; + self.requestAnimationFrame(render); + } + }; + + let lastTime = document.timeline.currentTime; + function render(t) { + if (t > lastTime) { + fps.textContent = Math.floor(1_000 / (t - lastTime)); + lastTime = t; + } + + ctx.clearRect(0, 0, canvas.width, canvas.height); + renderPoints(ctx, points); + if (bouncePoints(points)) { + //goButton.onclick({ target: goButton }); + } + movePoints(points); + + if (!paused) { + self.requestAnimationFrame(render); + } + } + + //goButton.onclick({ target: goButton }); + render(document.timeline.currentTime); +} + +document.addEventListener('DOMContentLoaded', loaded); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..66bafe7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,11 @@ +use log::{Level, error, info}; +use wasm_bindgen::prelude::*; +use web_sys::js_sys; + +#[wasm_bindgen(start)] +pub fn init() -> Result<(), JsValue> { + console_log::init_with_level(Level::Debug).expect("couldn't init console log"); + info!("wasm init"); + + Ok(()) +} |
