Skip to content

Scolavisa/Tick26

Repository files navigation

Tick Tack Timer

A Progressive Web Application for real-time mechanical clock tick detection and counting using advanced audio processing.

License Tests PWA

Live Demo: https://tick.scolavisa.eu

Overview

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.

Key Features

  • 🎯 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

Microphone Input Boost (Phone Compatibility)

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:

  1. Voice-processing constraints – when requesting microphone access, the app asks the browser to disable echoCancellation, noiseSuppression, and autoGainControl. This is a best-effort hint: some browsers or operating systems may ignore it.

  2. Digital Input Boost – a GainNode is inserted in the audio pipeline between the microphone source and the AudioWorklet processor (the graph is now Microphone → 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

Browser Requirements

  • Chrome 66+ (AudioWorklet support)
  • Edge 79+ (AudioWorklet support)
  • Safari 14.1+ (AudioWorklet support)
  • Firefox 76+ (AudioWorklet support)

Quick Start

Prerequisites

  • Node.js 20+
  • Yarn package manager

Installation

# Clone the repository
git clone https://github.com/Scolavisa/Tick26.git
cd Tick26

# Install dependencies
yarn install

# Build WASM module
yarn build:wasm

Development

# Start development server
yarn dev

# Open http://localhost:5173

Testing

# 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

Production Build

# Build WASM and application
yarn build:all

# Verify build integrity
yarn verify:build

# Preview production build
yarn preview

Project Structure

tick-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

Architecture

Audio Processing Pipeline

Microphone → AudioContext → GainNode → AudioWorklet → WASM Detector → Counter → UI
  1. Microphone Input: Captures audio via getUserMedia API (with best-effort voice-processing constraints disabled)
  2. GainNode: Digital pre-amp to compensate for low-level phone microphone signals (default 1× — no effect on desktop)
  3. AudioWorklet: Processes audio in dedicated thread (non-blocking)
  4. WASM Module: High-performance tick detection algorithm
  5. Counter: Maintains tick count and session state
  6. UI: Real-time display with visual feedback

Key Components

  • 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

Debounce Windows (Bounce Suppression)

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.

Development Guide

Adding New Features

  1. Create a spec in .kiro/specs/ following the spec-driven development methodology
  2. Write tests first (unit + property-based tests)
  3. Implement the feature following the existing architecture
  4. Update documentation in docs/

Testing Strategy

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.

Code Style

  • TypeScript strict mode enabled
  • ESLint + Prettier for code formatting
  • Vue 3 Composition API with <script setup>
  • Functional programming patterns preferred

Deployment

The project uses GitHub Actions for automatic deployment to GitHub Pages.

Automatic Deployment

Every push to main branch triggers:

  1. Dependency installation
  2. WASM module build
  3. Test suite execution (344 tests)
  4. Application build
  5. Build verification
  6. Deployment to GitHub Pages

See docs/DEPLOYMENT.md for detailed deployment instructions.

Documentation

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Implement your changes
  5. Ensure all tests pass (yarn test:run)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Testing

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

Performance

  • 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

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Acknowledgments

Support

Project Status

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

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors