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

realtimecursor-sdk-fixed

v1.1.0

Published

Fixed version of RealtimeCursor SDK for real-time collaboration

Readme

RealtimeCursor SDK - Fixed Version (v1.1.0)

A lightweight SDK for adding real-time cursor tracking and collaboration features to your web applications.

Features

  • Real-time cursor tracking
  • Collaborator presence
  • Content synchronization
  • React hooks and components
  • Vanilla JavaScript support

Installation

npm install realtimecursor-sdk-fixed

Usage

React

import React, { useState, useRef, useEffect } from 'react';
import { useRealtimeCursor, CursorOverlay, CollaboratorsList } from 'realtimecursor-sdk-fixed';
import 'realtimecursor-sdk-fixed/dist/cursor.css';

function CollaborativeEditor() {
  const [content, setContent] = useState('');
  const editorRef = useRef(null);
  
  const { 
    cursors, 
    collaborators,
    updateCursor, 
    updateContent,
    connect,
    disconnect
  } = useRealtimeCursor({
    apiUrl: 'http://localhost:3001',
    projectId: 'your-project-id',
    user: {
      id: 'user-123',
      name: 'John Doe',
      color: '#3b82f6' // Optional
    }
  });

  // Connect on mount
  useEffect(() => {
    connect();
    return () => disconnect();
  }, [connect, disconnect]);

  // Update cursor position on mouse move
  const handleMouseMove = (e) => {
    if (!editorRef.current) return;
    
    const rect = editorRef.current.getBoundingClientRect();
    updateCursor({
      x: e.clientX,
      y: e.clientY,
      relativeX: e.clientX - rect.left,
      relativeY: e.clientY - rect.top
    });
  };

  // Update content when changed
  const handleContentChange = (e) => {
    const newContent = e.target.value;
    setContent(newContent);
    updateContent(newContent);
  };

  return (
    <div className="collaborative-editor">
      <h2>Collaborative Editor</h2>
      
      <div className="editor-container" ref={editorRef} onMouseMove={handleMouseMove}>
        <textarea
          value={content}
          onChange={handleContentChange}
          placeholder="Start typing..."
        />
        <CursorOverlay cursors={cursors} />
      </div>
      
      <div className="collaborators-panel">
        <h3>Active Collaborators ({collaborators.length})</h3>
        <CollaboratorsList collaborators={collaborators} />
      </div>
    </div>
  );
}

Vanilla JavaScript

import { RealtimeCursor } from 'realtimecursor-sdk-fixed';
import 'realtimecursor-sdk-fixed/dist/cursor.css';

// Initialize the cursor client
const cursorClient = new RealtimeCursor({
  apiUrl: 'http://localhost:3001',
  projectId: 'your-project-id',
  user: {
    id: 'user-123',
    name: 'John Doe',
    color: '#3b82f6' // Optional
  }
});

// Connect to the real-time service
cursorClient.connect();

// Set up event handlers
cursorClient.onConnect = () => {
  console.log('Connected to real-time service');
};

cursorClient.onDisconnect = () => {
  console.log('Disconnected from real-time service');
};

cursorClient.onCursorsChange = (cursors) => {
  console.log('Cursors updated:', cursors);
  renderCursors(cursors);
};

cursorClient.onCollaboratorsChange = (collaborators) => {
  console.log('Collaborators updated:', collaborators);
  renderCollaborators(collaborators);
};

cursorClient.onContentUpdate = (data) => {
  console.log('Content updated:', data);
  document.getElementById('editor').value = data.content;
};

// Update cursor position on mouse move
document.getElementById('editor-container').addEventListener('mousemove', (e) => {
  const rect = e.currentTarget.getBoundingClientRect();
  cursorClient.updateCursor({
    x: e.clientX,
    y: e.clientY,
    relativeX: e.clientX - rect.left,
    relativeY: e.clientY - rect.top
  });
});

// Update content when changed
document.getElementById('editor').addEventListener('input', (e) => {
  cursorClient.updateContent(e.target.value);
});

// Disconnect when done
window.addEventListener('beforeunload', () => {
  cursorClient.disconnect();
});

// Helper functions to render cursors and collaborators
function renderCursors(cursors) {
  const container = document.getElementById('cursors-container');
  container.innerHTML = '';
  
  Object.values(cursors).forEach(cursor => {
    const cursorElement = document.createElement('div');
    cursorElement.className = 'realtimecursor-cursor';
    cursorElement.style.left = `${cursor.position.x || cursor.position.relativeX || 0}px`;
    cursorElement.style.top = `${cursor.position.y || cursor.position.relativeY || 0}px`;
    
    // Add cursor SVG and label
    cursorElement.innerHTML = `
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" style="transform: rotate(-45deg)">
        <path d="M1 1L11 11V19L7 21V13L1 1Z" fill="${cursor.user.color || '#3b82f6'}" stroke="white" stroke-width="1" />
      </svg>
      <div class="realtimecursor-label" style="background-color: ${cursor.user.color || '#3b82f6'}">
        ${cursor.user.name}
      </div>
    `;
    
    container.appendChild(cursorElement);
  });
}

function renderCollaborators(collaborators) {
  const container = document.getElementById('collaborators-container');
  container.innerHTML = '';
  
  if (collaborators.length === 0) {
    container.innerHTML = '<div class="realtimecursor-no-collaborators">No active collaborators</div>';
    return;
  }
  
  collaborators.forEach(user => {
    const userElement = document.createElement('div');
    userElement.className = 'realtimecursor-collaborator';
    
    userElement.innerHTML = `
      <div class="realtimecursor-collaborator-avatar" style="background-color: ${user.color || '#3b82f6'}">
        ${user.name ? user.name.charAt(0).toUpperCase() : '?'}
      </div>
      <div class="realtimecursor-collaborator-name">
        ${user.name}
      </div>
    `;
    
    container.appendChild(userElement);
  });
}

API Reference

RealtimeCursor Class

const cursorClient = new RealtimeCursor(options);

Options

  • apiUrl (string): URL of the RealtimeCursor API server
  • projectId (string): Unique identifier for the project
  • user (object): User information
    • id (string): Unique identifier for the user
    • name (string): Display name for the user
    • color (string, optional): Color for the user's cursor (hex code)

Methods

  • connect(): Connect to the real-time service
  • disconnect(): Disconnect from the real-time service
  • updateCursor(position): Update cursor position
    • position (object): Cursor position
      • x (number, optional): Absolute X position
      • y (number, optional): Absolute Y position
      • relativeX (number, optional): Relative X position within container
      • relativeY (number, optional): Relative Y position within container
      • textPosition (number, optional): Position in text (for text editors)
  • updateContent(content, version): Update content
    • content (string): New content
    • version (number, optional): Content version

Event Handlers

  • onConnect: Called when connected to the service
  • onDisconnect: Called when disconnected from the service
  • onCursorsChange(cursors): Called when cursors are updated
  • onCollaboratorsChange(collaborators): Called when collaborators list changes
  • onContentUpdate(data): Called when content is updated by another user
  • onUserJoined(user): Called when a user joins
  • onUserLeft(user): Called when a user leaves
  • onError(error): Called when an error occurs

useRealtimeCursor Hook

const { 
  cursors, 
  collaborators,
  connected,
  connect,
  disconnect,
  updateCursor, 
  updateContent
} = useRealtimeCursor(options);

Returns

  • cursors (object): Map of cursor objects by user ID
  • collaborators (array): List of active collaborators
  • connected (boolean): Connection status
  • connect(): Function to connect to the service
  • disconnect(): Function to disconnect from the service
  • updateCursor(position): Function to update cursor position
  • updateContent(content, version): Function to update content

CursorOverlay Component

<CursorOverlay cursors={cursors} containerRef={containerRef} />

Props

  • cursors (object): Map of cursor objects by user ID
  • containerRef (React.RefObject, optional): Reference to the container element

CollaboratorsList Component

<CollaboratorsList collaborators={collaborators} />

Props

  • collaborators (array): List of active collaborators

Backend Server

This SDK requires a backend server for real-time communication. The server is included in the package and can be started with:

cd api
npm install
npm start

License

MIT