| Crates.io | emom |
| lib.rs | emom |
| version | 1.1.7 |
| created_at | 2025-11-20 02:41:01.203351+00 |
| updated_at | 2026-01-08 00:39:59.652286+00 |
| description | A customizable EMOM (Every Minute On the Minute) timer for workouts, with a drift-correcting countdown timer library for WebAssembly applications |
| homepage | https://github.com/jac18281828/emomtimer |
| repository | https://github.com/jac18281828/emomtimer |
| max_upload_size | |
| id | 1941075 |
| size | 153,081 |
A high-performance EMOM (Every Minute On the Minute) workout timer with liquid glass aesthetics, built entirely in Rust and WebAssembly.
Traditional JavaScript timers (setInterval, setTimeout) suffer from significant drift, especially in:
The emom countdown timer solves these problems by:
Timeout calls for flexibilityResult: Accurate timing that stays precise over minutes or hours, even under adverse conditions.
Visit the live deployment: http://emom-timer-us-east-2-504242000181.s3-website.us-east-2.amazonaws.com
The easiest way to run locally is using the provided dev container:
Reopen in Containertrunk build --releasetrunk serve --address=0.0.0.0 --releasehttp://localhost:8080Add to your Cargo.toml:
[dependencies]
emom = { git = "https://github.com/jac18281828/emomtimer" }
use emom::countdown_timer::{CountdownTimer, TimerConfig};
let config = TimerConfig::default(); // 100ms ticks
let timer = CountdownTimer::new(config, |ticks| {
println!("Elapsed: {} tenths of a second", ticks);
});
timer.start();
// ... later ...
timer.stop();
use emom::countdown_timer::{CountdownTimer, TimerConfig};
use std::cell::RefCell;
use std::rc::Rc;
let remaining = Rc::new(RefCell::new(600)); // 60 seconds in tenths
let remaining_clone = Rc::clone(&remaining);
let timer = CountdownTimer::new(TimerConfig::default(), move |_ticks| {
let mut rem = remaining_clone.borrow_mut();
if *rem > 0 {
*rem -= 1;
println!("Remaining: {}.{} seconds", *rem / 10, *rem % 10);
}
});
timer.start();
use yew::prelude::*;
use emom::countdown_timer::{CountdownTimer, TimerConfig};
use std::rc::Rc;
#[function_component]
fn TimerComponent() -> Html {
let ticks = use_state(|| 0);
let timer = use_memo(|_| {
let ticks = ticks.clone();
CountdownTimer::new(TimerConfig::default(), move |t| {
ticks.set(t);
})
}, ());
let start = {
let timer = Rc::clone(&timer);
Callback::from(move |_| timer.start())
};
let stop = {
let timer = Rc::clone(&timer);
Callback::from(move |_| timer.stop())
};
html! {
<div>
<p>{ format!("Ticks: {}", *ticks) }</p>
<button onclick={start}>{"Start"}</button>
<button onclick={stop}>{"Stop"}</button>
</div>
}
}
Customize the timer behavior:
use emom::countdown_timer::TimerConfig;
let config = TimerConfig {
interval_ms: 100, // Tick every 100ms
sync_interval_ticks: 10, // Sync with wall clock every 10 ticks (1 second)
sync_threshold_ticks: 1, // Correct if drift exceeds 1 tick (100ms)
};
Configuration Guidelines:
interval_ms: Tick interval in milliseconds. Use 100 for tenths of seconds, 1000 for full secondssync_interval_ticks: How often to check for drift. Every 10 ticks (1 second) is recommendedsync_threshold_ticks: Minimum drift before correction. Set to 1 to prevent micro-correctionsSee LIBRARY_USAGE.md for detailed examples and advanced usage patterns.
Built with modern Rust tooling and frameworks:
Yew is a modern Rust framework comparable to React or Vue.js, but with unique advantages:
Perfect for: Applications where performance, reliability, and type safety are critical.
# Development build
trunk build
# Release build with optimizations
trunk build --release
# Run all tests
cargo test
# Run with coverage
cargo test --all-features
# Lint and format
cargo fmt --check
cargo clippy --all-features --no-deps -- -D warnings
emomtimer/
├── src/
│ ├── lib.rs # Library exports and countdown timer
│ ├── main.rs # Yew application and UI
│ └── countdown_timer.rs # Drift-correcting timer implementation
├── style.css # Liquid glass UI styling
├── index.html # Application shell
├── Cargo.toml # Dependencies and package metadata
└── README.md # This file
Contributions are welcome! Please:
cargo test and cargo clippy passThis project is open source. See the repository for license details.
Built with ❤️ using Rust and WebAssembly. Special thanks to the Yew and Rust communities for excellent tooling and documentation.