npm package: @pkme/widget-bridge
Description: TypeScript React bridge client for Secret City Games widget integration across Framer, Figma, and web platforms
Author: Patrick Keenan
Latest version: 1.0.17

# @pkme/widget-bridge

A TypeScript React bridge client for Secret City Games widget integration across Framer, Figma, and web platforms.

## Installation

**No installation needed for Framer or Figma!** Both platforms auto-resolve npm packages.

For other environments:
```bash
npm install @pkme/widget-bridge
```

## Quick Start

### React Hooks (Framer, React apps)

```typescript
import React from "react"
import { useBridgeData } from "@pkme/widget-bridge"

interface GlobalData {
  playerName?: string
  theme?: 'light' | 'dark'
  totalScore?: number
}

interface CardData {
  progress?: number
  completed?: boolean
}

function MyWidget() {
  const {
    globalData,
    itemData,
    setGlobal,
    setItem,
    navigate,
    complete,
    isReady
  } = useBridgeData<GlobalData, CardData>()

  if (!isReady) {
    return <div>Connecting to Secret City Games...</div>
  }

  return (
    <div>
      <h1>Player: {globalData?.playerName}</h1>
      <p>Progress: {itemData?.progress || 0}%</p>
      <button onClick={() => setItem({ progress: 50 })}>
        Update Progress
      </button>
      <button onClick={() => complete({ score: 100 })}>
        Complete Card
      </button>
    </div>
  )
}
```

### Vanilla JavaScript (Figma plugins, vanilla web)

```typescript
import { bridge } from "@pkme/widget-bridge"

// Wait for bridge to be ready
await bridge.ready()
console.log('Connected to Secret City Games!')

// Set up data subscriptions
bridge.subscribeGlobal((globalData) => {
  console.log('Global data updated:', globalData)
})

bridge.subscribeItem((itemData) => {
  console.log('Item data updated:', itemData)
})

// Update data
await bridge.setGlobal({ playerName: 'Alice' })
await bridge.setItem({ progress: 75 })

// Navigate
await bridge.navigate('/next-card')
await bridge.complete({ score: 100 })
```

## Import Options

### For Framer (Immediate Availability)
Use CDN import for immediate availability in Framer:
```typescript
import { useBridgeData } from "https://unpkg.com/@pkme/widget-bridge@1.0.16/dist/index.esm.js"
import { bridge } from "https://unpkg.com/@pkme/widget-bridge@1.0.16/dist/index.esm.js"
```

### Alternative CDN Imports
```typescript
// jsDelivr CDN (reliable alternative)
import { useBridgeData } from "https://cdn.jsdelivr.net/npm/@pkme/widget-bridge@1.0.16/dist/index.esm.js"

// Standard npm import (works once JSPM indexes - may take 24hrs)
import { useBridgeData, bridge } from "@pkme/widget-bridge"

// JSPM CDN (once indexed)
import { useBridgeData } from "https://jspm.dev/@pkme/widget-bridge@1.0.16"
```

**Note**: Use unpkg or jsDelivr CDNs for immediate availability. These serve the exact files from npm without transformation, avoiding compatibility issues with esm.sh.

## Core Features

- 🔄 **Real-time data sync** between widgets and Secret City Games app
- 🎯 **Global & Item data** - shared vs card-specific state
- 🚀 **Navigation** - seamless routing between game cards
- 🛡️ **Loop prevention** - optimistic updates without recursion
- 📱 **Cross-platform** - Framer, Figma, React Native WebView, iframe
- 🔧 **TypeScript** - full type safety included

## React Hooks

### `useBridgeData<TGlobal, TItem>()`
Complete integration with global and item data plus navigation:

```typescript
const {
  globalData,     // Shared across all cards
  itemData,       // Current card only
  setGlobal,      // Update shared data
  setItem,        // Update current card
  navigate,       // Navigate to other cards
  complete,       // Mark card complete
  back,           // Go back
  isReady,        // Connection status
  context,        // { sessionId, gameId, viewId }
  environment     // 'expo' | 'iframe' | 'standalone'
} = useBridgeData<GlobalData, CardData>()
```

### `useBridge()`
Access bridge instance and status:

```typescript
const { bridge, isReady, context, environment } = useBridge()
```

### `useGlobalData<T>()`
Manage global game state:

```typescript
const [globalData, setGlobalData] = useGlobalData<MyGlobalType>()
```

### `useItemData<T>()`
Manage card-specific data:

```typescript
const [itemData, setItemData] = useItemData<MyItemType>()
```

## Bridge Methods

### Data Operations
```typescript
// Current card data
await bridge.setItem({ progress: 50 })
bridge.subscribeItem((data) => console.log('Item updated:', data))

// Specific card data
await bridge.setItemById('card-123', { completed: true })
bridge.subscribeItemById('card-123', (data) => console.log('Card 123:', data))

// Global data (shared)
await bridge.setGlobal({ playerName: 'Alice' })
bridge.subscribeGlobal((data) => console.log('Global:', data))
```

### Navigation
```typescript
// Navigate to another card
await bridge.navigate('/games/puzzle/cards/level-2', {
  title: 'Level 2',
  difficulty: 'medium'
})

// Go back
await bridge.back()

// Complete current card
await bridge.complete({
  score: 100,
  timeSpent: 120
})
```

## Utility Functions

```typescript
import {
  navigateToNextCard,
  completeCard,
  navigateToCard,
  savePuzzleProgress,
  updateGlobalGameState
} from "@pkme/widget-bridge"

// Navigate to next card with completion
await navigateToNextCard({ completed: true, score: 100 })

// Complete current card
await completeCard({ score: 100, timeSpent: 120 })

// Navigate to specific card
await navigateToCard('level-2', { difficulty: 'medium' })

// Save progress
await savePuzzleProgress(0.75, { hintsUsed: 2 })

// Update global state
await updateGlobalGameState({ currentLevel: 3 })
```

## Static Assets

The package includes game utilities:

```typescript
import { VALID_WORDS, isValidWord } from "@pkme/widget-bridge/assets/games/wordle-words"

// Validate 5-letter words (2,343 valid words)
if (!isValidWord(userGuess)) {
  showError("Not a valid word")
}

// Get random word
const randomWord = VALID_WORDS[Math.floor(Math.random() * VALID_WORDS.length)]
```

## Examples

### Framer Component
See `/examples/framer/PuzzleWidget.tsx` for a complete interactive Framer component.

### Figma Plugin
See `/examples/figma/puzzle-plugin.ts` for a complete Figma plugin example.

## Environment Detection

The bridge automatically detects the runtime environment:

```typescript
console.log('Environment:', bridge.environment)
// 'expo' - React Native WebView (Secret City Games app)
// 'iframe' - Web iframe
// 'standalone' - Development/testing
```

## TypeScript Support

Full type definitions included:

```typescript
import type {
  BridgeInstance,
  BridgeContext,
  BridgeMessage,
  UseBridgeReturn,
  UseBridgeDataReturn
} from "@pkme/widget-bridge"

interface MyGlobalData {
  playerName: string
  theme: 'light' | 'dark'
}

interface MyCardData {
  progress: number
  completed: boolean
}

const {
  globalData,
  itemData
} = useBridgeData<MyGlobalData, MyCardData>()
```

## Browser Bundle

For vanilla HTML/JS:

```html
<script src="https://unpkg.com/@pkme/widget-bridge/dist/browser.js"></script>
<script>
  const { bridge } = window.SecretCityBridge

  bridge.ready().then(() => {
    console.log('Bridge ready!')
    bridge.setGlobal({ test: true })
  })
</script>
```

## Requirements

- React >=16.8.0 (for React hooks)
- Node.js >=14.0.0 (for development)
- TypeScript (optional but recommended)

## License

MIT License

## Repository

[secret-city-go](https://github.com/patrickkeenan/secret-city-go)