npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

use-clock-source

v1.1.1

Published

A centralized timing system for React applications with synchronized animations and timed events

Downloads

7

Readme

use-clock-source

A centralized timing system for React applications that provides synchronized animations and timed events across your entire app.

Features

  • Centralized Clock: Single source of truth for all timing operations
  • High Performance: Uses requestAnimationFrame for smooth 60fps animations
  • Synchronized Events: All components use the same timing reference
  • Global Control: Pause, resume, or stop all animations at once
  • React Context: Easy integration with React's context system
  • TypeScript: Full TypeScript support with comprehensive type definitions
  • Standalone Hook: Use independently or with context provider

Installation

npm install use-clock-source
# or
yarn add use-clock-source
# or
pnpm add use-clock-source

Quick Start

Using Context Provider (Recommended)

Wrap your app with the TimingProvider:

import React from 'react';
import { TimingProvider } from 'use-clock-source';

function App() {
  return (
    <TimingProvider targetFPS={60} useRAF={true} autoStart={true}>
      <YourApp />
    </TimingProvider>
  );
}

Use the timing clock in any component:

import React, { useState, useEffect } from 'react';
import { useTimingClock } from 'use-clock-source';

function AnimatedComponent() {
  const clock = useTimingClock();
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const startTime = clock.now;
    
    const updateProgress = () => {
      const elapsed = clock.now - startTime;
      setProgress(Math.min(elapsed / 2000, 1)); // 2 second animation
    };

    const cleanup = clock.createInterval(updateProgress, 16); // ~60fps
    return cleanup;
  }, [clock]);

  return <div style={{ opacity: progress }}>Animated Content</div>;
}

Using Standalone Hook

For components that need independent timing:

import React from 'react';
import { useTimingClock } from 'use-clock-source';

function MyComponent() {
  const clock = useTimingClock({
    autoStart: true,
    targetFPS: 60,
    useRAF: true
  });

  // Same API as context-based hook
}

API Reference

TimingProvider Props

import { ReactNode } from 'react';

interface TimingProviderProps {
  children: ReactNode;
  targetFPS?: number;        // Default: 60
  useRAF?: boolean;          // Default: true
  autoStart?: boolean;       // Default: true
}

TimingClock Interface

interface TimingClock {
  // Current time in milliseconds since epoch
  now: number;
  
  // Current time in seconds since epoch (for easier calculations)
  time: number;
  
  // Delta time since last frame (for smooth animations)
  deltaTime: number;
  
  // Whether the clock is currently running
  isRunning: boolean;
  
  // Control methods
  start(): void;
  stop(): void;
  pause(): void;
  resume(): void;
  
  // Utility methods
  getElapsedTime(since: number): number;
  schedule(callback: () => void, delay: number): () => void;
  createInterval(callback: () => void, interval: number): () => void;
  createTimeout(callback: () => void, delay: number): () => void;
}

Usage Examples

Basic Animation

import React, { useState, useEffect } from 'react';
import { useTimingClock } from 'use-clock-source';

function FadeInComponent() {
  const clock = useTimingClock();
  const [opacity, setOpacity] = useState(0);

  useEffect(() => {
    const startTime = clock.now;
    
    const animate = () => {
      const elapsed = clock.now - startTime;
      const progress = Math.min(elapsed / 1000, 1); // 1 second fade
      setOpacity(progress);
    };

    return clock.createInterval(animate, 16); // 60fps
  }, [clock]);

  return <div style={{ opacity }}>Fading in...</div>;
}

Synchronized Slideshow

import React, { useState, useEffect } from 'react';
import { useTimingClock } from 'use-clock-source';

function Slideshow() {
  const clock = useTimingClock();
  const [currentSlide, setCurrentSlide] = useState(0);

  useEffect(() => {
    const advanceSlide = () => {
      setCurrentSlide(prev => (prev + 1) % slides.length);
    };

    // All slideshows advance simultaneously
    return clock.createInterval(advanceSlide, 3000);
  }, [clock]);

  return <div>Slide {currentSlide}</div>;
}

Global Animation Control

import React from 'react';
import { useTimingClock } from 'use-clock-source';

function AnimationControls() {
  const clock = useTimingClock();

  return (
    <div>
      <button onClick={clock.pause}>Pause All</button>
      <button onClick={clock.resume}>Resume All</button>
      <button onClick={clock.stop}>Stop All</button>
    </div>
  );
}

Smooth Counter Animation

import React, { useState, useEffect } from 'react';
import { useTimingClock } from 'use-clock-source';

function AnimatedCounter({ target }: { target: number }) {
  const clock = useTimingClock();
  const [current, setCurrent] = useState(0);

  useEffect(() => {
    const startTime = clock.now;
    const startValue = current;
    
    const animate = () => {
      const elapsed = clock.now - startTime;
      const progress = Math.min(elapsed / 2000, 1); // 2 second animation
      
      // Easing function
      const eased = 1 - Math.pow(1 - progress, 3);
      const newValue = startValue + (target - startValue) * eased;
      
      setCurrent(Math.round(newValue));
    };

    return clock.createInterval(animate, 16);
  }, [clock, target]);

  return <div>{current}</div>;
}

Performance Benefits

  1. Single Animation Loop: One centralized loop instead of multiple timers
  2. RequestAnimationFrame: Uses browser's optimized animation timing
  3. Efficient Updates: Only updates when needed
  4. Memory Management: Automatic cleanup of callbacks
  5. Synchronized Timing: All animations use the same time reference

Migration from setInterval/setTimeout

Replace your existing timing code:

import { useEffect } from 'react';
import { useTimingClock } from 'use-clock-source';

// Before
useEffect(() => {
  const interval = setInterval(updateAnimation, 16);
  return () => clearInterval(interval);
}, []);

// After
function MyComponent() {
  const clock = useTimingClock();
  
  useEffect(() => {
    return clock.createInterval(updateAnimation, 16);
  }, [clock]);
}

Requirements

  • React 18.0.0 or higher
  • TypeScript 5.0.0 or higher (for TypeScript projects)

License

MIT

Contributing

Contributions are welcome! This project uses Conventional Commits for automatic versioning and changelog generation.

Commit Message Format

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Types:

  • feat: New features
  • fix: Bug fixes
  • docs: Documentation changes
  • style: Code style changes
  • refactor: Code refactoring
  • perf: Performance improvements
  • test: Test additions/changes
  • chore: Build process or tooling changes

Examples:

git commit -m "feat: add pause/resume functionality"
git commit -m "fix: resolve memory leak in interval cleanup"
git commit -m "docs: update README with new examples"

Automatic Versioning

This project uses semantic-release for automatic versioning:

  • Patch releases (1.0.0 → 1.0.1): Bug fixes (fix: commits)
  • Minor releases (1.0.0 → 1.1.0): New features (feat: commits)
  • Major releases (1.0.0 → 2.0.0): Breaking changes (BREAKING CHANGE: in commit body/footer)

Version numbers, changelogs, and npm releases are automatically generated based on your commit messages.

📦 Publishing Notes

Important: The package is only published to npm when commits contain release-triggering types:

  • feat: - Triggers minor release and npm publish
  • fix: - Triggers patch release and npm publish
  • BREAKING CHANGE: - Triggers major release and npm publish
  • docs:, chore:, style:, refactor:, test: - No release triggered

If your GitHub Actions show successful runs but the package doesn't appear in npm, check that your recent commits include feat: or fix: types. Documentation and maintenance commits alone won't trigger a release.

Development Workflow

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes following the commit message convention
  4. Add tests for new functionality
  5. Run pnpm test to ensure everything passes
  6. Create a pull request

See CONTRIBUTING.md for detailed guidelines.

$$