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

@joycostudio/argos

v0.1.7

Published

Client-side telemetry for JOYCO sites

Downloads

1,064

Readme

Argos

npm core + react gzip

Client-side telemetry for JOYCO sites. Drop a component into your layout — GPU capabilities, FPS sampling, and loader timing are tracked automatically.

Features

| Feature | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------- | | GPU detection | Detects WebGL, WebGPU support, and reads GPU renderer/vendor strings on page land. | | FPS sampling | Measures real frame timing via requestAnimationFrame. Reports avg, min, max, p5 FPS and frame drop count. Automatic by default (5s), configurable duration, or fully manual with named samples. | | Loader timing | Manual trackLoaderStart / trackLoaderComplete for measuring loader duration. | | Zero-config React | <Argos /> component — mount once, telemetry fires automatically. | | Duplicate protection | Multiple mounts are detected with a dev-mode warning; only the first instance initializes. | | Background-tab safe | FPS measurement skips frames collected while the tab is hidden. | | SSR-safe | All browser APIs accessed inside useEffect; no window/document on the server. |

Install

pnpm add @joycostudio/argos

Quick start

import { Argos } from '@joycostudio/argos/react'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <Argos token={process.env.NEXT_PUBLIC_ARGOS_TOKEN} />
      </body>
    </html>
  )
}

This fires two events automatically on page load:

  1. page_land — GPU capabilities
  2. fps_sample — frame timing stats after a 5-second measurement window

Configuring FPS sampling

// Custom duration (ms)
<Argos token="..." fps={8000} />

// Disable automatic FPS sampling entirely
<Argos token="..." fps={false} />

Manual FPS sampling

For sites with loaders or heavy initial animations, disable automatic sampling and control when measurement happens:

import { Argos, startFpsSample, stopFpsSample } from '@joycostudio/argos/react'

// In your layout
<Argos token="..." fps={false} />

// After your loader completes
startFpsSample('post-loader')

// Later, or let it auto-stop after 5s (default)
const data = stopFpsSample('post-loader')

You can run multiple named samples concurrently:

startFpsSample('hero-animation')
startFpsSample('scroll-section')

stopFpsSample('hero-animation')
stopFpsSample('scroll-section')

Each sample auto-stops after its max duration (default 5s) if not stopped manually. stopFpsSample sends the telemetry event and returns the FpsSampleData (or null).

Loader timing

For sites with a loading screen, measure the time between loader mount and unmount:

import { trackLoaderStart, trackLoaderComplete } from '@joycostudio/argos/react'
import { useEffect } from 'react'

export function Loader() {
  useEffect(() => {
    trackLoaderStart()
    return () => trackLoaderComplete()
  }, [])

  return <div>Loading…</div>
}

The token is resolved from the <Argos /> component or the NEXT_PUBLIC_ARGOS_TOKEN environment variable — no need to pass it again.


Events

All events are sent as POST to the ingestion endpoint with Bearer token auth.

page_land

Fires immediately on mount.

{
  "event_type": "telemetry",
  "event_name": "page_land",
  "origin": "https://example.com",
  "path": "/",
  "data": {
    "webgl": true,
    "webgpu": false,
    "renderer": "ANGLE (Apple, ANGLE Metal Renderer: Apple M2, ...)",
    "vendor": "Google Inc. (Apple)"
  }
}

fps_sample

Fires when a sample completes (automatically after max duration, or when stopFpsSample is called).

{
  "event_type": "telemetry",
  "event_name": "fps_sample",
  "origin": "https://example.com",
  "path": "/",
  "data": {
    "sample_id": "post-loader",
    "fps_avg": 60,
    "fps_min": 42,
    "fps_max": 60,
    "fps_p5": 48,
    "frame_drop_count": 3,
    "sample_duration_ms": 5002
  }
}

| Field | Description | | -------------------- | ------------------------------------------------------------------------ | | sample_id | Identifier for the sample ("__auto__" for automatic, or custom id). | | fps_avg | Average FPS across the sample window. | | fps_min | Lowest instantaneous FPS recorded. | | fps_max | Highest instantaneous FPS recorded. | | fps_p5 | 5th percentile FPS — worst-case performance excluding outliers. | | frame_drop_count | Number of frames longer than 33.33ms (below 30 FPS threshold). | | sample_duration_ms | Actual measurement duration in milliseconds. |

loader_complete

Fires when trackLoaderComplete() is called.

{
  "event_type": "telemetry",
  "event_name": "loader_complete",
  "origin": "https://example.com",
  "path": "/",
  "data": {
    "loader_ms": 2340
  }
}

Core API

The core module is framework-agnostic — use it without React if needed.

import { detectGpu, startFpsSample, stopFpsSample, sendEvent, trackLoaderStart, trackLoaderComplete } from '@joycostudio/argos'

| Export | Description | | ------------------------------ | ------------------------------------------------------------------------------- | | detectGpu() | Returns { webgl, webgpu, renderer, vendor }. SSR-safe (returns defaults). | | startFpsSample(id?, maxMs?) | Starts collecting frame timings. Default id "default", default max duration 5s. Auto-stops after max duration. | | stopFpsSample(id?) | Stops the sample, sends the event, and returns FpsSampleData \| null. | | sendEvent(token, event) | Fire-and-forget POST to the ingestion endpoint with keepalive: true. | | trackLoaderStart() | Starts the loader timer. | | trackLoaderComplete() | Stops the timer and sends the loader_complete event. | | setToken(token) | Sets the auth token (called automatically by <Argos />). | | getToken() | Reads the stored token or NEXT_PUBLIC_ARGOS_TOKEN env var. |


Package exports

| Import path | Contents | | ---------------------- | ------------------------------------------------------------------------------------------------- | | @joycostudio/argos | Core: detectGpu, startFpsSample, stopFpsSample, sendEvent, trackLoaderStart, trackLoaderComplete, setToken, getToken, and all types. | | @joycostudio/argos/react | React: Argos component, startFpsSample, stopFpsSample, trackLoaderStart, trackLoaderComplete, and types. |