Skip to main content

Structure

The starter separates client boot, server boot, shared client config, and modules.

client.ts

client.ts starts the browser client in MMORPG mode:
import { startGame, provideMmorpg } from "@rpgjs/client";
import configClient from "./config/config.client";
import { mergeConfig } from "@signe/di";

startGame(
  mergeConfig(configClient, {
    providers: [provideMmorpg({})],
  }) 
);
Use this entry when the client connects to a remote RPGJS server.

server.ts

server.ts creates the game server and registers your providers:
import { createServer, provideServerModules, LocalStorageSaveStorageStrategy } from "@rpgjs/server";
import { provideMain } from "./modules/main";
import { provideSaveStorage } from "@rpgjs/server";
import { provideTiledMap } from "@rpgjs/tiledmap/server";

export default createServer({
  providers: [
    provideMain(),
    provideSaveStorage(new LocalStorageSaveStorageStrategy({ key: "save" })),
    provideServerModules([]),
    provideTiledMap()
  ]
});
This is where you plug modules, maps, database content, save strategies, or server adapters.

standalone.ts

standalone.ts runs the client and server together for a standalone RPG:
import { mergeConfig } from "@signe/di";
import { provideRpg, startGame } from "@rpgjs/client";
import startServer from "./server";
import configClient from "./config/config.client";

startGame(
  mergeConfig(configClient, {
    providers: [provideRpg(startServer)],
  })
);
Use this entry when you want a single-player RPG running entirely from the client app.

config/config.client.ts

config.client.ts contains the common client setup shared by MMORPG and standalone RPG:
import { provideClientGlobalConfig, provideClientModules, Presets } from "@rpgjs/client";
import { provideMain } from "../modules/main";
import { provideTiledMap } from "@rpgjs/tiledmap/client";

export default {
  providers: [
    provideTiledMap({
      basePath: "map",
    }),
    provideClientGlobalConfig(),
    provideMain(),
    provideClientModules([
      {
        spritesheets: [
          {
            id: "hero",
            image: "spritesheets/hero.png",
            ...Presets.RMSpritesheet(3, 4)
          }
        ]
      }
    ])
  ],
};
Put here everything the client always needs: map loading, global config, modules, spritesheets, sounds, and resolvers.

provideClientGlobalConfig()

provideClientGlobalConfig() is the client-side place for shared global configuration. It can hold built-in options such as keyboardControls, and also any custom object you want to expose everywhere in the client through dependency injection.
import { provideClientGlobalConfig } from "@rpgjs/client";

export default {
  providers: [
    provideClientGlobalConfig({
      keyboardControls: {
        up: "z",
        down: "s",
        left: "q",
        right: "d",
        action: "enter",
        escape: "escape"
      },
      ui: {
        locale: "fr",
        showDamagePreview: true
      },
      api: {
        baseUrl: "/api"
      }
    })
  ]
};
If you omit keyboardControls, RPGJS injects the default bindings automatically:
{
  up: "up",
  down: "down",
  left: "left",
  right: "right",
  action: "space",
  escape: "escape"
}
You can retrieve this global config anywhere on the client with inject(GlobalConfigToken):
import { inject } from "@signe/di";
import { GlobalConfigToken } from "@rpgjs/client";

const config = inject(GlobalConfigToken) as {
  keyboardControls: {
    up: string;
    down: string;
    left: string;
    right: string;
    action: string;
    escape: string;
  };
  ui?: {
    locale?: string;
    showDamagePreview?: boolean;
  };
};

console.log(config.keyboardControls.action);
console.log(config.ui?.locale);
This is useful in client services, GUI components, or custom systems that need access to global input bindings or project-specific client configuration.

modules/main

The main module is usually where you declare your first server hooks and maps:
import { createModule } from "@rpgjs/common";
import server from "./server";

export function provideMain() {
  return createModule("main", [{
    server
  }]);
}
This keeps your game logic modular. You can add more modules later for battle, UI, quests, chat, or any custom feature.