Skip to main content
Reading time: ~20 minutes
This tutorial walks you through creating your first CORP game from scratch. By the end, you’ll have a working game with components, GameObjects, and understand the basics of the framework.
New to CORP? See the README for an overview of features and architecture.

Prerequisites

Before starting, ensure you have:
  • Node.js (v14 or higher)
  • Visual Studio Code (recommended IDE)
  • Git for cloning the template
  • Roblox Studio installed

Step 1: Install Required Tools

Install VS Code Extensions

Install these essential VS Code extensions:
  1. roblox-ts Extension
  2. Rojo Extension

Install Rojo Studio Plugin

  1. Go to Rojo Releases
  2. Download the latest Rojo.rbxm file
  3. In Roblox Studio, go to Plugins folder:
    • Windows: %LOCALAPPDATA%\Roblox\Plugins
    • Mac: ~/Documents/Roblox/Plugins
  4. Place Rojo.rbxm in the Plugins folder
  5. Restart Roblox Studio
  6. You should see the Rojo plugin in the toolbar

Step 2: Clone the Template

Start by cloning the CORP template repository:
git clone https://github.com/MonoliskSoftware/CORP-TEMPLATE
cd CORP-TEMPLATE
The template includes:
  • CORP framework as a git submodule
  • Pre-configured project structure
  • Default Gamepack ready to customize
  • Bootstrap scripts for client and server

Step 2: Initialize Submodules

Initialize the CORP submodule:
git submodule update --init --recursive
This downloads the CORP framework into the CORP/ directory.

Step 3: Install Dependencies

Install npm dependencies:
npm install
This installs roblox-ts and other required packages.

Step 4: Configure Your Game

Update Gamepack Name

Open GAMEPACKS/MYGAME/metadata.ts and update the name:
import { Gamepacks } from "CORP/shared/unreal/gamepacks";

const metadata: Gamepacks.Config.Metadata = {
    name: "MyFirstGame",  // Change from "MYGAME" to your game name
    
    options: {
        assets: {},
        source: {},
        exports: {
            components: {},
            macros: {},
            scriptableObjects: {},
            scripts: {
                client: {},
                server: {}
            },
            boot: {}
        }
    }
};

export = metadata;

Update Game Configuration

Open GAMECONFIG/gameinfo.ts and update the root pack:
import { Unreal } from "CORP/shared/unreal";

const gameinfo: Unreal.Gameinfo = {
    rootPack: "MyFirstGame",  // Must match metadata name
    authority: Unreal.Authority.SERVER
};

export = gameinfo;

Step 5: Your Project Structure

Your project now has this structure:
CORP-TEMPLATE/
├── CORP/                    # Git submodule (framework)
├── GAMECONFIG/
│   └── gameinfo.ts         # Game configuration
├── GAMEPACKS/
│   └── MyFirstGame/        # Your Gamepack (renamed from MYGAME)
│       ├── metadata.ts     # Gamepack configuration
│       ├── exports/        # Component/Macro/ScriptableObject mappings
│       │   ├── components.ts
│       │   ├── bootconfig.ts
│       │   └── scripts/
│       ├── assets/         # Asset folder
│       └── src/            # Your game code
├── client/
│   └── bootstrapper.client.ts  # Client entry point
├── server/
│   └── bootstrapper.server.ts  # Server entry point
└── package.json

Step 6: Create Your First Component

Components define behavior for GameObjects. Let’s create a simple component.

Create the Component File

Create GAMEPACKS/MyFirstGame/src/HelloWorld.ts:
import { Behavior } from "CORP/shared/componentization/behavior";
import { GameObject } from "CORP/shared/componentization/game-object";

export class HelloWorld extends Behavior {
    public constructor(gameObject: GameObject) {
        super(gameObject);
    }

    // Called when the component starts
    public onStart(): void {
        print(`Hello from GameObject: ${this.gameObject.getName()}!`);
        print("My first CORP component is working!");
    }

    // Called when the component is being removed
    public willRemove(): void {
        print("Goodbye from HelloWorld component!");
    }

    // Required: Return the script that defines this component
    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }
}

Export the Component

Open GAMEPACKS/MyFirstGame/exports/components.ts and add your component:
import { Config } from "CORP/shared/unreal/gamepacks/config";
import { HelloWorld } from "../src/HelloWorld";

const components: Config.Components = {
    mappings: {
        "hello_world": HelloWorld  // Use snake_case for mapping names
    }
};

export = components;

Step 7: Set Up the Game Scene

Configure Boot Settings

Open GAMEPACKS/MyFirstGame/exports/bootconfig.ts:
import { Boot } from "CORP/shared/unreal/gamepacks/boot";

const bootConfig: Boot.Config = {
    startFromWorkspace: true  // Load GameObjects from workspace
};

export = bootConfig;

Create a Scene in Roblox Studio

  1. Open your game in Roblox Studio
  2. Create a Folder in Workspace
  3. Rename it to something like “GameScene”
  4. Add a Tag to this folder: GameObjectSceneRoot
    • Install the Tag Editor plugin if you don’t have it
  5. Inside this folder, create a Folder named “TestObject”
  6. Add a tag to “TestObject”: GameObject
Your workspace hierarchy should look like:
Workspace
└── GameScene [GameObjectSceneRoot]
    └── TestObject [GameObject]
Note: The GameObjectSceneRoot tag tells CORP where to find your scene root. The GameObject tag marks instances that should become GameObjects.

Step 8: Build and Test

Start the Development Workflow

CORP uses Rojo to sync your code to Roblox Studio in real-time. You need two terminals: Terminal 1 - Start Rojo Server:
rojo serve default.project.json
This starts the Rojo server on port 34872. You should see:
Rojo server listening on port 34872
Terminal 2 - Watch TypeScript Compilation:
npx rbxtsc --watch
This compiles your TypeScript code whenever you save a file.
Tip: You can use npm run watch if your package.json has a watch script configured.

Connect Roblox Studio to Rojo

  1. Open your game in Roblox Studio
  2. Click the Rojo plugin button in the toolbar
  3. Click Connect (it should auto-detect localhost:34872)
  4. You should see “Connected to Rojo” with a green indicator
Now your code will sync to Studio automatically when you save!

Test Your Game

  1. Make sure your workspace scene is set up (Step 7)
  2. Click Play (F5) in Roblox Studio
  3. Check the Output window
You should see:
Hello from GameObject: TestObject!
My first CORP component is working!
🎉 Congratulations! You’ve created your first CORP game!

Development Workflow Tips

  • Keep both terminals running while developing
  • Save your TypeScript files and they’ll auto-compile and sync to Studio
  • Don’t manually edit Roblox instance names - let Rojo manage the sync
  • Use Output window for debugging with print() statements
  • Restart the Rojo connection if you add new files/folders

Understanding What Happened

Let’s review what just happened:
  1. Bootstrap Process: The client and server entry points call Unreal.bootstrap()
  2. Manifest Creation: CORP reads your Gamepack and creates a manifest of all components
  3. Boot Config: The startFromWorkspace: true setting tells CORP to load from the workspace
  4. Scene Loading: CORP finds the GameObjectSceneRoot tag and converts tagged instances to GameObjects
  5. Component Initialization: Your HelloWorld component’s onStart() method is called

Component Lifecycle Explained

Understanding the component lifecycle is crucial:
  1. Constructor: Component is instantiated
    • Don’t access other components here!
  2. willStart(): Pre-initialization hook (optional)
  3. onStart(): Main initialization
    • Safe to access other components
    • Set up your game logic here
  4. onPropertiesApplied(): Called after serialized properties are applied (optional)
  5. willRemove(): Cleanup before destruction
    • Disconnect events, clean up resources
  6. remove(): Component is destroyed
export class LifecycleExample extends Behavior {
    private connection?: RBXScriptConnection;

    public willStart(): void {
        // Pre-initialization (rarely needed)
    }

    public onStart(): void {
        // Main initialization - set up game logic
        const otherComponent = this.gameObject.getComponent(SomeComponent);
        this.connection = RunService.Heartbeat.Connect(() => {
            // Update logic
        });
    }

    public onPropertiesApplied(): void {
        // React to serialized properties (if using @SerializeField)
    }

    public willRemove(): void {
        // IMPORTANT: Clean up resources
        this.connection?.Disconnect();
    }

    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }
}

Working with GameObjects at Runtime

While the workspace-based approach is great for level design, you can also create GameObjects dynamically:
import { GameObject } from "CORP/shared/componentization/game-object";
import { HelloWorld } from "../HelloWorld";

export class GameManager extends Behavior {
    public onStart(): void {
        // Create a new GameObject
        const myObject = new GameObject("DynamicObject");
        
        // Add a component
        const hello = myObject.addComponent(HelloWorld);
        
        // Set parent (attaches to scene)
        myObject.setParent(this.gameObject);
        
        // Get a component
        const component = myObject.getComponent(HelloWorld);
        
        // Remove a component
        myObject.removeComponent(HelloWorld);
        
        // Destroy the GameObject
        myObject.destroy();
    }

    public willRemove(): void {}
    
    protected getSourceScript(): ModuleScript {
        return script as ModuleScript;
    }
}

Next Steps

Now that you have a working CORP game, here’s what to learn next:

Learn Core Concepts

  • Core Concepts: Deep dive into GameObjects, Components, and Behaviors
  • Unreal System: Understanding Gamepacks and project organization
  • Decorators: Using @SerializeField, @RequiresComponent, and more

Add Game Features

  • Examples: Build player controllers, health systems, and weapons
  • Scene Management: Advanced scene loading and serialization
  • Macros: Transform Roblox instances into GameObjects procedurally
  • ScriptableObjects: Create reusable data assets

Add Multiplayer

Troubleshooting

”No scene root found in workspace”

Solution: Make sure you’ve tagged a Folder in Workspace with GameObjectSceneRoot.

”Component not found in manifest”

Solution:
  1. Check that your component is exported in exports/components.ts
  2. Verify the mapping name matches what you’re using
  3. Rebuild your project (npm run build)

Component’s onStart() not being called

Solution:
  1. Verify bootstrap is running (check for any errors in Output)
  2. Ensure the GameObject has the proper tags in workspace
  3. Check that the component export mapping is correct

”CORP is not defined” or import errors

Solution:
  1. Run git submodule update --init --recursive
  2. Verify the CORP folder exists in your project root
  3. Check your tsconfig.json paths configuration

Changes not reflecting in-game

Solution:
  1. Make sure npm run watch is running (or rebuild with npm run build)
  2. In Roblox Studio, stop and restart the play session
  3. Check the Output window for compilation errors

Tips for Success

✅ Best Practices

  • Initialize in onStart(): Never access other components in the constructor
  • Use @RequiresComponent: Enforce component dependencies declaratively
  • Clean up in willRemove(): Disconnect events and free resources
  • Use snake_case for mappings: Component exports should use snake_case names
  • Match Gamepack names: Ensure metadata.ts name matches gameinfo.ts rootPack

🎯 Common Patterns

// Accessing other components safely
export class MyComponent extends Behavior {
    private otherComponent?: OtherComponent;

    public onStart(): void {
        // Get components in onStart, not constructor
        this.otherComponent = this.gameObject.getComponent(OtherComponent);
    }
}

// Using RequiresComponent
@RequiresComponent(NetworkObject)
export class MyNetworkComponent extends NetworkBehavior {
    // NetworkObject is guaranteed to exist
}

// Serializable configuration
export class Configurable extends Behavior {
    @SerializeField
    public speed: number = 10;
    
    @SerializeField
    public maxHealth: number = 100;
}

Quick Reference

See the README for:
  • Common imports
  • Component templates
  • NetworkBehavior templates
  • Architecture overview
  • Best practices

Support and Resources


🚀 You’re ready to build amazing games with CORP! Continue with Core Concepts to deepen your understanding.