Skip to content

Examples

Simple Chat Application

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('chat-room')

// Listen for chat messages
socket.subscribe('chat', ({ user, message, timestamp }) => {
  const chatDiv = document.getElementById('chat-messages')
  const messageEl = document.createElement('div')
  messageEl.innerHTML = `
    <strong>${user}:</strong> ${message}
    <small>${new Date(timestamp).toLocaleTimeString()}</small>
  `
  chatDiv.appendChild(messageEl)
  chatDiv.scrollTop = chatDiv.scrollHeight
})

// Send message function
function sendMessage() {
  const input = document.getElementById('message-input')
  const username = document.getElementById('username').value
  
  if (input.value.trim()) {
    socket.send('chat', {
      user: username || 'Anonymous',
      message: input.value,
      timestamp: Date.now()
    })
    input.value = ''
  }
}

Real-time Cursor Tracking

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('collaboration-room')
const cursors = new Map()

// Track mouse movement
document.addEventListener('mousemove', (e) => {
  socket.send('cursor', {
    x: e.clientX,
    y: e.clientY,
    userId: getCurrentUserId(),
    color: getUserColor()
  })
})

// Display other users' cursors
socket.subscribe('cursor', ({ x, y, userId, color }) => {
  if (userId === getCurrentUserId()) return // Don't show own cursor
  
  let cursor = cursors.get(userId)
  if (!cursor) {
    cursor = document.createElement('div')
    cursor.className = 'remote-cursor'
    cursor.style.cssText = `
      position: fixed;
      width: 20px;
      height: 20px;
      background: ${color};
      border-radius: 50%;
      pointer-events: none;
      z-index: 9999;
      transition: all 0.1s ease;
    `
    document.body.appendChild(cursor)
    cursors.set(userId, cursor)
  }
  
  cursor.style.left = x + 'px'
  cursor.style.top = y + 'px'
})

Live Document Collaboration

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('document-' + documentId)
let isTyping = false

// Listen for text changes from other users
socket.subscribe('text-change', ({ operation, position, text, userId }) => {
  if (userId === getCurrentUserId()) return
  
  const editor = document.getElementById('editor')
  const currentText = editor.value
  
  if (operation === 'insert') {
    editor.value = currentText.slice(0, position) + text + currentText.slice(position)
  } else if (operation === 'delete') {
    editor.value = currentText.slice(0, position) + currentText.slice(position + text.length)
  }
})

// Send text changes to other users
document.getElementById('editor').addEventListener('input', (e) => {
  if (isTyping) return
  
  const target = e.target
  const operation = e.inputType.includes('delete') ? 'delete' : 'insert'
  
  socket.send('text-change', {
    operation,
    position: target.selectionStart,
    text: e.data || '',
    userId: getCurrentUserId(),
    timestamp: Date.now()
  })
})

// Typing indicators
let typingTimeout
document.getElementById('editor').addEventListener('keypress', () => {
  socket.send('typing-start', { userId: getCurrentUserId() })
  
  clearTimeout(typingTimeout)
  typingTimeout = setTimeout(() => {
    socket.send('typing-stop', { userId: getCurrentUserId() })
  }, 2000)
})

Multiplayer Game

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('game-' + gameId)
let gameState = { players: {}, board: [] }

// Join game
socket.send('player-join', {
  playerId: getPlayerId(),
  username: getUsername(),
  avatar: getPlayerAvatar()
})

// Listen for game updates
socket.subscribe('game-state', (newState) => {
  gameState = newState
  renderGame(gameState)
})

socket.subscribe('player-join', ({ playerId, username, avatar }) => {
  gameState.players[playerId] = { username, avatar, score: 0 }
  showPlayerJoined(username)
  renderPlayers(gameState.players)
})

socket.subscribe('player-leave', ({ playerId, username }) => {
  delete gameState.players[playerId]
  showPlayerLeft(username)
  renderPlayers(gameState.players)
})

// Make a game move
function makeMove(moveData) {
  socket.send('game-move', {
    playerId: getPlayerId(),
    move: moveData,
    timestamp: Date.now()
  })
}

// Listen for moves from other players
socket.subscribe('game-move', ({ playerId, move, gameState: newState }) => {
  gameState = newState
  animateMove(playerId, move)
  renderGame(gameState)
  
  // Check for game over conditions
  if (gameState.winner) {
    showGameOver(gameState.winner)
  }
})

User Presence System

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('presence-' + roomId)
const onlineUsers = new Set()

// Announce presence when joining
socket.send('user-online', {
  userId: getCurrentUserId(),
  username: getUsername(),
  avatar: getUserAvatar(),
  status: 'online'
})

// Listen for user presence updates
socket.subscribe('user-online', ({ userId, username, avatar, status }) => {
  onlineUsers.add(userId)
  updateUserList(onlineUsers)
  showNotification(`${username} joined`)
})

socket.subscribe('user-offline', ({ userId, username }) => {
  onlineUsers.delete(userId)
  updateUserList(onlineUsers)
  showNotification(`${username} left`)
})

socket.subscribe('user-status', ({ userId, status }) => {
  updateUserStatus(userId, status) // away, busy, etc.
})

// Send periodic heartbeat
setInterval(() => {
  socket.send('heartbeat', {
    userId: getCurrentUserId(),
    timestamp: Date.now()
  })
}, 30000)

// Handle page visibility changes
document.addEventListener('visibilitychange', () => {
  const status = document.hidden ? 'away' : 'online'
  socket.send('user-status', {
    userId: getCurrentUserId(),
    status
  })
})

// Clean up on page unload
window.addEventListener('beforeunload', () => {
  socket.send('user-offline', {
    userId: getCurrentUserId(),
    username: getUsername()
  })
})

Live Polling/Voting

ts
import { IttySocket } from 'itty-sockets'

const socket = new IttySocket('poll-' + pollId)
let pollData = { question: '', options: [], votes: {} }

// Load initial poll data
socket.subscribe('poll-data', (data) => {
  pollData = data
  renderPoll(pollData)
})

// Listen for new votes
socket.subscribe('vote-cast', ({ userId, optionId, username }) => {
  pollData.votes[userId] = optionId
  updateVoteCount(pollData)
  showVoteNotification(`${username} voted`)
})

// Cast a vote
function castVote(optionId) {
  socket.send('vote-cast', {
    userId: getCurrentUserId(),
    username: getUsername(),
    optionId,
    timestamp: Date.now()
  })
}

// Real-time results
function updateVoteCount(pollData) {
  const counts = {}
  pollData.options.forEach(option => counts[option.id] = 0)
  
  Object.values(pollData.votes).forEach(optionId => {
    counts[optionId] = (counts[optionId] || 0) + 1
  })
  
  // Update UI with live results
  renderResults(counts)
}

// Admin functions (if user is poll creator)
function updatePoll(question, options) {
  socket.send('poll-update', {
    question,
    options,
    adminId: getCurrentUserId()
  })
}

function closePoll() {
  socket.send('poll-close', {
    adminId: getCurrentUserId(),
    timestamp: Date.now()
  })
}