{"_id":"@emredogan/lumina-chat","name":"@emredogan/lumina-chat","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@emredogan/lumina-chat","version":"0.1.0","description":"Drop-in cinematic AI chat widget for React — neural-core avatar, smooth motion, tool-use rendering, voice-ready. Bring your own /api endpoint.","keywords":["react","chat","ai","ai-sdk","anthropic","claude","chatbot","ui","widget","lumina","neural-core"],"license":"MIT","author":{"name":"Emre Doğan","email":"emre30283@gmail.com"},"homepage":"https://emredogan.com","repository":{"type":"git","url":"git+https://github.com/emredogan-cloud/my-portfolio.git","directory":"packages/lumina-chat"},"bugs":{"url":"https://github.com/emredogan-cloud/my-portfolio/issues"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles.css":"./dist/styles.css"},"sideEffects":["**/*.css"],"scripts":{"build":"tsc -p tsconfig.json && node ../../scripts/lumina-chat/copy-assets.mjs","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0"},"dependencies":{"@ai-sdk/react":"^3.0.0","ai":"^6.0.0","lucide-react":"^1.14.0","motion":"^12.0.0"},"devDependencies":{"@types/react":"^19.0.0","@types/react-dom":"^19.0.0","typescript":"^5.0.0"},"engines":{"node":">=18"},"publishConfig":{"access":"public","provenance":true},"_id":"@emredogan/lumina-chat@0.1.0","gitHead":"e64284015f8ed842c009994cb5e8b61a673df14d","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-4Fcg72Itdz2RbHgj2oRgKI3fJ9k/cPr5fVf4H0NHl4A8dgN1XFEOViiYLeeinh+1m7DZCnj9gZJ5wrShnS/BLw==","shasum":"6946fb5f4b821205af6f2213d3f378c2c1b846a6","tarball":"https://registry.npmjs.org/@emredogan/lumina-chat/-/lumina-chat-0.1.0.tgz","fileCount":28,"unpackedSize":73147,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@emredogan%2flumina-chat@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDwcWEX9FgWpT1nhRZHZU5cN7CKJ8ICKzk6gB3uv5Xg4AiByEKY4wGx3Vt0YpJyLxgtlHmbzy6zy1sui1AKoZZ7KiQ=="}]},"_npmUser":{"name":"emredogan","email":"emre30283@gmail.com"},"directories":{},"maintainers":[{"name":"emredogan","email":"emre30283@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lumina-chat_0.1.0_1778921261154_0.44690977467098025"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T08:47:41.049Z","0.1.0":"2026-05-16T08:47:41.323Z","modified":"2026-05-16T08:47:42.124Z"},"maintainers":[{"name":"emredogan","email":"emre30283@gmail.com"}],"description":"Drop-in cinematic AI chat widget for React — neural-core avatar, smooth motion, tool-use rendering, voice-ready. Bring your own /api endpoint.","homepage":"https://emredogan.com","keywords":["react","chat","ai","ai-sdk","anthropic","claude","chatbot","ui","widget","lumina","neural-core"],"repository":{"type":"git","url":"git+https://github.com/emredogan-cloud/my-portfolio.git","directory":"packages/lumina-chat"},"author":{"name":"Emre Doğan","email":"emre30283@gmail.com"},"bugs":{"url":"https://github.com/emredogan-cloud/my-portfolio/issues"},"license":"MIT","readme":"# `@emredogan/lumina-chat`\n\n> A drop-in cinematic AI chat widget for React. Neural-core avatar, smooth motion, tool-use rendering, voice-ready. **Bring your own `/api/chat` endpoint.**\n\n[![npm](https://img.shields.io/npm/v/@emredogan/lumina-chat.svg?style=flat-square&color=00d2ff)](https://www.npmjs.com/package/@emredogan/lumina-chat)\n[![types](https://img.shields.io/npm/types/@emredogan/lumina-chat.svg?style=flat-square&color=00d2ff)](https://www.npmjs.com/package/@emredogan/lumina-chat)\n[![license](https://img.shields.io/npm/l/@emredogan/lumina-chat.svg?style=flat-square&color=00d2ff)](./LICENSE)\n[![bundle](https://img.shields.io/bundlephobia/minzip/@emredogan/lumina-chat.svg?style=flat-square&color=00d2ff&label=bundle)](https://bundlephobia.com/package/@emredogan/lumina-chat)\n\nLumina is the same chat widget that ships on [emredogan.com](https://emredogan.com), now extracted as a reusable package. It pairs a dormant cyan \"neural core\" trigger with a cinematic chat panel that wakes up, plays a welcome sequence, and feels like a piece of intelligent software — not a customer-support bubble.\n\n---\n\n## Why Lumina\n\nMost chat widgets feel grafted on. Lumina was designed as the centerpiece of a portfolio site, then extracted once the patterns proved stable. What you get:\n\n- **A presence, not a popup.** The trigger pulses gently like dormant infrastructure. The window opens centered on first visit with a 3-line welcome sequence, then pins to the corner once the user closes it.\n- **Designed-in reliability.** The conversation persists across page reload via `sessionStorage`. The input has three independent unlock paths so it can never deadlock during the welcome sequence — even under React Strict Mode's double-render.\n- **Tool-use rendering, out of the box.** When your AI calls a tool, the response stream renders an inline status pill (`searching notes…` → `searching notes ✓`). Configure the labels with one prop.\n- **Bring your own backend.** The package POSTs to whatever endpoint you wire up. AI SDK's `useChat` hook does the heavy lifting under the hood, so any server route that accepts AI SDK messages and returns a streaming response works — Anthropic, OpenAI, Mistral, your own LLM proxy, anything.\n- **Cinematic motion budget.** All animations are compositor-friendly (opacity + transform). No `backdrop-filter`. No per-frame paints. The widget idles at zero GPU cost.\n\n---\n\n## Install\n\n```bash\nnpm install @emredogan/lumina-chat\n```\n\n`react` and `react-dom` (≥18) are peer dependencies. The package itself depends on `motion`, `lucide-react`, `@ai-sdk/react`, and `ai` — these install automatically.\n\nYou also need **Tailwind CSS (v3 or v4)** in the consumer project. The components use Tailwind utility classes for layout and typography. If you're not on Tailwind yet, [install it in 60 seconds](https://tailwindcss.com/docs/installation).\n\n---\n\n## Quick start\n\n```tsx\n// app/layout.tsx (Next.js App Router)\nimport \"@emredogan/lumina-chat/styles.css\";\nimport { LuminaChat } from \"@emredogan/lumina-chat\";\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        {children}\n        <LuminaChat />\n      </body>\n    </html>\n  );\n}\n```\n\nNow wire up the backend. Lumina POSTs AI SDK messages to `/api/chat` by default — the simplest possible Next.js handler that streams Claude responses:\n\n```ts\n// app/api/chat/route.ts\nimport { anthropic } from \"@ai-sdk/anthropic\";\nimport { streamText, convertToModelMessages, type UIMessage } from \"ai\";\n\nexport const maxDuration = 30;\n\nexport async function POST(req: Request) {\n  const { messages }: { messages: UIMessage[] } = await req.json();\n  const result = streamText({\n    model: anthropic(\"claude-haiku-4-5-20251001\"),\n    messages: convertToModelMessages(messages),\n  });\n  return result.toUIMessageStreamResponse();\n}\n```\n\nThat's the minimum mount. Everything else is opt-in.\n\n---\n\n## Customization\n\n```tsx\n<LuminaChat\n  assistantName=\"Aria\"\n  welcomeMessages={[\n    \"Welcome to Acme.\",\n    \"I'm Aria, your shopping assistant.\",\n    \"What are you looking for today?\",\n  ]}\n  placeholder=\"Ask Aria anything...\"\n  position=\"centered-then-bottom-right\"\n  autoOpenDelayMs={2000}\n  dimOverlay={true}\n  theme={{\n    brandColor: \"#ff6b00\",\n    avatarSrc: \"/aria-avatar.png\",\n    glowIntensity: 0.85,\n  }}\n  toolLabels={{\n    searchProducts: \"searching catalog\",\n    checkInventory: \"checking stock\",\n    calculateShipping: \"calculating shipping\",\n  }}\n  transport={{\n    apiEndpoint: \"/api/aria-chat\",\n    bodyExtras: () => ({ locale: \"en-US\", cartId: getCartId() }),\n  }}\n  persistence={{\n    conversationKey: \"aria-conversation-v1\",\n    minimizedKey: \"aria-minimized-v1\",\n  }}\n/>\n```\n\n### Props at a glance\n\n| Prop | Type | Default | What it does |\n|---|---|---|---|\n| `welcomeMessages` | `readonly string[]` | 3-line generic intro | Lines played in sequence on first open. Empty array skips the welcome. |\n| `assistantName` | `string` | `\"Lumina\"` | Display name in the window header. |\n| `placeholder` | `string` | `\"Ask Lumina anything...\"` | Input placeholder once unlocked. |\n| `position` | `\"centered-then-bottom-right\" \\| \"bottom-right\"` | first | Lifecycle mode. `bottom-right` skips the centered first reveal. |\n| `autoOpenDelayMs` | `number` | `1500` | Auto-open delay on first visit. `0` disables auto-open. |\n| `dimOverlay` | `boolean` | `true` | Whether the centered first open dims the page. |\n| `theme.brandColor` | `string` (hex) | `\"#00d2ff\"` | Re-tints avatar glow, trigger pulse, input focus, tool pills. |\n| `theme.avatarSrc` | `string` | _none_ | Avatar PNG/JPG. Falls back to a pure-CSS gradient if missing or 404. |\n| `theme.glowIntensity` | `number` | `1` | Multiplier for the avatar's outer glow. Reduce on busy backgrounds. |\n| `toolLabels` | `Record<string, string>` | `{}` | Map of tool name → human label for inline tool-use pills. |\n| `transport.apiEndpoint` | `string` | `\"/api/chat\"` | The endpoint that streams chat responses. |\n| `transport.bodyExtras` | `() => Record<string, unknown>` | _none_ | Returns extras merged into every chat request body. |\n| `persistence.conversationKey` | `string` | `\"lumina-conversation-v1\"` | sessionStorage key for chat history. Empty string disables. |\n| `persistence.minimizedKey` | `string` | `\"lumina-minimized-v1\"` | sessionStorage key for the \"user closed once\" flag. |\n\n---\n\n## Composition (advanced)\n\nIf you don't want the orchestrator's lifecycle, compose the parts directly:\n\n```tsx\nimport { LuminaWindow, LuminaTrigger } from \"@emredogan/lumina-chat\";\n\nfunction MyChat() {\n  const [isOpen, setIsOpen] = useState(false);\n  return (\n    <>\n      <LuminaTrigger isOpen={isOpen} onClick={() => setIsOpen(true)} />\n      <LuminaWindow\n        isOpen={isOpen}\n        onClose={() => setIsOpen(false)}\n        hasBeenMinimized={true}  // skip the centered first reveal\n        welcomeMessages={[]}     // skip welcome too\n      />\n    </>\n  );\n}\n```\n\nThe `LuminaAvatar` is also exported standalone if you want to use the cyan neural-core circle elsewhere on your site.\n\n---\n\n## Server contract\n\nThe `transport.apiEndpoint` (default `/api/chat`) must accept a POST body shaped like:\n\n```ts\n{\n  messages: UIMessage[];           // AI SDK 6 UIMessage shape\n  ...bodyExtras                    // anything you returned from bodyExtras()\n}\n```\n\n…and return a streaming response that AI SDK's `useChat` hook understands. The simplest implementation is `streamText(...).toUIMessageStreamResponse()` from the `ai` package, as shown in the Quick start above.\n\nFor tool use, register your tools on the server side and pass them to `streamText`:\n\n```ts\nconst result = streamText({\n  model: anthropic(\"claude-haiku-4-5-20251001\"),\n  messages: convertToModelMessages(messages),\n  tools: { searchProducts, checkInventory },\n});\n```\n\nThe chat panel will automatically render an inline pill for each tool call. Map the tool names to human labels via the `toolLabels` prop.\n\n---\n\n## Browser support\n\n- Modern evergreen browsers (Chrome, Edge, Firefox, Safari — last 2 versions).\n- React 18 and React 19.\n- Server-side rendering (Next.js, Remix, Astro islands) is supported — components are `\"use client\"` and degrade gracefully on the server.\n- IE11: not supported. Safari < 14: untested.\n\n---\n\n## Performance notes\n\n- **Idle CPU: zero.** All animations idle to a steady state, at which point `motion/react` stops the requestAnimationFrame loop entirely.\n- **No `backdrop-filter`.** Early prototypes used full-viewport blur on the dim overlay; profiling showed this was the primary cause of jank on lower-end devices. The current dim is a simple opaque layer.\n- **Tree-shakeable.** Per-file ESM emission means bundlers only pull what you import. If you only need `LuminaAvatar`, the trigger and window code never lands in your bundle.\n- **Minified package size: ~10 KB gzipped** (the JS only — `motion`, `lucide-react`, and `ai` are larger and shared with the rest of your app).\n\n---\n\n## Roadmap\n\n- **Voice mode.** Mic-button + streaming TTS already exists in the source portfolio; extracting it cleanly is the v0.2 milestone.\n- **Headless mode.** Expose the `useChat` orchestration as a hook for consumers who want full control over the markup.\n- **Theming via CSS custom properties.** Currently themed via inline RGB; a `--lumina-brand` custom property surface is on the way for static-CSS workflows.\n\n---\n\n## License\n\nMIT © [Emre Doğan](https://emredogan.com)\n","readmeFilename":"README.md","_rev":"1-0573d7e0e84f9da55e5b5c3302465bff"}