### Install, Start, Build, Lint, and Generate Icons (Bash)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This snippet provides essential bash commands for managing the project. It includes commands for installing dependencies with pnpm, starting the development server, building for production, running the linter, and generating application icons. These commands facilitate the development lifecycle of the LAPLACE Chat Overlay.
```bash
# Install dependencies
pnpm install
# Start development server
pnpm start
# Build for production (creates packages in out/ directory)
pnpm make
# Run linter
pnpm lint
# Generate application icons
pnpm generate-icons
```
--------------------------------
### Verify macOS Code Signing Identity
Source: https://github.com/laplace-live/chat-overlay/blob/master/docs/macos-notarization-setup.md
This command verifies that your code signing identity is correctly set up and accessible in your macOS Keychain. It lists all identities available for code signing, allowing you to confirm the exact name required for configuration, such as in GitHub repository secrets.
```bash
security find-identity -v -p codesigning
```
--------------------------------
### Run Development Mode with pnpm
Source: https://github.com/laplace-live/chat-overlay/blob/master/README.md
Starts the LAPLACE Chat Overlay application in development mode using the pnpm package manager. This command is essential for developers to test changes and debug the application.
```bash
pnpm start
```
--------------------------------
### Verify Application Code Signature
Source: https://github.com/laplace-live/chat-overlay/blob/master/docs/macos-notarization-setup.md
This command checks the code signature of a macOS application. It's crucial for verifying that your application has been correctly signed, which is a prerequisite for notarization and for the auto-update mechanism to function properly on macOS. The verbose output provides detailed information about the signature.
```bash
codesign -dv --verbose=4 /path/to/app
```
--------------------------------
### Export macOS Developer ID Certificate to PKCS12
Source: https://github.com/laplace-live/chat-overlay/blob/master/docs/macos-notarization-setup.md
This script exports your macOS Developer ID certificate from the Keychain to a PKCS12 file. This file is then converted to a base64 encoded string, which is necessary for storing as a secret in CI/CD platforms like GitHub Actions. Ensure you replace 'YOUR_PASSWORD' with a strong password and delete the .p12 file after successful conversion for security.
```bash
security export -t identities -f pkcs12 -k ~/Library/Keychains/login.keychain-db \
-P YOUR_PASSWORD -o ~/Desktop/Certificates.p12
base64 -i ~/Desktop/Certificates.p12 | pbcopy
rm ~/Desktop/Certificates.p12
```
--------------------------------
### Setup Custom Context Menu for Editable Elements (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This utility function sets up a global event listener for the 'contextmenu' event to display a custom context menu. It identifies if the target element is an input or textarea, captures selected text and input type, and then invokes Electron's `showContextMenu` API. Dependencies include the `electronAPI` exposed in the preload script. The function should be called once during application initialization in the renderer process.
```typescript
// utils/context-menu.ts
export function setupContextMenu() {
document.addEventListener('contextmenu', e => {
e.preventDefault()
const target = e.target
if (!(target instanceof Element)) return
const isEditable = target.tagName === 'INPUT' || target.tagName === 'TEXTAREA'
if (!isEditable && !window.getSelection()?.toString()) {
return // Don't show menu if not on editable element and no text selected
}
let selectionText = ''
let inputType = ''
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
selectionText = target.value.substring(
target.selectionStart || 0,
target.selectionEnd || 0
)
inputType = target instanceof HTMLInputElement ? target.type : 'textarea'
} else {
selectionText = window.getSelection()?.toString() || ''
}
window.electronAPI.showContextMenu({
selectionText,
isEditable,
inputType,
})
})
}
// Initialize in renderer.tsx
setupContextMenu()
```
--------------------------------
### Create Production Build with pnpm
Source: https://github.com/laplace-live/chat-overlay/blob/master/README.md
Packages the LAPLACE Chat Overlay application for distribution on the target platform. This command generates the final build files, typically found in the 'out' directory, ready for deployment.
```bash
pnpm make
```
--------------------------------
### Git Workflow for Contributions
Source: https://github.com/laplace-live/chat-overlay/blob/master/README.md
A standard Git workflow for contributing to the LAPLACE Chat Overlay project. It outlines the steps for forking the repository, creating a feature branch, committing changes, and submitting a pull request.
```git
git checkout -b feature/amazing-feature
git commit -m 'Add some amazing feature'
git push origin feature/amazing-feature
```
--------------------------------
### Electron Main Process IPC Handlers for Window Control and Communication
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This code sets up various Inter-Process Communication (IPC) handlers in the Electron main process. It manages window opacity, always-on-top status, click-through mode, mouse event forwarding, retrieves the app version, synchronizes custom CSS changes between windows, and broadcasts connection states. It also includes logic for displaying a context menu based on the editability of the target element.
```typescript
// Main process (main.ts)
import { ipcMain, BrowserWindow } from 'electron'
const registerIpcHandlers = () => {
// Opacity control
ipcMain.on('set-window-opacity', (_event, opacity) => {
mainWindow.setOpacity(opacity)
})
// Always on top toggle
ipcMain.on('set-always-on-top', (_event, enabled) => {
mainWindow.setAlwaysOnTop(enabled)
})
// Click-through mode
ipcMain.on('set-click-through', (_event, enabled) => {
if (enabled) {
mainWindow.webContents.send('click-through-enabled', true)
} else {
mainWindow.setIgnoreMouseEvents(false)
mainWindow.webContents.send('click-through-enabled', false)
}
})
// Mouse events control
ipcMain.on('set-ignore-mouse-events', (_event, ignore) => {
mainWindow.setIgnoreMouseEvents(ignore, { forward: true })
})
// Get app version
ipcMain.handle('get-app-version', () => {
return app.getVersion()
})
// CSS synchronization between windows
ipcMain.on('update-custom-css', (_event, css) => {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('custom-css-updated', css)
}
})
// Connection state broadcasting
ipcMain.on('broadcast-connection-state', (_event, state) => {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('connection-state-updated', state)
}
if (preferencesWindow && !preferencesWindow.isDestroyed()) {
preferencesWindow.webContents.send('connection-state-updated', state)
}
})
ipcMain.handle('request-connection-state', () => {
return currentConnectionState
})
// Context menu
ipcMain.on('show-context-menu', (_event, { isEditable, selectionText }) => {
const template = []
const hasSelection = selectionText && selectionText.length > 0
if (isEditable) {
template.push(
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut', enabled: hasSelection },
{ role: 'copy', enabled: hasSelection },
{ role: 'paste' },
{ type: 'separator' },
{ role: 'selectAll' }
)
} else {
template.push({ role: 'copy', enabled: hasSelection })
}
const menu = Menu.buildFromTemplate(template)
menu.popup()
})
}
// Register handlers on app ready
app.whenReady().then(() => {
registerIpcHandlers()
createWindow()
})
```
--------------------------------
### Manage Persistent Settings with Settings Store (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This snippet demonstrates a persistent settings store using Zustand with localStorage synchronization. It allows managing UI and server settings, persisting them across sessions and synchronizing them across multiple browser windows. Settings include opacity, font size, window behavior, event visibility, custom CSS, server connection details, and origin filtering.
```typescript
import { useSettingsStore } from './store/useSettingsStore'
// In a React component
function PreferencesPanel() {
const {
// UI Settings
opacity, setOpacity,
baseFontSize, setBaseFontSize,
alwaysOnTop, setAlwaysOnTop,
clickThrough, setClickThrough,
showInteractionEvents, setShowInteractionEvents,
showGiftFree, setShowGiftFree,
showEntryEffect, setShowEntryEffect,
customCSS, setCustomCSS,
// Server Settings
serverHost, setServerHost,
serverPort, setServerPort,
serverPassword, setServerPassword,
allowedOrigins, setAllowedOrigins,
} = useSettingsStore()
return (
)
}
// Settings are automatically persisted to localStorage key 'overlay-settings'
// Storage events sync settings across multiple windows
```
--------------------------------
### Expose Electron IPC Methods with contextBridge (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This preload script snippet demonstrates how to securely expose Electron IPC methods to the renderer process using `contextBridge`. It allows the renderer to send messages, invoke actions, and subscribe to events from the main process. Dependencies include 'electron'. It handles window manipulation, application version, platform detection, CSS updates, preferences management, and connection state broadcasting/requesting. Limitations may include the specific IPC channels exposed.
```typescript
// Preload script (preload.ts)
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
setWindowOpacity: (opacity: number) =>
ipcRenderer.send('set-window-opacity', opacity),
setAlwaysOnTop: (enabled: boolean) =>
ipcRenderer.send('set-always-on-top', enabled),
setClickThrough: (enabled: boolean) =>
ipcRenderer.send('set-click-through', enabled),
setIgnoreMouseEvents: (ignore: boolean) =>
ipcRenderer.send('set-ignore-mouse-events', ignore),
onClickThroughEnabled: (callback: (enabled: boolean) => void) => {
const handler = (_event: Electron.IpcRendererEvent, enabled: boolean)
callback(enabled)
ipcRenderer.on('click-through-enabled', handler)
return () => ipcRenderer.removeListener('click-through-enabled', handler)
},
getAppVersion: () =>
ipcRenderer.invoke('get-app-version'),
getPlatform: () =>
process.platform,
onCustomCSSUpdated: (callback: (css: string) => void) => {
const handler = (_event: Electron.IpcRendererEvent, css: string)
callback(css)
ipcRenderer.on('custom-css-updated', handler)
return () => ipcRenderer.removeListener('custom-css-updated', handler)
},
updateCustomCSS: (css: string)
ipcRenderer.send('update-custom-css', css),
openPreferences: () =>
ipcRenderer.send('open-preferences'),
closePreferences: () =>
ipcRenderer.send('close-preferences'),
broadcastConnectionState: (state: string) =>
ipcRenderer.send('broadcast-connection-state', state),
requestConnectionState: () =>
ipcRenderer.invoke('request-connection-state'),
onConnectionStateUpdate: (callback: (state: string) => void) => {
const handler = (_event: Electron.IpcRendererEvent, state: string)
callback(state)
ipcRenderer.on('connection-state-updated', handler)
return () => ipcRenderer.removeListener('connection-state-updated', handler)
},
showContextMenu: (params: {
selectionText: string
isEditable: boolean
inputType: string
}) => {
ipcRenderer.send('show-context-menu', params)
},
})
// Usage in renderer
declare global {
interface Window {
electronAPI: {
setWindowOpacity: (opacity: number) => void
setAlwaysOnTop: (enabled: boolean) => void
setClickThrough: (enabled: boolean) => void
setIgnoreMouseEvents: (ignore: boolean) => void
onClickThroughEnabled: (callback: (enabled: boolean) => void) => () => void
getAppVersion: () => Promise
getPlatform: () => string
onCustomCSSUpdated: (callback: (css: string) => void) => () => void
updateCustomCSS: (css: string) => void
openPreferences: () => void
closePreferences: () => void
broadcastConnectionState: (state: ConnectionState) => void
requestConnectionState: () => Promise
onConnectionStateUpdate: (callback: (state: ConnectionState) => void) => () => void
showContextMenu: (params: {
selectionText: string
isEditable: boolean
inputType: string
}) => void
}
}
}
```
--------------------------------
### Integrate Monaco Editor for Custom CSS with Live Preview
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This snippet demonstrates integrating the Monaco Editor to allow users to write and edit custom CSS. It utilizes a store for managing CSS state and a hook for debouncing input to optimize updates. The edited CSS is then applied dynamically to the document's head and also sent to the Electron main process for potential further handling.
```typescript
import { MonacoEditor } from './components/ui/monaco-editor'
import { useSettingsStore } from './store/useSettingsStore'
import { useDebouncedValue } from './hooks/useDebouncedValue'
function CustomCssTab() {
const { customCSS, setCustomCSS } = useSettingsStore()
const [localCSS, setLocalCSS] = useState(customCSS)
const debouncedCSS = useDebouncedValue(localCSS, 500)
// Save debounced changes
useEffect(() => {
setCustomCSS(debouncedCSS)
window.electronAPI.updateCustomCSS(debouncedCSS)
}, [debouncedCSS])
return (
setLocalCSS(value || '')}
language="css"
theme="vs-dark"
height="400px"
options={{
minimap: { enabled: false },
fontSize: 14,
automaticLayout: true,
}}
/>
)
}
// Apply custom CSS dynamically
useEffect(() => {
let styleElement = document.getElementById('dynamic-custom-css')
if (!styleElement) {
styleElement = document.createElement('style')
styleElement.id = 'dynamic-custom-css'
document.head.appendChild(styleElement)
}
styleElement.textContent = customCSS
}, [customCSS])
```
--------------------------------
### Control Window Opacity with React and Zustand
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
Allows setting and applying window opacity for the overlay. It utilizes Zustand for state management and Electron's IPC for inter-process communication to the main process. Opacity is set as a percentage and then converted for the Electron API.
```typescript
import { useSettingsStore } from './store/useSettingsStore'
// In a React component
const { opacity, setOpacity } = useSettingsStore()
// Set opacity to 80%
setOpacity(80)
// Apply opacity via IPC to main process
window.electronAPI.setWindowOpacity(opacity / 100)
```
--------------------------------
### Manage Runtime State with Runtime Store (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This snippet details the Runtime Store, a non-persistent state management solution using Zustand. It tracks the connection status, incoming messages, and the count of online users. The store provides functions to update these states, with automatic handling for message limits and clear operations. It depends on the `ConnectionState` enum from `@laplace.live/event-bridge-sdk`.
```typescript
import { useRuntimeStore } from './store/useRuntimeStore'
import { ConnectionState } from '@laplace.live/event-bridge-sdk'
// In a React component
function StatusDisplay() {
const {
connectionState, setConnectionState,
onlineUserCount, setOnlineUserCount,
messages, addMessage, clearMessages,
} = useRuntimeStore()
// Update connection state
useEffect(() => {
setConnectionState(ConnectionState.CONNECTED)
}, [])
// Add a message
const handleNewMessage = (event: LaplaceEvent) => {
addMessage(event)
// Automatically maintains max 100 messages for performance
}
// Update online count
const handleOnlineUpdate = (count: number) => {
setOnlineUserCount(count)
}
// Clear all messages
const handleClearChat = () => {
clearMessages()
}
return (
{connectionState}
{onlineUserCount} viewers online
{messages.map(msg => (
{msg.message}
))}
)
}
```
--------------------------------
### Implement Click-Through Mode for Electron Overlay
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
Manages the click-through functionality for the overlay window, allowing interaction with underlying applications while keeping the title bar interactive. It uses Zustand for state and Electron's `setIgnoreMouseEvents` API, with mousemove event listeners to determine title bar interaction.
```typescript
import { useSettingsStore } from './store/useSettingsStore'
// In a React component
const { clickThrough, setClickThrough } = useSettingsStore()
// Enable click-through
setClickThrough(true)
// Apply setting via IPC
window.electronAPI.setClickThrough(clickThrough)
// Handle mouse tracking to keep title bar interactive
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!clickThrough) {
window.electronAPI.setIgnoreMouseEvents(false)
return
}
const titleBar = titleBarRef.current
if (!titleBar) return
const titleBarRect = titleBar.getBoundingClientRect()
const isOverTitleBar = e.clientY <= titleBarRect.bottom
// Ignore mouse events when NOT over title bar
window.electronAPI.setIgnoreMouseEvents(!isOverTitleBar)
}
document.addEventListener('mousemove', handleMouseMove)
return () => document.removeEventListener('mousemove', handleMouseMove)
}, [clickThrough])
```
--------------------------------
### Manage LAPLACE Event Bridge Connection with useLaplaceClient Hook (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
The `useLaplaceClient` hook manages the connection lifecycle for the LAPLACE Event Bridge and integrates with application state. It handles connection, authentication, event filtering, state updates, automatic reconnection, and cleanup. Dependencies include the `@laplace.live/event-bridge-sdk` and Zustand stores.
```typescript
import { useLaplaceClient } from './hooks/useLaplaceClient'
import { useSettingsStore } from './store/useSettingsStore'
import { useRuntimeStore } from './store/useRuntimeStore'
// In a React component
function App() {
// Initialize client (automatically connects and manages lifecycle)
useLaplaceClient()
// Access connection state and messages
const { connectionState, messages, onlineUserCount } = useRuntimeStore()
const { serverHost, serverPort, serverPassword, allowedOrigins } = useSettingsStore()
return (
Status: {connectionState}
Online: {onlineUserCount}
{messages.map(msg => (
{msg.type}: {msg.message}
))}
)
}
// The hook automatically:
// - Connects to ws://${serverHost}:${serverPort}
// - Authenticates with serverPassword
// - Filters events by allowedOrigins (comma-separated list)
// - Updates runtime store with messages and connection state
// - Reconnects automatically on connection loss
// - Cleans up on unmount or settings change
```
--------------------------------
### Connect to LAPLACE Event Bridge with SDK
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
Establishes a WebSocket connection to the LAPLACE Event Bridge using the provided SDK. It handles various live streaming events (messages, gifts, superchats, online updates) and connection state changes. Features include automatic reconnection and event listeners.
```typescript
import { LaplaceEventBridgeClient, ConnectionState } from '@laplace.live/event-bridge-sdk'
import type { LaplaceEvent } from '@laplace.live/event-types'
// Initialize client
const client = new LaplaceEventBridgeClient({
url: 'ws://localhost:9696',
token: 'your-password',
reconnect: true,
})
// Handle all incoming events
const handleEvent = (event: LaplaceEvent) => {
console.log('Received event:', event)
// Handle different event types
switch (event.type) {
case 'message':
console.log(`${event.username}: ${event.message}`)
break
case 'gift':
console.log(`${event.username} sent ${event.message} (¥${event.priceNormalized})`)
break
case 'superchat':
console.log(`${event.username} superchatted ¥${event.priceNormalized}: ${event.message}`)
break
case 'online-update':
console.log(`Online users: ${event.online}`)
break
}
}
// Handle connection state changes
const handleConnectionStateChange = (state: ConnectionState) => {
console.log(`Connection state: ${state}`)
// States: DISCONNECTED, CONNECTING, CONNECTED, RECONNECTING
}
// Register listeners
client.onAny(handleEvent)
client.onConnectionStateChange(handleConnectionStateChange)
// Connect
await client.connect()
// Cleanup
client.offAny(handleEvent)
client.offConnectionStateChange(handleConnectionStateChange)
client.disconnect()
```
--------------------------------
### Toggle Always-On-Top Mode in Electron App
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
Enables or disables the always-on-top behavior of the overlay window. This functionality uses Zustand for state management and Electron's IPC to communicate the setting to the main process. The `alwaysOnTop` state is directly passed to the Electron API.
```typescript
import { useSettingsStore } from './store/useSettingsStore'
// In a React component
const { alwaysOnTop, setAlwaysOnTop } = useSettingsStore()
// Enable always on top
setAlwaysOnTop(true)
// Apply setting via IPC
window.electronAPI.setAlwaysOnTop(alwaysOnTop)
```
--------------------------------
### Render and Filter Chat Events with Auto-Scroll (TypeScript)
Source: https://context7.com/laplace-live/chat-overlay/llms.txt
This component renders and filters different chat event types (messages, superchats, gifts, interactions) with auto-scroll functionality. It uses Zustand for state management and React hooks for managing scroll behavior and rendering logic. Dependencies include React, Zustand, and custom types like LaplaceEvent and ConnectionState.
```typescript
import { ChatEvents } from './components/events'
import { useRuntimeStore } from './store/useRuntimeStore'
import { useSettingsStore } from './store/useSettingsStore'
function ChatEventsComponent() {
const { messages, connectionState } = useRuntimeStore()
const { showInteractionEvents, showGiftFree, showEntryEffect } = useSettingsStore()
const [isAutoScrollPaused, setIsAutoScrollPaused] = useState(false)
const messagesEndRef = useRef(null)
// Auto-scroll logic
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
}
const isAtBottom = () => {
const chatEvents = chatEventsRef.current
if (!chatEvents) return true
const threshold = 160
return chatEvents.scrollHeight - chatEvents.scrollTop - chatEvents.clientHeight < threshold
}
const handleScroll = () => {
setIsAutoScrollPaused(!isAtBottom())
}
useEffect(() => {
if (!isAutoScrollPaused) scrollToBottom()
}, [messages, isAutoScrollPaused])
// Render message by type
const renderMessage = (event: LaplaceEvent) => {
if (event.type === 'message') {
return (
{connectionState === ConnectionState.CONNECTED
? 'Waiting for messages…'
: 'Connecting to LAPLACE Event Bridge…'}
) : (
messages.map(renderMessage)
)}
)
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.