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

@datatechsolutions/teleprompter

v0.4.0

Published

Drop-in React teleprompter — auto-scroll, mirror, section labels, keyboard control. Zero deps.

Downloads

1,293

Readme


Why I built this

I needed a teleprompter for my YC pitch. Existing options were either $400 desktop apps, ad-walled freemium sites, or browser tools that couldn't mirror text for an autocue rig without paying. So I shipped this in a weekend and used it live.

Open-sourced because every founder doing a demo needs this, and nobody should have to learn FFmpeg to get text scrolling on screen.

npm install @datatechsolutions/teleprompter
import { Teleprompter } from '@datatechsolutions/teleprompter'

const SCRIPT = `// 0–5s · Hook
Hey YC. I'm Natalia, building Astrlabe.

// 5–13s · Credibility
Brazilian. Electrical engineer. Ten years as a data scientist.`

export default function PitchPage() {
  return <Teleprompter initialScript={SCRIPT} targetDuration="01:00" />
}

That's the whole thing. Click anywhere to play, click to pause, edit the script with the pencil button, hit M to mirror the text for behind-glass rigs.

What you get

  • 🎤 Voice-paced auto-scroll — mic listens, WPM is measured, scroll follows your speaking pace in real time. Pure Web Speech API, zero backend
  • 🎬 Manual auto-scroll — 10–300 px/sec, adjustable live (fallback when voice pacing is off or unsupported)
  • 🎨 Section labels// 0–5s · Hook syntax for free
  • 🔄 Mirror mode — for autocue rigs that read off a beam-splitter
  • ⌨️ Keyboard shortcuts — Space, ↑↓, +/-, M, E, R
  • 🌗 Edge fade gradients — text materialises and dissolves cinema-style
  • 📊 Progress bar + elapsed/target timer — pace yourself live
  • 🎯 Configurable accent colour — match your brand in one prop
  • 💾 localStorage persistence — drafts survive reload (opt-out via prop)
  • 📦 ESM + CJS + types — works in any modern React app
  • prefers-reduced-motion aware — respects OS setting automatically
  • 🚫 Zero runtime dependencies — only React as peer
import { useTeleprompter } from '@datatechsolutions/teleprompter'

function MyTeleprompter() {
  const { lines, isPlaying, togglePlay, scrollerRef, fontSize, mirror } =
    useTeleprompter({ initialScript: 'Hello world' })

  return (
    <div ref={scrollerRef} onClick={togglePlay} style={{ overflow: 'auto' }}>
      {lines.map((line, i) => (
        <p key={i} style={{ fontSize, transform: mirror ? 'scaleX(-1)' : undefined }}>
          {line.text}
        </p>
      ))}
    </div>
  )
}

The hook handles requestAnimationFrame, keyboard, localStorage, elapsed timer — you decide how to render.

Enable from the component:

<Teleprompter initialScript={SCRIPT} voicePaced />

…or tune the pacing model:

<Teleprompter
  initialScript={SCRIPT}
  voicePaced={{
    lang: 'pt-BR',
    windowMs: 5000,        // sliding window for WPM averaging
    targetWpm: 150,        // pace that maps to baselineSpeed
    baselineSpeed: 60,     // px/sec at targetWpm
  }}
/>

Mid-talk, the controls show a live 142 WPM readout. Click the mic button (or remove voicePaced prop) to fall back to manual speed.

Browser support: Chromium-based browsers (Chrome, Edge, Brave, Arc) on desktop + Android Chrome. The mic button auto-hides on unsupported browsers — you don't need to gate the prop yourself.

Standalone hook (use without the component):

import { useVoicePaced } from '@datatechsolutions/teleprompter'

const { supported, active, wpm, derivedSpeed, toggle } = useVoicePaced({
  lang: 'en-US',
})

Returns a speed in px/sec that follows the speaker's WPM — wire it into whatever scroll loop you already have.

Tailwind required

This package uses Tailwind utility classes. Add the dist path to your project's tailwind.config.js content array so the classes get generated:

export default {
  content: [
    './src/**/*.{ts,tsx}',
    './node_modules/@datatechsolutions/teleprompter/dist/**/*.{js,mjs,cjs}',
  ],
}

Without that line, the teleprompter renders unstyled. We picked Tailwind because the package is small and Tailwind classes mean zero CSS to ship — your bundle stays lean.

Props

<Teleprompter />

| Prop | Type | Default | Notes | |---------------------|----------------------|----------------------------------------|-------| | initialScript | string | '' | Lines starting with // render as section labels. Blank lines = visual gaps. | | storageKey | string \| null | @datatechsolutions/teleprompter:v1 | Pass null to disable persistence. | | initialSpeed | number | 60 | Scroll speed in px/sec. | | initialFontSize | number | 32 / 44 / 56 | Auto-picks based on viewport width. | | enableKeyboard | boolean | true | Wire Space / ↑↓ / +/- / M / E / R. | | speedRange | { min, max, step } | { 10, 300, 10 } | Bounds for speed bumps. | | fontSizeRange | { min, max, step } | { 20, 120, 4 } | Bounds for font size bumps. | | targetDuration | string \| null | '01:00' | Shown next to elapsed timer. | | voicePaced | boolean \| VoicePacedOptions | false | Enable mic-driven autoscroll. See voice-paced section. | | enableEditing | boolean | true | Show the in-built edit modal. | | controlsAccessory | ReactNode | — | Extra UI in the control bar. | | keyboardHint | string \| null | (default hint string) | Override or hide the hint at the bottom. | | accentColor | string | #8b5cf6 (violet-500) | Accent driving controls, marker, progress bar. | | showProgressBar | boolean | true | Thin accent line at viewport bottom. | | fadeEdges | boolean | true | Soft fade gradients top + bottom. | | reducedMotion | boolean | OS preference | Disable marker pulse + smooth easing. |

useTeleprompter()

Returns:

  • lines — parsed script (comment vs body)
  • scriptText / setScriptText
  • isPlaying / play / pause / togglePlay / reset
  • speed / setSpeed / bumpSpeed
  • fontSize / setFontSize / bumpFontSize
  • mirror / toggleMirror
  • elapsedMs
  • scrollerRef — attach to your scroll container

Script syntax

// Section label — uppercase tracking, smaller font, accent color
Body line one — large body text, what the speaker reads.
Body line two.

// Next section (blank lines above add a gap)
Another section.

That's it. No markdown, no escaping. The // prefix is matched after trimming, so leading whitespace is fine.

Keyboard shortcuts

| Key | Action | |-----------|-----------------------| | Space | Play / pause | | / | Speed +10 / -10 px/s | | + / - | Font size +4 / -4 px | | M | Toggle mirror | | E | Open edit modal | | R | Reset to top |

Shortcuts are disabled while typing in <input> / <textarea>.

Brand it

Match your accent in one prop:

<Teleprompter accentColor="#10b981" />   {/* emerald */}
<Teleprompter accentColor="#f97316" />   {/* orange */}
<Teleprompter accentColor="#06b6d4" />   {/* cyan */}

The colour drives section labels, the centre reader marker, the progress bar, the active mirror button, and the Save & reset gradient — so the whole UI shifts in sync.

FAQ

Does it work without Tailwind? Not yet. v1.0.0 will optionally ship a vanilla CSS sheet — see #4.

Is the AI version free? v0.4.0 will add AI script generation + tone shift via a hosted proxy. Free tier capped. See RFC #14.

Mobile? Works today (responsive control bar, viewport-aware font size). Touch gestures (swipe / pinch) coming in v0.3.0 — #12.

SSR? Yes — parseScript and the hook short-circuit on typeof window === 'undefined', so Next.js / Remix work without 'use client' directives at the import level. The component itself uses useEffect so wrap it in client boundary if your framework demands it.

Development

npm install
npm test           # vitest run — 39 unit tests
npm run build      # tsup → ESM + CJS + types
npm run type-check

End-to-end Playwright tests live in examples/playground/ and run against a real Vite dev server consuming the package via npm link.

Contributing

Issues + PRs welcome. The roadmap is public — every milestone lives as a GitHub EPIC tagged roadmap:

  • v0.3.0 — timing intelligence (in progress; voice-paced ✅, structured sections + touch gestures still open)
  • v0.4.0 Whisper backend — opt-in client-side Whisper for Firefox/Safari support + multi-language accuracy
  • v0.4.0 AI Co-pilot — write & rewrite scripts via LLM

License

MIT — see LICENSE.