npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

universal-game-controller

v1.3.2

Published

Simple game input for touch screen, keyboard, gamepad and mouse

Downloads

7

Readme

Universal Game Controller

npm npm bundle size NPM

Simple game input for 💻 keyboard, 📱 touchscreen and 🎮 gamepad through a unified API. Made for game jams.

Why?

  • You’ll need keyboard support for maximum game development speed and compatibility.
  • However, actual gameplay will be more fun and impressive with a game controller. Only if you had the time...
  • Touchscreen support will make it 100x easier to show the game to your friends after the game jam.

How?

Current game inputs are:

  • one joystick
  • one button

Constraining? That’s where creativity starts! Never underestimate the power of simplicity – easy to learn is easy to love.

Demo: https://ugc.bloat.app

See importing instructions below.

Design goals

  • Fun and practical to use in game jams.
  • Games are equally playable on laptop (for development), TV (for immersion) and phone (for sharing).
  • Easy to use for new players (on all platforms).
  • Fun even at high skill levels (on all platforms).
  • Light-weight and zero dependencies.

Features

All user inputs are provided as a state of the controller – no events as of now. These are meant to be read in the game update loop.

Joystick

controller.move: { x, y }

  • Output is a 2D vector that is guaranteed to be inside the unit circle (even if multiple controllers are used at once).
  • Gamepad: Analog left joystick (with a dead zone for drift compensation).
  • Keyboard: WASD (with diagonal length compensation).
  • Touchscreen: The first touch (anywhere) can be slided around as a virtual joystick. Scrolling the page is disabled (also on Safari).
  • Should be exactly (0, 0) when the user is not touching the controls – however, this is not guaranteed for gamepad, since the neutral position might vary from device to device, and there is no specification for maximum allowed drift.

Trigger button

controller.trigger: boolean

  • Gamepad: Button 1 (Xbox: A, Switch: B)
  • Keyboard: Space. Scrolling is prevented.
  • Touchscreen: Second touch (anywhere). The button is sustained even if the first touch ends.

Controller type

controller.type: InputType

  • The game can display instructions for the specific input device that the player is using.
  • If a gamepad is connected, type is always gamepad.
  • Otherwise touchscreen and keyboard will switch to the one that had the last input event.
  • On page load before any user actions, type is touchscreen if a touchscreen is present.

Importing

URL

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/main.js"></script>
const { controller } = UniversalGameController

NPM

npm install universal-game-controller
import { controller } from 'universal-game-controller'

Example using URL import

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/main.js"></script>
    </head>
    <body>
        <div id="instructions" style="font-family: sans-serif; width: 100%; text-align: center; font-size: 2em; padding-top: 0.3em;"></div>
        <div id="container" style="border: 2vmin solid rgb(15, 31, 46); width: 80vmin; height: 80vmin; border-radius: 50%; position: absolute; left: calc(50% - 40vmin); top: calc(50% - 40vmin); display: flex; justify-content: center; align-items: center;">
            <div id="output" style="border: 2vmin solid rgb(15, 31, 46); width: 40vmin; height: 40vmin; border-radius: 50%; transform: translate(0vmin); background-color: rgb(15, 31, 46); box-sizing: border-box;"></div>
        </div>
        <script>
            const { controller, InputType } = UniversalGameController;
            const output = document.querySelector('#output');
            const instructions = document.querySelector('#instructions');

            const gameLoop = () => {
                const move = controller.move;
                output.style.transform = `translate(${move.x * 25}vmin, ${move.y * 25}vmin)`;

                if (controller.trigger) {
                    output.style.width = '60vmin';
                    output.style.height = '60vmin';
                } else {
                    output.style.width = '30vmin';
                    output.style.height = '30vmin';
                }

                if (controller.type === InputType.KEYBOARD) {
                    instructions.innerText = 'Use WASD to move and space to trigger';
                } else if (controller.type === InputType.TOUCH) {
                    instructions.innerText = 'Use one finger to move and another to trigger';
                } else if (controller.type === InputType.GAMEPAD) {
                    instructions.innerText = 'Use the left stick to move and button 1 to trigger';
                }

                requestAnimationFrame(gameLoop);
            }
            gameLoop();
        </script>
    </body>
</html>

Ideas

  • Configurations for gamepad joystick dead zone and touchscreen virtual joystick size.
  • Provide the current touch coordinates for displaying virtual joysticks.
  • Capturing touch input only on specific DOM elements.
  • Twin-stick.
  • Events for trigger button state change.
  • Mouse support (because WASD has only 8 directions and this can be too limiting in top-down shooting games).
  • Optional joystick smoothing (to make it easier to move only a tiny bit with WASD).
  • More buttons with game-defined graphics for touchscreen version (how to hide them when touch screen is not present?)

Non-goals

  • Anything that displays graphics (e.g. virtual joysticks).
  • Anything that requires user action to enable (e.g. motion sensor).
  • Local multiplayer. Well, maybe. Multiplayer is fun, but this gets a bit complicated to handle in a generic way. The main point of this library is to provide an opinionated mapping between different input types, and there more trade-offs with 2-player control mapping possibilities.
  • Exposing all features of each input method. If you need more, just use the vanilla APIs – they are not that complicated.
  • XR / 3D input.