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

react-node-insim

v0.0.6

Published

React Node InSim

Downloads

8

Readme

React Node InSim

NPM Version

A React renderer for InSim buttons, based on Node InSim.

Introduction

🚧 This project is still under development. Any API may change as needed.

React Node InSim is a React renderer for Live for Speed InSim buttons. It also provides layout components for easier button positioning, hooks for handling incoming InSim packets and tracking server connections & players.

It is based on Node InSim, a Node.js library, written in TypeScript, for InSim communication.

It allows you to create things like this:

import type { InSim } from 'node-insim';
import { InSimFlags, IS_BTC, IS_MST, PacketType } from 'node-insim/packets';
import { StrictMode } from 'react';
import {
  Button,
  ConnectionsProvider,
  createRoot,
  PlayersProvider,
  useConnections,
  useOnConnect,
  useOnPacket,
  usePlayers,
  VStack,
} from 'react-node-insim';

function App() {
  // Get the list of current players and connections
  const players = usePlayers();
  const connections = useConnections();

  // Do something after the InSim app has been connected to LFS
  useOnConnect((packet, inSim) => {
    console.log(`Connected to LFS ${packet.Product} ${packet.Version}`);
    inSim.send(new IS_MST({ Msg: `React Node InSim connected` }));
  });

  // Handle incoming packets
  useOnPacket(PacketType.ISP_NCN, (packet) => {
    console.log(`New connection: ${packet.UName}`);
  });

  // Clickable buttons
  const handlePlayerClick = (plid: number) => (_: IS_BTC, inSim: InSim) => {
    inSim.send(new IS_MST({ Msg: `/echo PLID ${plid}` }));
  };

  const handleConnectionClick = (ucid: number) => (_: IS_BTC, inSim: InSim) => {
    inSim.send(new IS_MST({ Msg: `/echo UCID ${ucid}` }));
  };

  return (
    <>
      <Button top={10} left={40} width={30} height={5} UCID={255} color="title">
        Players
      </Button>
      <VStack
        background="dark"
        top={15}
        left={40}
        width={30}
        height={5}
        UCID={255}
      >
        {players.map((player) => (
          <Button key={player.PLID} onClick={handlePlayerClick(player.PLID)}>
            {player.PName}
          </Button>
        ))}
      </VStack>
      <Button top={10} left={70} width={30} height={5} UCID={255} color="title">
        Connections
      </Button>
      <VStack
        background="dark"
        top={15}
        left={70}
        width={30}
        height={5}
        UCID={255}
      >
        {connections.map((connection) => (
          <Button
            key={connection.UCID}
            onClick={handleConnectionClick(connection.UCID)}
          >
            {connection.UName}
          </Button>
        ))}
      </VStack>
    </>
  );
}

const root = createRoot({
  name: 'React InSim',
  host: '127.0.0.1',
  port: 29999,
  flags: InSimFlags.ISF_LOCAL,
});

root.render(
  <StrictMode>
    <PlayersProvider>
      <ConnectionsProvider>
        <App />
      </ConnectionsProvider>
    </PlayersProvider>
  </StrictMode>,
);

Table of contents

Requirements

Installation

NPM

npm install react@18 node-insim react-node-insim

Yarn

yarn add react@18 node-insim react-node-insim

pnpm

pnpm add react@18 node-insim react-node-insim

Basic usage

Displaying an InSim button on a local computer

import { InSimFlags } from 'node-insim/packets';
import { Button, createRoot } from 'react-node-insim';

const root = createRoot({
  name: 'React InSim',
  host: '127.0.0.1',
  port: 29999,
  flags: InSimFlags.ISF_LOCAL,
});

root.render(
  <Button top={100} left={80} width={30} height={10}>
    Hello InSim!
  </Button>,
);

You can use React hooks as usual to display stateful data via InSim.

import { InSimFlags } from 'node-insim/packets';
import { useEffect, useState } from 'react';
import { Button, createRoot } from 'react-node-insim';

function App() {
  const [time, setTime] = useState(new Date());

  useEffect(() => {
    const interval = setInterval(() => {
      setTime(new Date());
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  });

  return (
    <Button top={100} left={80} width={40} height={10}>
      Current time: {time.toLocaleTimeString()}
    </Button>
  );
}

const root = createRoot({
  name: 'React InSim',
  host: '127.0.0.1',
  port: 29999,
  flags: InSimFlags.ISF_LOCAL,
});

root.render(<App />);

Button

The Button component is used to display a button in LFS.

  • Buttons are drawn on a 200 by 200 canvas using absolute positioning
  • The maximum number of rendered buttons on a screen is 240

Import

import { Button } from 'react-node-insim';

Usage

<Button top={100} left={80} width={30} height={10}>
  Button
</Button>

Placement

Buttons use XY coordinates to position themselves on the screen. The top and left props control the button's X and Y position on the screen. The allowed range of values is 0 to 200.

<>
  <Button width={12} height={6} top={100} left={40}>
    Button
  </Button>
  <Button width={12} height={6} top={100} left={53}>
    Button
  </Button>
  <Button width={12} height={6} top={106} left={40}>
    Button
  </Button>
  <Button width={12} height={6} top={106} left={53}>
    Button
  </Button>
</>

Sizes

Use the width and height props to change the dimensions of the button. The allowed range of values is 0 to 200.

<>
  <Button variant="light" top={100} left={40} width={6} height={4}>
    Button
  </Button>
  <Button variant="light" top={99} left={47} width={10} height={6}>
    Button
  </Button>
  <Button variant="light" top={97} left={58} width={14} height={10}>
    Button
  </Button>
</>

Variants

Use the variant prop to change the button's visual style. You can use light or dark. If you don't specify a variant, the button will have transparent background and a light gray text color.

<>
  <Button top={100} left={40} width={12} height={6} variant="light">
    Button
  </Button>
  <Button top={100} left={53} width={12} height={6} variant="dark">
    Button
  </Button>
</>

Text colors

Use the color prop to customize the button's text color. If you don't specify a color, the button text will be default.

<>
  <Button top={73} left={40} width={12} height={6} color="default">
    default
  </Button>
  <Button top={73} left={53} width={12} height={6} color="title">
    title
  </Button>
  <Button top={73} left={66} width={12} height={6} color="unselected">
    unselected
  </Button>
  <Button top={73} left={79} width={12} height={6} color="selected">
    selected
  </Button>
  <Button top={80} left={40} width={12} height={6} color="ok">
    ok
  </Button>
  <Button top={80} left={53} width={12} height={6} color="cancel">
    cancel
  </Button>
  <Button top={80} left={66} width={12} height={6} color="textstring">
    textstring
  </Button>
  <Button top={80} left={79} width={12} height={6} color="unavailable">
    unavailable
  </Button>
</>

You can choose from a set of semantic colors or use one of the colors from the LFS color palette.

Semantic colors

  • default
  • title
  • unselected
  • selected
  • ok
  • cancel
  • textstring
  • unavailable

Note: The semantic color values can be customized in LFS Options -> Display -> Interface.

LFS color palette

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white

Background colors

Use the background prop to customize the button's background color. If you don't specify a color, the background will be transparent.

<>
  <Button top={67} left={40} width={12} height={6} background="light">
    light
  </Button>
  <Button top={67} left={53} width={12} height={6} background="dark">
    dark
  </Button>
  <Button top={67} left={66} width={12} height={6} background="transparent">
    transparent
  </Button>
</>

Horizontal stack

HStack displays buttons in a column without having to specify each button's position manually. You can also override button colors and sizes.

Import

import { HStack } from 'react-node-insim';

Usage

<HStack top={10} left={20} width={7} height={4} variant="dark">
  <Button>Stacked button</Button>
  <Button color="title">Custom color</Button>
  <Button height={6}>Custom height</Button>
</HStack>

Vertical stack

VStack displays buttons in a row without having to specify each button's position manually. You can also override button colors and sizes.

Import

import { VStack } from 'react-node-insim';

Usage

<VStack top={10} left={20} width={7} height={4} variant="dark">
  <Button>Stacked button</Button>
  <Button color="title">Custom color</Button>
  <Button height={6}>Custom height</Button>
</VStack>

Flex

Flex layout displays buttons in a row or column with flexbox options.

Import

import { Flex } from 'react-node-insim';

Usage

<Flex
  top={10}
  left={20}
  width={36}
  height={16}
  alignItems="center"
  justifyContent="space-evenly"
  background="dark"
  backgroundColor="light"
>
  <Button width={8} height={4}>
    Left
  </Button>
  <Button width={10} height={6}>
    Center
  </Button>
  <Button width={8} height={4}>
    Right
  </Button>
</Flex>

Grid

Grid layout displays buttons in a grid.

Import

import { Grid, GridButton } from 'react-node-insim';

Usage

<Grid
  top={30}
  left={40}
  width={30}
  height={30}
  background="dark"
  backgroundColor="light"
  gridTemplateColumns="1fr 2fr 1fr"
  gridTemplateRows="1fr 3fr 2fr"
  gridColumnGap={1}
  gridRowGap={1}
>
  <GridButton>1</GridButton>
  <GridButton
    gridColumnStart={2}
    gridRowStart={1}
    gridRowEnd={3}
    color="title"
    background="light"
  >
    2
  </GridButton>
  <GridButton
    gridColumnStart={3}
    gridColumnEnd={3}
    gridRowStart={1}
    gridRowEnd={3}
  >
    3
  </GridButton>
  <GridButton alignSelf="end" height={10}>
    4
  </GridButton>
  <GridButton gridColumnStart={1} gridColumnEnd={4}>
    5
  </GridButton>
</Grid>

Toggle button

A button that can be toggled on and off by clicking it.

Import

import { ToggleButton } from 'react-node-insim';

Usage

function App() {
  const [isOn, setIsOn] = useState(false);

  return (
    <ToggleButton
      top={100}
      left={80}
      width={12}
      height={6}
      isOn={isOn}
      onToggle={setIsOn}
    >
      Toggle
    </ToggleButton>
  );
}

Variants

Use the variant prop to change the button's background style. You can use light or dark. If you don't specify a variant, light will be used.

<>
  <ToggleButton variant="light" top={100} left={40} width={12} height={6}>
    Toggle
  </ToggleButton>
  <ToggleButton variant="dark" top={100} left={53} width={12} height={6}>
    Toggle
  </ToggleButton>
</>

Disabled state

Use the isDisabled prop to prevent toggling the button on/off.

<>
  <ToggleButton
    isDisabled={false}
    variant="light"
    top={100}
    left={40}
    width={12}
    height={6}
  >
    Enabled
  </ToggleButton>
  <ToggleButton
    isDisabled
    variant="light"
    top={100}
    left={53}
    width={12}
    height={6}
  >
    Disabled
  </ToggleButton>
  <ToggleButton
    isDisabled={false}
    variant="dark"
    top={106}
    left={40}
    width={12}
    height={6}
  >
    Enabled
  </ToggleButton>
  <ToggleButton
    isDisabled
    variant="dark"
    top={106}
    left={53}
    width={12}
    height={6}
  >
    Disabled
  </ToggleButton>
</>

Toggle button group

A group of buttons that can be toggled on and off by clicking them.

Import

import { ToggleButtonGroup } from 'react-node-insim';

Usage

const options = [
  { label: 'low', value: 1 },
  { label: 'medium', value: 2 },
  { label: 'high', value: 3 },
];

function App() {
  const [selectedOption, setSelectedOption] = useState(options[0]);

  return (
    <ToggleButtonGroup
      top={30}
      left={50}
      width={36}
      height={6}
      options={options}
      selectedOption={selectedOption}
      onChange={setSelectedOption}
    />
  );
}

Text box

A text box whose content can span multiple rows. If the content is too long, the text box will show a scrollbar.

Import

import { TextBox } from 'react-node-insim';

Usage

<TextBox
  top={40}
  left={50}
  cols={20}
  rows={4}
  width={20}
  rowHeight={4}
  variant="light"
>
  Hello world this is a text box lorem ipsum dolor sit amet consectetur
  adipisicing elitrea lorem ipsum dolor sit amet consectetur adipisicing elit
</TextBox>

Hooks

useOnConnect

Execute code after the InSim app has been connected.

The first parameter is an IS_VER packet callback executed when IS_VER is received upon successful InSim connection to LFS.

import { useOnConnect } from 'react-node-insim';

function App() {
  useOnConnect((packet, inSim) => {
    console.log(`Connected to LFS ${packet.Product} ${packet.Version}`);
    inSim.send(new IS_MST({ Msg: `React Node InSim connected` }));
  });

  return null;
}

useOnDisconnect

Execute code after the InSim app has been disconnected.

The first parameter is the "disconnect" event callback from Node InSim.

import { useOnDisconnect } from 'react-node-insim';

function App() {
  useOnDisconnect(() => {
    console.log('Disconnected from LFS');
  });

  return null;
}

useOnPacket

Execute code when an InSim packet is received

import { useOnPacket } from 'react-node-insim';

function App() {
  useOnPacket(PacketType.ISP_NCN, (packet) => {
    console.log(`New connection: ${packet.UName}`);
  });

  return null;
}

useConnections

Get a live list of all connected guests.

import { useConnections } from 'react-node-insim';

function App() {
  const connections = useConnections();

  return (
    <VStack background="dark" top={10} left={10} width={20} height={4}>
      {connections.map((connection) => (
        <Button key={connection.UCID}>{connection.UName}</Button>
      ))}
    </VStack>
  );
}

usePlayers

Get a live list of all players on track.

import { usePlayers } from 'react-node-insim';

function App() {
  const players = usePlayers();

  return (
    <VStack background="dark" top={10} left={10} width={20} height={4}>
      {players.map((player) => (
        <Button key={player.PLID}>{player.PName}</Button>
      ))}
    </VStack>
  );
}

useMessage

Send a message to a connection or a player.

import { useMessage } from 'react-node-insim';

function App() {
  const { sendMessageToConnection, sendMessageToPlayer } = useMessage();

  return (
    <>
      <Button
        top={5}
        left={10}
        width={15}
        height={5}
        onClick={(packet) => {
          sendMessageToConnection(
            packet.UCID,
            'Hello from React Node InSim',
            MessageSound.SND_SYSMESSAGE,
          );
        }}
      >
        Send message to a connection
      </Button>
      <Button
        top={10}
        left={10}
        width={15}
        height={5}
        onClick={(packet) => {
          sendMessageToPlayer(
            12, // PLID
            'Hello from React Node InSim',
            MessageSound.SND_SYSMESSAGE,
          );
        }}
      >
        Send message to a player
      </Button>
    </>
  );
}

useRaceControlMessage

Send a race control message (RCM) to a connection or a player.

import { useRaceControlMessage } from 'react-node-insim';

function App() {
  const { sendRaceControlMessageToConnection, sendRaceControlMessageToPlayer } =
    useRaceControlMessage();

  return (
    <>
      <Button
        top={5}
        left={10}
        width={15}
        height={5}
        onClick={(packet) => {
          sendRaceControlMessageToConnection(
            packet.UCID,
            'Hello from React Node InSim',
            2000,
          );
        }}
      >
        Send message to a connection
      </Button>
      <Button
        top={10}
        left={10}
        width={15}
        height={5}
        onClick={(packet) => {
          sendRaceControlMessageToPlayer(
            12, // PLID
            'Hello from React Node InSim',
            2000,
          );
        }}
      >
        Send message to a player
      </Button>
    </>
  );
}

useInSim

Access to Node InSim API of the current InSim client instance.

import { useInSim } from 'react-node-insim';

function App() {
  const inSim = useInSim();

  useEffect(() => {
    inSim.send(new IS_MST({ Msg: 'App mounted' }));
  }, []);

  return null;
}

Development

Requirements

Installation

yarn

Run example app

yarn start

Lint code

yarn lint

Format code

yarn format

React Node Insim - An open source project by Sim Broadcasts