Pi.js – Getting Started

In this post, I will be discussing the basics of the Pi.js JavaScript library. I will be using the Pijs.org editor to code. You can find it here: Pijs.org Editor.

Once you open the Pijs.org Editor, the first thing you should do is to create a new JavaScript file. You can do this by going to File -> Create new File. Select JavaScript for the File Type. Note that the pijs.org editor will create the HTML file for you when you run or download the project, and it will automatically include all of your scripts as sources.

In this example I will be naming the file "main.js" and it will be placed in the root folder. You do not need to enter an extension when creating the file name because the .js will be added by default.

Once the file has been added, you will see it in the upper left-hand side of the page. Note the green "x" next to the name, indicating that the file is an active file. This means that when you run the program, this file will automatically get included. If you uncheck it, it will no longer be green and it won't be included when you run the project, but it will still download when you click download project as part of the Project Settings.

Generally, the first thing you want to do when creating a pi.js project is to create a screen. Let's create a 300x200 screen and print our "Hello World" project.

$.screen("300x200");
$.print("Hello World");

Press Ctrl+R to run it. You will see the output on the screen.

Let's update our project settings so that the default run browser will fit the same aspect ratio as our screen. We will update the project to 900x600.

Now, let's make a simple guessing game.

$.screen("300x200");
$.print("Welcome to the Guessing Game!\n", false, true);
$.input("Guess a number between 1 and 100: ", function (guess) {
    $.print("You guessed " + guess);
} );

In the print statement, we added a "\n" at the end, meaning we want an extra space. We also added two parameters. The second parameter is false, meaning it will not be inline, and the third parameter means we want the text to be centered on the screen. We then prompt the user to guess a number between 1 and 100. In this statement, we pass in a function that gets called after the user enters their number, and we print that number.

Press Ctrl+R to run it. You can see the "Welcome" text is centered now, and there are two new lines before the prompt. Enter a number, and it returns your guess.

Now let's add an answer and see if the user can guess it.

$.screen("300x200");
$.print("Welcome to the Guessing Game!\n", false, true);
let answer = Math.round(Math.random() * 99) + 1;
$.input("Guess a number between 1 and 100: ", function (guess) {
    $.print("You guessed " + guess);
    if(answer === guess) {
        $.print("You guessed correctly!");
    } else {
        $.print("Wrong, guess again.");
    }
} );

Here we have added the answer which is a random number between 1 and 100. Then we let the user guess the answer, but they only get one guess. To implement another guess, we could do a bunch of nested input methods with callbacks, but that would be ridiculous.

One thing I don't like about this code is that with the callback function in the input, it is kind of messing with the flow of our program. Let's try another approach to make this easier to deal with.

$.screen("300x200");
$.print("Welcome to the Guessing Game!\n", false, true);
guessingGame();
async function guessingGame() {
    let answer = Math.round(Math.random() * 99) + 1;
    let guess = -1;
    while(guess !== answer) {
        guess =  await $.input("Guess a number between 1 and 100: ");
        if(answer !== guess) {
            let hint = "too high";
            if(guess < answer) {
                hint = "too low";
            }
            $.print("Wrong, " + hint + "!");
        }
    }
    $.print("You guessed correctly!");
}

This is much better. Here we have everything happening sequentially all laid out in one function. You have to add the keyword “async” in order to make this work because this is a requirement in JavaScript in order to use the "await" keyword. What is going on is that the $.input function is returning an object called a promise, I won’t go into detail about promises here but the value in the assignment on the left hand-side, the guess variable, when used with the await keyword won’t contain the promise but it will have the ultimately be the value that we want, the guess. Just remember, that await and async must go together or this won’t work.

Now we also have a loop here so the user can make as many guesses as they need until they get the right answer. We're also giving them a hint if they are too high or too low.

There is one problem with this code. And that is the guess is a string and not a number so let's fix that.

guess = await $.input("Guess a number between 1 and 100: ", null, true, true, false);

Here I’m telling the input first, that I don’t have a callback so that value is null, then I pass true to set it to a number, and true to set it as an integer, and finally I set false so that there are no negative numbers. This means that I can’t enter any decimal values or string values, and the value will be converted to a number after the await.

In the final step let's add some sound.

$.screen("300x200");
$.print("Welcome to the guessing game!\n", false, true);
guessingGame();
async function guessingGame() {
    let answer = Math.round(Math.random() * 99) + 1;
    let guess = -1;
    while(guess !== answer) {
        guess = await $.input("Guess a number between 1 and 100: ", null, true, true, false);
        if(answer !== guess) {
            let hint = "too high";
            if(guess < answer) {
                hint = "too low";
                $.play("SQUARE V20 T140 O2 L8 CDGAB");
            } else {
                $.play("SQUARE V20 T140 O4 L8 CDGAB");
            }
            $.print("Wrong, " + hint + "!");
        }
    }
    $.print("You guessed correctly!");
    $.play("SQUARE V20 T120 O4 L16 CEG>C< T240 O5 L16 CEG>C< T480 O6 L16 CEG>C<");
}

Now we have successfully added sound effects to the guessing game using Pi.js.

The play method in Pi.js is a powerful tool for generating sound effects and music in your JavaScript projects. By using note values, you can create unique melodies and soundscapes to enhance the user experience of your application.

Making a Thumbnail for Pi.js Youtube Intro Video

I was working on my thumbnail image in my favorite paint program Paint.net and I was struggling to get it to look just right. Then the idea came to me that I should create the thumbnail with Pi.js. So that's what I did. The following is a step by step instructions on how I did that.

The first step was I download a font that I liked from OpenGameArt.org and found a CC0 licensed font from a creator that goes by the name gnsh. Thanks gnsh! Then I went to Editor and started to work.

I started my code by creating a new screen with the dimensions of 320x180. I chose this size because it scales up to the Youtube recommended size: 1280x760 nicely.

$.screen( "320x180" );

Then I loaded my fonts. Notice that the fonts need a string to load up with the characters in the image. The order matters here.

Fonts

// A list of characters included in my fonts
var chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]" +
  "^_`abcdefghijklmnopqrstuvwxyz{|}~";
// My font images
var font1 = $.loadFont( "fonts/gnsh-bitmapfont-colour8.png", 5, 12, chars );
var font2 = $.loadFont( "fonts/gnsh-bitmapfont-colour2.png", 5, 12, chars );
var font3 = $.loadFont( "fonts/gnsh-bitmapfont-colour5.png", 5, 12, chars );

Then I loaded my other images.

// Other images
var stars = $.loadImage( "images/stars.png" );
var mario = $.loadImage( "images/mario.png" );
var sonic = $.loadImage( "images/sonic2.png" );
var pi_logo = $.loadImage( "images/pijs-logo2.webp" );

The next thing I needed to do in the code is to wait for the images to get loaded. You can't draw an image until it gets loaded. But thankfully the Pi.js has a convenient function for that called ready.

$.ready( function () {
	// Code to be run goes here
} );

Once my images are loaded I'm ready to draw them. I scaled mario smaller by 0.75 and scaled up sonic by 3x. Check out the drawImage command to see what all those parameters are.

// Draw images
$.drawImage( stars, 0, 0 );
$.drawImage( mario, 15, 80, null, null, null, null, 0.75, 0.75 );
$.drawImage( sonic, 190, 50, null, null, null, null, 3, 3 );

After that I draw an ellipse and my logo.

// Draw an ellipse in the top left corner of the screen
$.ellipse( 5, 5, 53, 40, "white" );
$.drawImage( pi_logo, 0, -5, null, null, null, null, 0.5, 0.5  );

Then finally I print my text.

// Print the Pi.js text at the top center
$.setFont( font1 );
$.setPosPx( 0, 12 );
$.setFontSize( 10, 24 );
$.print( "Pi.js", false, true );
// Print the main text
$.setFont( font2 );
$.setFontSize( 10, 24 );
$.setPosPx( 0, 60 );
$.print( "Make Classic Retro", false, true );
$.print( "Games With This New", false, true );
$.print( "JavaScript Library", false, true );
// Print over the word New for emphisis
$.setFont( font3 );
$.setFontSize( 10, 24 );
$.setPosPx( 0, 84 );
$.print( "                New", false, true );

Here is the final code. It's important to note that I changed the $.loadImage and $.loadFont string parameters from "images/..." to "/images/..." and "fonts/..." to "/fonts/..." this is so that it will run this example from this page here. But if you are using the Editor and upload files into a subfolder it will have to be in the format of "images/...".

$.screen( "320x180" );
// A list of characters included in my fonts
var chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]" +
  "^_`abcdefghijklmnopqrstuvwxyz{|}~";
// My font images
var font1 = $.loadFont( "/fonts/gnsh-bitmapfont-colour2.png", 5, 12, chars );
var font2 = $.loadFont( "/fonts/gnsh-bitmapfont-colour8.png", 5, 12, chars );
var font3 = $.loadFont( "/fonts/gnsh-bitmapfont-colour5.png", 5, 12, chars );
// Other images
var stars = $.loadImage( "/images/stars.png" );
var mario = $.loadImage( "/images/mario.png" );
var sonic = $.loadImage( "/images/sonic2.png" );
var pi_logo = $.loadImage( "/images/pijs-logo2.webp" );
$.ready( function () {
	// Draw images
  	$.drawImage( stars, 0, 0 );
	$.drawImage( mario, 15, 80, null, null, null, null, 0.75, 0.75 );
	$.drawImage( sonic, 190, 50, null, null, null, null, 3, 3 );
	// Draw an ellipse in the top left corner of the screen
	$.ellipse( 5, 5, 53, 40, "white" );
	$.drawImage( pi_logo, 0, -5, null, null, null, null, 0.5, 0.5  );
	// Print the Pi.js text at the top center
	$.setFont( font1 );
	$.setPosPx( 0, 12 );
	$.setFontSize( 10, 24 );
	$.print( "Pi.js", false, true );
	// Print the main text
	$.setFont( font2 );
	$.setFontSize( 10, 24 );
	$.setPosPx( 0, 60 );
	$.print( "Make Classic Retro", false, true );
	$.print( "Games With This New", false, true );
	$.print( "JavaScript Library", false, true );
	// Print over the word New for emphisis
	$.setFont( font3 );
	$.setFontSize( 10, 24 );
	$.setPosPx( 0, 84 );
	$.print( "                New", false, true );
} );

Introducing Pi.js – a JavaScript library

Introduction

Pi.js is a new JavaScript library that has been designed specifically for creating retro games and apps with retro graphics. It's inspired by QBasic and is easy to use, making it ideal for those who want to create retro-style games without having to learn complex programming languages. In this article, we will take a closer look at Pi.js and explore its features.

Features

Pi.js has a range of features that make it an ideal choice for those who want to create retro-style games and apps. One of its most notable features is its graphics, which are designed to emulate the graphics of old-school games. This gives users the ability to create games with a nostalgic feel, while still taking advantage of modern programming techniques.

Another great feature of Pi.js is its sound capabilities. The library has a range of sound effects and music that can be used to enhance the gaming experience. This allows developers to create games that are not only visually retro, but also audibly retro.

Input functions are also included in Pi.js. This means that developers can create games that are fully interactive, allowing players to control the game using a keyboard or gamepad. This makes Pi.js ideal for those who want to create games that have a true retro feel, but with modern input capabilities.

An image of some gamepads.

Procedural Programming

Pi.js is designed for procedural programming style, which makes it easy for developers to create complex games without having to worry about complex programming concepts. This style of programming is based on the concept of breaking down a problem into smaller, more manageable parts. This allows developers to create games that are both efficient and easy to understand.

Some procedural style of code.

Ease of Use

One of the biggest advantages of Pi.js is its ease of use. The library has been designed with simplicity in mind, making it accessible to developers of all skill levels. This means that even those who are new to programming can quickly learn how to use Pi.js and start creating retro-style games and apps.

Conclusion

Pi.js is a powerful JavaScript library that is ideal for creating retro-style games and apps. Its graphics, sound, and input functions make it easy for developers to create immersive gaming experiences, while its procedural programming style makes it efficient and easy to use. With Pi.js, developers can create games that evoke feelings of nostalgia, while still taking advantage of modern programming techniques.