Skip to content

Your First Script

Let’s create a simple “Hello, World!” script that will be compiled to scrHello.gml. Here’s what we’re going to do:

  1. Create a new GML script in src/hello.ss.
  2. Write our “Hello, World!” code in it.
  3. Import the hello module to src/index.ss.
  4. Run bun run generate | npm run generate | pnpm generate to compile it.
  5. Open the compiled .out/scripts/scrHello/scrHello.gml to see the result.

We’ll use the inline project structure for this example. Your project should look like this:

  • Directoryyour-gamemaker-project // your GameMaker project folder
    • Directoryscripts/
    • Directorysrc/ // directory we’re going to use for ScaffScript
      • hello.ss
      • index.ss
    • package.json
    • scaff.config.*
    • your-gamemaker-project.yyp
  1. Edit the generate script in package.json to target the correct GameMaker project path.

    package.json
    {
    // --- snip ---
    "scripts": {
    "generate": "scaff gen ./my-game.yyp",
    "generate": "scaff gen ./your-gamemaker-project.yyp",
    "help": "scaff help",
    "scaff": "scaff"
    },
    // --- snip ---
    }

    The your-gamemaker-project.yyp should be the path to your GameMaker project file. For example, if your GameMaker project file is located at ./path/to/your/project/your-gamemaker-project.yyp, then the script should look like this:

    {
    // --- snip ---
    "scripts": {
    "generate": "scaff gen ./path/to/your/project/your-gamemaker-project.yyp",
    "help": "scaff help",
    "scaff": "scaff"
    },
    // --- snip ---
    }
  2. Let’s consider hello.ss as a module that exports a variable and a function. Basically, it’s like a self-contained unit of code that you can import and use in other files.

    src/hello.ss
    export var message = "Hello, World!";
    export function print_message() {
    show_debug_message(message);
    }
    • export keyword makes the variable/function available outside of the module, so that you can import it in other files.
    • var keyword declares a variable. For the var keyword, it’s the same as var in GML.
    • function keyword declares a function. It’s the same as function in a script asset in GML.
    • So, message variable and print_message function are both exported from the hello module, which can be imported in other files.

    If we create a tree structure to represent the code above, it would look like this:

    hello
    ├── var message = "Hello, World!";
    └── function print_message() {
    show_debug_message(message);
    }

    That’s your first module! Now, let’s import it in index.ss and see how it works.

  3. Create a new file named index.ss in the src/ directory. This file will serve as the entry point for our project.

    In this step, you can choose to either use import statement or include statement to import the hello module. But in reality, you would use both statements in different scenarios. For now, let’s see how to use import statement first.

    import statement is a general purpose statement to import modules. It’s used to import modules from other files, then you can use the imported modules with content directives.

    src/index.ss
    import { print_message } from "./hello"
    @content print_message
    print_message();
    • import keyword imports the print_message function from the hello module.
    • @content directive inlines the full compiled GML declaration of the print_message function at the current position.
    • print_message() calls the print_message function.
    • So, the index module imports the print_message function from the hello module, then calls it.

    The index.ss will look like this after compilation:

    src/index.ss
    import { print_message } from "./hello"
    @content print_message
    function print_message() {
    show_debug_message(message);
    }
    print_message();

    The example above only imports the print_message function, so the message variable is not imported. But of course, you can import it by adding message to the import statement.

    src/index.ss
    import { print_message, message } from "./hello"
    @content print_message
    print_message();

    It won’t affect the result, because we don’t use any content directives on the message variable. Let’s edit the code a bit to see how it works.

    src/index.ss
    import { print_message, message } from "./hello"
    @content print_message
    print_message();
    show_debug_message(@valueof message);

    The index.ss will look like this after compilation:

    src/index.ss
    import { print_message, message } from "./hello"
    @content print_message
    show_debug_message(@valueof message);
    function print_message() {
    show_debug_message(message);
    }
    show_debug_message("Hello, World!");
    • @valueof directive inlines the raw value of the message variable at the current position.
    • So, the show_debug_message(@valueof message); line is compiled to show_debug_message("Hello, World!");.

    include statement is short hand for import statement + @content directive. It’s used to inline the compiled content of a module at the point of the statement. See the difference between import and include for more information.

    Let’s see how to use include statement to import the hello module.

    src/index.ss
    include { print_message } from "./hello"
    print_message();

    The index.ss will look like this after compilation:

    src/index.ss
    include { print_message } from "./hello"
    function print_message() {
    show_debug_message(message);
    }
    print_message();
    • include statement inlines the compiled content of the print_message function at the point of the statement.
    • print_message() calls the print_message function.
    Inlining Multiple Exports in a Single include Statement
    Section titled “Inlining Multiple Exports in a Single include Statement”

    You can inline multiple exports in a single include statement. For example:

    src/index.ss
    include { message, print_message } from "./hello"
    show_debug_message(message);

    The index.ss will look like this after compilation:

    src/index.ss
    include { print_message, message } from "./hello"
    var message = "Hello, World!";
    function print_message() {
    show_debug_message(message);
    }
    show_debug_message(message);
  4. We’re not done yet with index.ss. We need to add an integration block and intg statement, so ScaffScript can integrate the compiled content to a specific asset.

    Let’s add an integration block and intg statement to index.ss. We’ll use the import statement and @content directive in this example.

    src/index.ss
    intg { main } to "./scripts/scrHello"
    import { message, print_message } from "./hello"
    #[main]
    @content print_message
    print_message();
    show_debug_message($"message is {@valueof message}");

    It will generate ./.out/scripts/scrHello/scrHello.gml that contains the compiled content of the main integration block.

    ./.out/scripts/scrHello/scrHello.gml
    function print_message() {
    show_debug_message(message);
    }
    print_message();
    show_debug_message("message is Hello, World!");
    • intg { main } to "./scripts/scrHello" statement maps the main integration block to the scrHello script asset.
    • #[main] integration block defines the content that will be generated and integrated to the scrHello script asset.
  5. Open your terminal in your project root directory, and run the generate script to compile the index.ss and generate the scrHello.gml file.

    Terminal window
    bun run generate

Congrats! You’ve just created your first ScaffScript script. You can check the generated GML code in the .out/ directory.

Optional: Integrating to GameMaker Project

Section titled “Optional: Integrating to GameMaker Project”

In ScaffScript, we have a feature to integrate the generated GML to your GameMaker project. It’s called GM Integration. You can activate it by setting noIntegration: false in scaff.config.cjs|ts.

scaff.config.cjs
module.exports = {
clearOutputDir: false,
noIntegration: true,
noIntegration: false,
production: false,
source: "./src",
tabType: "1t",
targetPlatform: "all",
useGmAssetPath: true
// other options...
};
  1. Open your terminal in your project root directory, and run the script with your package manager:

    Terminal window
    bun run generate
  2. Open your GameMaker project, and you should see a window similar to this:

    GameMaker IDE Reload Window

    Click the Reload button to reload the changes. After that, you should see the scrHello script asset in the GameMaker IDE.

  3. Open the scrHello script asset in the GameMaker IDE, and you should see the compiled GML code.

    scrHello.gml
    function print_message() {
    show_debug_message(message);
    }
    print_message();
    show_debug_message("message is Hello, World!");

    In the terminal, ScaffScript waiting your input whether to accept or revert the changes. Type y to accept the changes, or n to revert the changes.

    Terminal window
    [INPUT] Revert file scrHello.gml from scripts/scrHello? (y/N) ->

    Enter y to revert the changes, or just press Enter to accept the changes.

That’s how you integrate ScaffScript to your GameMaker project. You can check out the GameMaker Workflow for more information.