skills/hytopia-debugging/SKILL.md
Helps debug HYTOPIA SDK games. Use when users need performance monitoring, error handling, client debugging, or troubleshooting. Covers debug panels, ErrorHandler, browser dev tools, and server logging.
npx skillsauth add abstrucked/hytopia-skills hytopia-debuggingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill helps you debug HYTOPIA SDK games effectively.
Documentation: https://dev.hytopia.com/sdk-guides/debugging
Use this skill when the user:
The HYTOPIA client provides real-time performance metrics:
Keyboard: Press the tilde key (`) - typically top-left of keyboard
Mobile: Tap with 5 fingers simultaneously anywhere on screen
Persistent Debug: Append ?debug to your game URL for debug panel to persist across hot reloads
Access via:
// All console.log() calls from UI code appear here
console.log('Player clicked button');
console.log('UI state:', uiState);
// Errors also appear with stack traces
console.error('Failed to load asset');
Server logs appear in the terminal where you launched the HYTOPIA server:
// Standard logging
console.log('Player joined:', player.username);
console.log('Game state:', gameState);
// Debug specific systems
console.log('[Physics] Collision detected:', entityA.id, entityB.id);
console.log('[AI] Enemy state changed:', enemy.state);
The SDK provides native error logging with stack traces:
import { ErrorHandler } from 'hytopia';
// Warning - non-critical issues
ErrorHandler.warn('Player inventory nearly full');
// Error - recoverable errors
ErrorHandler.error('Failed to load player data, using defaults');
// Fatal Error - unrecoverable, may crash
ErrorHandler.fatalError('Critical game state corruption detected');
// Wrap risky operations
function loadPlayerData(player: Player) {
try {
const data = loadFromStorage(player.id);
return data;
} catch (error) {
ErrorHandler.error(`Failed to load data for ${player.username}: ${error}`);
return getDefaultPlayerData();
}
}
// Validate inputs
function handlePlayerAction(player: Player, action: string) {
if (!action) {
ErrorHandler.warn(`Empty action from ${player.username}`);
return;
}
if (!isValidAction(action)) {
ErrorHandler.error(`Invalid action "${action}" from ${player.username}`);
return;
}
processAction(player, action);
}
const DEBUG = true; // Set false in production
function debugLog(category: string, message: string, data?: any) {
if (!DEBUG) return;
const timestamp = new Date().toISOString();
if (data) {
console.log(`[${timestamp}] [${category}] ${message}`, data);
} else {
console.log(`[${timestamp}] [${category}] ${message}`);
}
}
// Usage
debugLog('Physics', 'Raycast hit', { entity: entity.id, distance: 5.2 });
debugLog('Network', 'Player sync', { playerCount: world.players.length });
function measurePerformance(name: string, fn: () => void) {
const start = performance.now();
fn();
const duration = performance.now() - start;
if (duration > 16) { // More than one frame at 60fps
console.warn(`[Performance] ${name} took ${duration.toFixed(2)}ms`);
}
}
// Usage
measurePerformance('AI Update', () => {
updateAllEnemies();
});
// Log entity states for debugging
function debugEntity(entity: Entity) {
console.log('Entity Debug:', {
id: entity.id,
position: entity.position,
rotation: entity.rotation,
velocity: entity.velocity,
health: entity.getData('health'),
state: entity.getData('state')
});
}
// Periodic state dump
setInterval(() => {
console.log('=== World State ===');
console.log('Players:', world.players.length);
console.log('Entities:', world.entities.length);
world.players.forEach(p => {
console.log(` ${p.username}: ${JSON.stringify(p.position)}`);
});
}, 10000); // Every 10 seconds
// Track network events
world.onPlayerJoin = (player) => {
console.log(`[Network] Player connected: ${player.username} (${player.id})`);
};
world.onPlayerLeave = (player) => {
console.log(`[Network] Player disconnected: ${player.username}`);
};
// Log sync issues
function onSyncError(player: Player, error: string) {
ErrorHandler.error(`[Sync] Player ${player.username}: ${error}`);
}
// Check entity state
console.log('Entity position:', entity.position);
console.log('Entity velocity:', entity.velocity);
console.log('Has physics:', entity.hasComponent('physics'));
console.log('Is kinematic:', entity.isKinematic);
// Profile expensive operations
console.time('AI Update');
updateAllEnemies();
console.timeEnd('AI Update');
console.time('Physics Tick');
world.physicsStep();
console.timeEnd('Physics Tick');
world.onPlayerLeave = (player) => {
console.log('Player left:', {
username: player.username,
playTime: Date.now() - player.getData('joinTime'),
lastPosition: player.position,
lastAction: player.getData('lastAction')
});
};
development
Helps build and manage worlds in HYTOPIA SDK. Use when users need to create terrain, place blocks, manage chunks, or work with the world editor integration. Covers blocks, chunk loading, world generation, and build.hytopia.com workflow.
tools
Helps create and use plugins in HYTOPIA SDK games. Use when users need to add NPM packages, create reusable modules, or extend game functionality. Covers plugin requirements, installation, and best practices.
development
Helps implement physics and collision in HYTOPIA SDK games. Use when users need rigid bodies, collision detection, raycasting, forces, or physics-based gameplay. Covers PhysicsComponent, colliders, raycasting, and physics simulation.
development
Helps save and load persistent data in HYTOPIA SDK games. Use when users need to save player progress, leaderboards, game state, or any data that persists across sessions. Covers PersistenceManager, global data, and player data.