skills/hytopia-mobile/SKILL.md
Helps implement mobile support in HYTOPIA SDK games. Use when users need touch controls, mobile UI, device detection, or cross-platform compatibility. Covers mobile controls, touch input, and responsive UI.
npx skillsauth add abstrucked/hytopia-skills hytopia-mobileInstall 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 implement mobile support in HYTOPIA SDK games.
Documentation: https://dev.hytopia.com/sdk-guides/mobile
Use this skill when the user:
HYTOPIA handles automatically:
HYTOPIA adds .mobile class to <body> on mobile devices:
/* Desktop-only styles */
.desktop-controls {
display: block;
}
/* Hide desktop controls on mobile */
body.mobile .desktop-controls {
display: none;
}
/* Mobile-only styles */
.mobile-controls {
display: none;
}
body.mobile .mobile-controls {
display: flex;
}
// Check if running on mobile
if (hytopia.isMobile) {
setupMobileUI();
} else {
setupDesktopUI();
}
// Conditional logic
function showControls() {
if (hytopia.isMobile) {
showTouchButtons();
} else {
showKeyboardHints();
}
}
Use hytopia.pressInput() to simulate keyboard/mouse input:
// Simulate key press
hytopia.pressInput('space', true); // Key down
hytopia.pressInput('space', false); // Key up
// Simulate mouse click
hytopia.pressInput('ml', true); // Left mouse down
hytopia.pressInput('ml', false); // Left mouse up
hytopia.pressInput('mr', true); // Right mouse down
<script>
// Jump button
const jumpBtn = document.getElementById('jump-btn');
jumpBtn.addEventListener('touchstart', (e) => {
e.preventDefault(); // Prevent default touch behavior
jumpBtn.classList.add('active');
hytopia.pressInput(' ', true); // Space key
});
jumpBtn.addEventListener('touchend', (e) => {
e.preventDefault();
jumpBtn.classList.remove('active');
hytopia.pressInput(' ', false);
});
// Attack button
const attackBtn = document.getElementById('attack-btn');
attackBtn.addEventListener('touchstart', (e) => {
e.preventDefault();
attackBtn.classList.add('active');
hytopia.pressInput('ml', true); // Left click
});
attackBtn.addEventListener('touchend', (e) => {
e.preventDefault();
attackBtn.classList.remove('active');
hytopia.pressInput('ml', false);
});
</script>
<div class="mobile-controls">
<a id="interact-btn" class="mobile-button">
<img src="{{CDN_ASSETS_URL}}/icons/interact.png" />
</a>
<a id="jump-btn" class="mobile-button">
<img src="{{CDN_ASSETS_URL}}/icons/jump.png" />
</a>
<a id="attack-btn" class="mobile-button">
<img src="{{CDN_ASSETS_URL}}/icons/attack.png" />
</a>
</div>
<style>
.mobile-controls {
display: none;
}
body.mobile .mobile-controls {
display: flex;
gap: 14px;
position: fixed;
bottom: 40px;
right: 40px;
}
.mobile-button {
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.mobile-button img {
width: 24px;
height: 24px;
filter: invert(1);
}
.mobile-button.active {
transform: scale(0.92);
background-color: rgba(0, 0, 0, 0.75);
}
</style>
<script>
document.querySelectorAll('.mobile-button').forEach(btn => {
const input = btn.dataset.input;
btn.addEventListener('touchstart', (e) => {
e.preventDefault();
btn.classList.add('active');
hytopia.pressInput(input, true);
});
btn.addEventListener('touchend', (e) => {
e.preventDefault();
btn.classList.remove('active');
hytopia.pressInput(input, false);
});
});
</script>
/* Base UI */
.game-hud {
font-size: 16px;
padding: 10px;
}
/* Larger touch targets on mobile */
body.mobile .game-hud {
font-size: 20px;
padding: 16px;
}
/* Minimum touch target size: 44x44px */
body.mobile button,
body.mobile .touchable {
min-width: 44px;
min-height: 44px;
}
/* Keyboard hints - desktop only */
.keyboard-hint {
display: inline-block;
}
body.mobile .keyboard-hint {
display: none;
}
/* Simplify mobile UI */
body.mobile .detailed-stats {
display: none;
}
body.mobile .simple-stats {
display: block;
}
/* Account for notches and rounded corners */
body.mobile .mobile-controls {
padding-bottom: env(safe-area-inset-bottom, 20px);
padding-right: env(safe-area-inset-right, 20px);
}
| Input | Key |
|-------|-----|
| Space/Jump | ' ' (space) |
| Left Click | 'ml' |
| Right Click | 'mr' |
| WASD | 'w', 'a', 's', 'd' |
| Interact | 'e' |
| Reload | 'r' |
| Sprint | 'shift' |
e.preventDefault() in touch handlersdevelopment
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.