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

gymsense-rn

v1.8.0

Published

XLabs GymSense multiplatform SDK

Readme

gymsense-rn

XLabs GymSense multiplatform library.

Installation

npm install gymsense-rn expo-speech

Note: expo-speech is required for native text-to-speech support in the embedded web application.

Usage

Exercise Component

Use the Exercise component to execute exercises with a specific exercise ID and target.

import { View, Platform, StyleSheet } from 'react-native';
import { Exercise } from 'gymsense-rn';
import type { SessionCompletePayload, SetCompletePayload } from 'gymsense-rn';

export default function Index() {
  return (
    <View style={styles.safeArea}>
      <Exercise
        token="your_token_here"
        exerciseId={12}
        target={10}
        sets={3}
        restDuration={45}
        bodyWeight={70}
        theme="light"
        onSetComplete={(result: SetCompletePayload) => {
          console.log("Set Completed");
          console.log("Set Number:", result.setNumber);
          console.log("Count:", result.count);
          console.log("Accuracy:", result.accuracy);
          console.log("Duration:", result.duration);
        }}
        onSessionComplete={(result: SessionCompletePayload) => {
          console.log("Exercise Session Completed");
          console.log("Exercise ID:", result.exerciseId);
          console.log("Exercise Name:", result.exerciseName);
          console.log("Type:", result.type);
          console.log("Total Sets:", result.totalSets);
          console.log("Sets Data:", result.sets);
          console.log("Total Count:", result.count);
          console.log("Average Accuracy:", result.accuracy);
          console.log("Calories Burned:", result.calories);
        }}
        onSessionCanceled={() => {
          console.log("Exercise Session Canceled");
        }}
        debug={false}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: "transparent",
    paddingBottom: Platform.OS === 'android' ? 50 : 0,
  },
});

RecordExercise Component

Use the RecordExercise component to create new exercises.

import { View, Platform, StyleSheet } from 'react-native';
import { RecordExercise } from 'gymsense-rn';
import type { ExerciseCreatedPayload } from 'gymsense-rn';

export default function Index() {
  return (
    <View style={styles.safeArea}>
      <RecordExercise
        token="your_token_here"
        authorId={123}
        authorName="John Doe"
        theme="light"
        onExerciseCreated={(result: ExerciseCreatedPayload) => {
          console.log("Exercise Created");
          console.log("Exercise ID:", result.exerciseId);
          console.log("Exercise Name:", result.exerciseName);
          console.log("Exercise Type:", result.exerciseType);
          console.log("Author ID:", result.authorId);
          console.log("Author Name:", result.authorName);
          console.log("Video URL:", result.videoUrl);
          console.log("Icon URL:", result.iconUrl);
          console.log("Created At:", result.createdAt);
        }}
        debug={false}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: "transparent",
    paddingBottom: Platform.OS === 'android' ? 50 : 0,
  },
});

EditExercise Component

Use the EditExercise component to edit existing exercises.

import { View, Platform, StyleSheet } from 'react-native';
import { EditExercise } from 'gymsense-rn';
import type { ExerciseUpdatedPayload } from 'gymsense-rn';

export default function Index() {
  return (
    <View style={styles.safeArea}>
      <EditExercise
        token="your_token_here"
        exerciseId={123}
        theme="light"
        onExerciseUpdated={(result: ExerciseUpdatedPayload) => {
          console.log("Exercise Updated");
          console.log("Exercise ID:", result.exerciseId);
          console.log("Exercise Name:", result.exerciseName);
          console.log("Exercise Type:", result.exerciseType);
          console.log("Author ID:", result.authorId);
          console.log("Author Name:", result.authorName);
          console.log("Video URL:", result.videoUrl);
          console.log("Icon URL:", result.iconUrl);
          console.log("Updated At:", result.updatedAt);
        }}
        debug={false}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: "transparent",
    paddingBottom: Platform.OS === 'android' ? 50 : 0,
  },
});

Component Props

Exercise

| Prop | Type | Required | Description | | ------------------- | ------------------------------------------ | -------- | ----------------------------------------------------- | | token | string | Yes | Authentication token | | exerciseId | number | Yes | ID of the exercise to execute | | target | number | Yes | Target repetitions or duration per set | | sets | number | No | Number of sets to perform (default: 1) | | restDuration | number | No | Rest duration between sets in seconds (default: 30) | | bodyWeight | number | No | User's body weight in kg (optional) | | theme | 'light' \| 'dark' | No | UI theme (default: 'light') | | onSetComplete | (result: SetCompletePayload) => void | No | Callback when each set completes | | onSessionComplete | (result: SessionCompletePayload) => void | No | Callback when entire session completes | | onSessionCanceled | () => void | No | Callback when session is canceled | | debug | boolean | No | Enable debug mode (default: false) |

RecordExercise

| Prop | Type | Required | Description | | ------------------- | ------------------------------------------ | -------- | ------------------------------------ | | token | string | Yes | Authentication token | | authorId | number | Yes | ID of the exercise author | | authorName | string | Yes | Name of the exercise author | | theme | 'light' \| 'dark' | No | UI theme (default: 'light') | | onExerciseCreated | (result: ExerciseCreatedPayload) => void | No | Callback when exercise is created | | debug | boolean | No | Enable debug mode (default: false) |

EditExercise

| Prop | Type | Required | Description | | ------------------- | ------------------------------------------ | -------- | ------------------------------------ | | token | string | Yes | Authentication token | | exerciseId | number | Yes | ID of the exercise to edit | | theme | 'light' \| 'dark' | No | UI theme (default: 'light') | | onExerciseUpdated | (result: ExerciseUpdatedPayload) => void | No | Callback when exercise is updated | | debug | boolean | No | Enable debug mode (default: false) |

Message Payloads

SetCompletePayload

Triggered when each individual set is completed.

{
  setNumber: number;   // Set number (1-indexed)
  count: number;       // Reps completed or seconds held
  accuracy: number;    // Score (0-100)
  rom?: number;        // Range of Motion (if exerciseType is 'repetition')
  stability?: number;  // Stability score (if exerciseType is 'hold')
  duration: number;    // Duration of the set in seconds
  target: number;      // The target count for this set
}

SessionCompletePayload

Triggered when the entire exercise session is completed (all sets finished).

{
  start: number;                 // Start timestamp (Unix seconds)
  end: number;                   // End timestamp (Unix seconds)
  duration: number;              // Total session duration in seconds
  exerciseId: number;            // ID of the exercise
  exerciseName: string;          // Name of the exercise
  type: "repetition" | "hold";   // Exercise type
  totalSets: number;             // Total number of sets configured
  sets: SetCompletePayload[];    // Array of data for each completed set
  count: number;                 // Total reps/seconds across all sets
  accuracy: number;              // Average accuracy across all sets
  rom?: number;                  // Average ROM (if applicable)
  stability?: number;            // Average Stability (if applicable)
  calories?: number;             // Estimated calories burned during the session (if applicable)
}

ExerciseCreatedPayload

{
  exerciseId: number; // Database ID of the newly created exercise
  exerciseName: string; // Name of the exercise
  exerciseType: 'repetition' | 'hold'; // Exercise type
  authorId: string; // ID of the author/trainer
  authorName: string; // Name of the author/trainer
  videoUrl: string; // URL to the reference video
  iconUrl: string; // URL to the exercise icon
  createdAt: string; // ISO timestamp of creation
}

ExerciseUpdatedPayload

{
  exerciseId: number; // Database ID of the updated exercise
  exerciseName: string; // Name of the exercise
  exerciseType: 'repetition' | 'hold'; // Exercise type
  authorId: string; // ID of the author/trainer
  authorName: string; // Name of the author/trainer
  videoUrl: string; // URL to the reference video
  iconUrl: string; // URL to the exercise icon
  updatedAt: string; // ISO timestamp of update
}

Screenshots

Web

Native

Features

Native Text-to-Speech Bridge

The library includes a native TTS bridge that enables the embedded web application to use text-to-speech on mobile devices. The Web Speech API (SpeechSynthesisUtterance) is automatically polyfilled and routed to the device's native TTS engine via expo-speech.

Benefits:

  • ✅ Works on iOS and Android (where Web Speech API is not supported in WebViews)
  • ✅ No changes required in the web application code
  • ✅ Uses native device voices for better quality
  • ✅ Supports multiple languages and voice customization

For detailed information, see TTS_BRIDGE_GUIDE.md.

License

MIT


Made with create-react-native-library