A Progressive Web Application for real-time mechanical clock tick detection and counting using advanced audio processing.
Live Demo: https://tick.scolavisa.eu
Tick Tack Timer is a PWA that listens to mechanical clock ticks using your device's microphone and counts them in real-time. It uses high-performance audio processing through AudioWorklet and WebAssembly to detect ticks with minimal latency.
- 🎯 Real-time tick detection with <100ms latency
- 🎤 Microphone selection (internal or external USB-C)
- ⚙️ Calibration system for different clock sizes (small/medium/large)
- 📊 Session management with duration tracking
- 💾 Offline support via Service Worker
- 📱 PWA installable on mobile and desktop
- 🎨 Responsive design (320px-768px)
- ⚡ High-performance WASM-based audio processing
Mobile phones often deliver a much quieter microphone signal to web applications than desktop computers do. The main reasons are:
- The browser may limit microphone gain to protect call quality.
- Built-in AGC / noise suppression / echo cancellation (applied by the OS or browser) can significantly reduce the raw signal level visible to the Web Audio API.
Tick Tack Timer addresses this in two ways:
-
Voice-processing constraints – when requesting microphone access, the app asks the browser to disable
echoCancellation,noiseSuppression, andautoGainControl. This is a best-effort hint: some browsers or operating systems may ignore it. -
Digital Input Boost – a
GainNodeis inserted in the audio pipeline between the microphone source and the AudioWorklet processor (the graph is nowMicrophone → GainNode → AudioWorklet). By default the gain is 1× (unity) so desktop behaviour is completely unchanged. On the Calibration page you can manually raise the boost (2×, 4×, 8×, 16×, 32×), and the auto-calibration logic will automatically double the gain (up to 16×) each time it detects an extremely low signal level with no ticks detected.
Note: very high gain values amplify background noise as well as the clock signal. If the calibration succeeds at a high boost level, consider moving the microphone closer to the clock for a cleaner signal.
- Frontend: Vue 3 with Composition API
- Language: TypeScript (strict mode)
- Build Tool: Vite
- Router: Vue Router 4
- Testing: Vitest + fast-check (property-based testing)
- Audio Processing: AudioWorklet + WebAssembly (AssemblyScript)
- PWA: Service Worker + Web App Manifest
- Package Manager: Yarn
- Chrome 66+ (AudioWorklet support)
- Edge 79+ (AudioWorklet support)
- Safari 14.1+ (AudioWorklet support)
- Firefox 76+ (AudioWorklet support)
- Node.js 20+
- Yarn package manager
# Clone the repository
git clone https://github.com/Scolavisa/Tick26.git
cd Tick26
# Install dependencies
yarn install
# Build WASM module
yarn build:wasm# Start development server
yarn dev
# Open http://localhost:5173# Run all tests (344 tests)
yarn test:run
# Run tests in watch mode
yarn test
# Run tests with UI
yarn test:ui
# Generate coverage report
yarn coverage# Build WASM and application
yarn build:all
# Verify build integrity
yarn verify:build
# Preview production build
yarn previewtick-tack-timer/
├── src/
│ ├── audio/ # Audio processing system
│ │ ├── AudioManager.ts # Audio system coordinator
│ │ └── tick-detector-math.ts
│ ├── components/ # Vue components
│ │ └── ErrorDisplay.vue
│ ├── composables/ # Vue composables
│ │ ├── useAudio.ts # Microphone & audio management
│ │ ├── useCalibration.ts # Calibration logic
│ │ ├── useCounter.ts # Tick counting
│ │ └── useSession.ts # Session management
│ ├── pages/ # Page components
│ │ ├── SettingsPage.vue
│ │ ├── CalibrationPage.vue
│ │ └── MeasurementPage.vue
│ ├── router/ # Vue Router configuration
│ ├── styles/ # Global styles
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ ├── App.vue # Root component
│ └── main.ts # Application entry point
├── assembly/ # AssemblyScript/WASM
│ └── tick-detector.ts # High-performance tick detection
├── public/ # Static assets
│ ├── tick-processor.worklet.js # AudioWorklet processor
│ ├── manifest.json # PWA manifest
│ ├── sw.js # Service worker
│ └── icons/ # PWA icons
├── tests/ # Test suites
│ ├── unit/ # Unit tests
│ └── property/ # Property-based tests
├── docs/ # Documentation
└── .github/workflows/ # CI/CD workflows
Microphone → AudioContext → GainNode → AudioWorklet → WASM Detector → Counter → UI
- Microphone Input: Captures audio via getUserMedia API (with best-effort voice-processing constraints disabled)
- GainNode: Digital pre-amp to compensate for low-level phone microphone signals (default 1× — no effect on desktop)
- AudioWorklet: Processes audio in dedicated thread (non-blocking)
- WASM Module: High-performance tick detection algorithm
- Counter: Maintains tick count and session state
- UI: Real-time display with visual feedback
- AudioManager: Coordinates audio system initialization and communication; manages the GainNode digital pre-amp
- TickProcessorWorklet: Real-time audio processing in AudioWorklet thread
- Tick Detector (WASM): High-performance RMS calculation and threshold detection
- Composables: Reactive state management for audio, calibration, counting, and sessions
After each detected tick the AudioWorklet ignores further detections for a short window to prevent mechanical bounce and acoustic ringing of the clock mechanism from being counted as separate ticks. The window is sized per clock type so it is always long enough to suppress bounce but still well below the shortest possible inter-tick gap:
| Clock size | Expected frequency | Min. inter-tick gap | Debounce window |
|---|---|---|---|
| Small | ~5.5 Hz | ~182 ms | 120 ms |
| Medium | ~2.5 Hz | ~400 ms | 150 ms |
| Large | ~0.75 Hz | ~1333 ms | 250 ms |
The values are defined in src/constants.ts (DEBOUNCE_WINDOW_MS) and can be tuned there if
real-world testing reveals that a particular clock type still produces bounce.
- Create a spec in
.kiro/specs/following the spec-driven development methodology - Write tests first (unit + property-based tests)
- Implement the feature following the existing architecture
- Update documentation in
docs/
The project uses a dual testing approach:
- Unit Tests: Specific scenarios with known inputs/outputs
- Property-Based Tests: 100+ iterations with random inputs to validate universal properties
See docs/CONTRIBUTING.md for detailed testing guidelines.
- TypeScript strict mode enabled
- ESLint + Prettier for code formatting
- Vue 3 Composition API with
<script setup> - Functional programming patterns preferred
The project uses GitHub Actions for automatic deployment to GitHub Pages.
Every push to main branch triggers:
- Dependency installation
- WASM module build
- Test suite execution (344 tests)
- Application build
- Build verification
- Deployment to GitHub Pages
See docs/DEPLOYMENT.md for detailed deployment instructions.
- DEPLOYMENT.md - Deployment guide and troubleshooting
- CONTRIBUTING.md - Contribution guidelines
- ARCHITECTURE.md - Detailed architecture documentation
- TESTING.md - Testing strategy and guidelines
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Implement your changes
- Ensure all tests pass (
yarn test:run) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
The project has comprehensive test coverage:
- 344 tests across 23 test files
- Unit tests for all components, composables, and audio system
- Property-based tests for correctness properties
- 100% passing test suite
Run tests with:
yarn test:run- Bundle Size: 756 KB total
- Vue Vendor Bundle: 87.19 KB (gzipped: 34.00 KB)
- WASM Module: 453 bytes
- Audio Processing Latency: <100ms
- Test Suite Duration: ~9 seconds
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Built with Vue 3
- Audio processing powered by Web Audio API
- WASM compiled from AssemblyScript
- Property-based testing with fast-check
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Live Demo: https://tick.scolavisa.eu
✅ Production Ready - All features implemented and tested
- 344/344 tests passing
- Production build verified
- Deployed to GitHub Pages
- PWA installable on mobile and desktop
Made with ❤️ for mechanical clock enthusiasts