open-index/open-npm huggingface dataset:
npm package: @spotlane/player
Description: A React component for embedding interactive product demos. Render click-through demos with hotspots, tooltips, and screen transitions — no backend required.
Latest version: 0.1.2

# @spotlane/player

A React component for embedding interactive product demos. Render click-through demos with hotspots, tooltips, and screen transitions — no backend required.

## Installation

```bash
npm install @spotlane/player
```

## How it works

1. Build your interactive demo at [spotlane.dev](https://spotlane.dev) — upload screenshots, place hotspots, and link screens together.
2. When ready, click **Export** to download a `.json` demo file.
3. Import that file into your app and pass it to `<DemoPlayer>`.

## Usage

```tsx
import { DemoPlayer } from '@spotlane/player'
import '@spotlane/player/style'

// Import the .json file downloaded from spotlane.dev
import demoFile from './my-demo.json'

export default function App() {
  return (
    <DemoPlayer
      demo={demoFile}
      width="100%"
      onComplete={() => console.log('Demo finished')}
    />
  )
}
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `demo` | `DemoFile` | required | The demo data object |
| `width` | `string \| number` | `'100%'` | Container width |
| `height` | `string \| number` | `'auto'` | Container height |
| `onComplete` | `() => void` | — | Called when the user reaches the end of the demo |
| `className` | `string` | — | Additional CSS class on the root element |
| `style` | `React.CSSProperties` | — | Inline styles on the root element |

## Demo file format (reference)

The `.json` file is generated by [spotlane.dev](https://spotlane.dev) — you don't need to write it by hand. The schema is shown below for reference.

```ts
interface DemoFile {
  version: '1.0';
  meta: {
    title: string;
    description: string;
    createdAt: number; // Unix ms
    updatedAt: number; // Unix ms
  };
  startScreenId: string;
  screens: Screen[];
}

interface Screen {
  id: string;
  title: string;
  image: string;                  // base64 data URL
  hotspots: Hotspot[];
  description?: string;           // Markdown supported
  descriptionPosition?: 'top' | 'bottom' | 'left' | 'right'; // default: 'bottom'
  descriptionClassName?: string;
}

interface Hotspot {
  id: string;
  x: number;             // 0–1 fraction of image width
  y: number;             // 0–1 fraction of image height
  label: string;
  description: string;
  targetScreenId: string | null; // null = end of demo
  color?: string;                // default: '#7c6af7'
  width?: number;                // 0–1 fraction of image width, default: 0.022
  height?: number;               // 0–1 fraction of image height, default: 0.022
  shape?: 'circle' | 'rect';    // default: 'circle'
  rippleScale?: number;          // ripple animation max scale, default: 2.6
}
```

## Peer dependencies

- `react >= 17`
- `react-dom >= 17`