How to Build Website like Codecademy

building

Interactive coding platforms are probably the most common way many people get started learning how to code. I used websites such as Codecademy, freecodecamp, and W3School a lot to learn to code and I have always been wondering how to build websites like these. There seem to be very few resources on this topic so I will share my approach on building the interactive JavaScript course on this site, basically by tons of trial and error.

Why I Build CsPlayground?

I am an educator based in Malaysia primarily teaching coding to secondary students. I am constantly looking for platforms to provide students with self-learning, interactive coding activities and most importantly being able to track their progress. I have tried using freecodecamp, codecademy, codecombat however they either do not have the progress tracking feature or relatively expensive to subscribe to. So, I built this website primarily for my usage, and hopefully, I could help other educators do the same thing at an affordable cost.

Framework

Csplayground is built entirely on Vue.js. Since I am most comfortable with this framework, I try to avoid any server-side logic and build most of them on Vue alone. This might not be the best way to do it but at least it works for now.

The Editor

Setting up the code editor is probably the easiest part. I use Ace editor – a embeddable code editor written in JavaScript. This is also the editor used in sites like Khan Academy and Codecademy. Setting up ace editor is straightforward, all you have to do is import the pre-packaged version of Ace editor. You can find the tutorial here and the NPM package here.

Running the Code

To get the code written in the editor, you can use the getValue() method of the editor’s instance.

let editor = ace.edit(element, {
    mode: "ace/mode/javascript",
    selectionStyle: "text"
})
editor.getValue(); // Get user code

Next, to execute the code, there are two options I discovered:

  1. Use JavaScript eval() on client side
  2. Send code string to server side and execute using Node vm module

Option no 1 is easy to implement however a quick search will show you every article why you should not use eval() in JavaScript because it allows users to run malicious code in your app.

Option no 2 is to setup up a server-side script on Node that evaluates the user’s code using the vm module. Since vm module evaluates code in an isolated sandbox, it has no context of the browser console. Hence, I need to override the sandbox console to capture the console.log arguments and return the results.

function hook_consolelog(callback) {
    var old_log = console.log;

    console.log = (function(write) {
        return function() {
            write.apply(console, arguments)
            callback.apply(null, arguments);
        }
    })(console.log)

    return function() {
        console.log = old_log;
    }
}

var result = [];
var unhook = hook_consolelog(function(v) {
    result.push(v);
});

My current codebase currently using the eval() method which I think is a bad choice so I am refactoring it to use vm module instead.

Console

One important feature of an interactive JavaScript platform is to display the console message onscreen. The way I implemented this feature is by overriding the console function to capture the arguments and display them on DOM. I override the console.error function as well as my submission correctness testing relies on assertions.

window.console = {
    log: (...data: any[]) => {
      // Display on DOM
    },

    warn: (...data: any[]) => {
      // Display on DOM
    },

    info: (...data: any[]) => {
      // Display on DOM
    },

    error: (...data: any[]) => {
      // Display on DOM
    }
  };

Submission Correctness Testing

To check the user’s code, I rely on two different tests – assertion and regex. Assertion tests are quite straightforward as I only have to append the assertion test to the user’s code. The caveat is that I could not evaluate any intermediate state of variables. For example, to check if a variable is assigned with the correct value:

// User code
var number = 6;
var number = 4;

// Code below this line is appended
assert(number === 4, "number should have a value of 4");

As shown above, assertion appended after the user’s code only able to check for the final value.

Next, to check for any specific way of coding, I use regex to do the testing. For example, if the activity requires the user to assign the number variable using the + operator:

const a = 3;
const b = 4;

// Assign number as a + b
let number =
assert(
    /let\snumber\s=\s*a\s*\+\s*b\s*;/.test(code),
    "assign number as a + b"
  );

If any of the assertion tests failed, the AssertionError will be caught by the custom console we overrode and display it onscreen. Doing assertion tests this way has a few downsides. For one, if the first assertion test failed, the rest of the code will not be evaluated and I could not provide the user with feedback on various test cases for that particular activity.

Afterthoughts

This project seems quite daunting to me at first but by solving one problem at a time now I able to make it work. There are still many improvements to be made. I’ve spent quite some time figuring out how to do this so I am sharing this with those who had no idea where to start. If you have any idea of how to make it better or any major flaw in my approach, feel free to connect with me on Twitter!

Binary Representation of Text

Most text characters are converted into binary using a code called ASCII (American Standard Code for Information Interchange). The first version of ASCII was published in 1963 and last updated in 1986.

ASCII contains 128 characters, which is enough for most English content. For example, the dollar sign ($) can be represented as binary code of 0100100 (decimal 36); as you can see, it is represented using seven bits of data.

ASCII, however, is not enough for everyone as we have many different languages that use different alphabets such as the Russian alphabet and Chinese characters. For that, a new code was created and it is called Unicode. This new standard assigns a unique number to every character in every language. Each unicode character can take up to four bytes.

Binary Representation of Images

image data representation

All data are stored as binary in computers. How images are represented in binary? To understand how images are stored digitally, first, we need to learn what is a pixel.

What is a pixel?

A pixel (short for picture element) is the smallest element of a display. It is a dot or square in an image that represents only one colour. If we take a close-up of any images, you can see that images are made up of many pixels. To produce a full range of colours, each pixel consists of three LEDs (red, green, and blue). By combining different intensities of the colours, each pixel can display up to 16 million colours, which is way more than 10 million colours the human eye can discriminate.

pixel example
By ed g2s • talk – Example image is a rendering of Image:Personal computer, exploded 5.svg., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=807503
By Kprateek88 – Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=4635158

Binary images (monochrome)

Now, let us start with binary images where pixels can have exactly two colours – black and white. Since each pixel only has two states, we can use a single bit to represent each pixel – 1 for white and 0 for black. Here is a 10 x 10 pixels image example generated using our binary image visualisation tool.

csplayground.io learning tools

Colour Depth

As demonstrated in the previous example, using 1 bit to represent each pixel can only provide two colour options. Naturally, we can increase the number of bits to represent each pixel and thus expand the possible colour options. For every additional bit we use to represent each pixel, the number of colour options doubles. The number of bits used to represent a single pixel is known as colour depth or bit depth.

1-bit: 2 colours
2-bit: 4 colours
3-bit: 8 colours

8-bit: 256 colours
16-bit: 65536 colours
24-bit: 16777216 colours

For example with 3-bit colour depth, we could create 8 colour variations for each pixel.

8-bit colour depth image

True colour (24-bit)

As of today, almost all computer and phone displays use 24-bit colour depth. The term true colour is often used to refer to all colour depths that are equal to or more than 24-bit. 8 bits each is used to represent the intensity of colour red, green, and blue. Using 8 bits for each colour, the value range from 0 to 255. 

binary 00000000 – decimal 0
binary 11111111 – decimal 255

Resolution

The resolution of an image refers to how tightly pixels are packed together. It is commonly expressed in pixels per inch (PPI). Higher resolutions mean that there more pixels per inch (PPI), resulting in more pixel information and creating a high-quality, crisp image.

Interactive tool

Hands-on generating images of different resolutions using different colour depths.

Colour Guessing Game – MIT App Inventor Tutorials

In this game, a RGB value will be generated randomly and player will need to select the correct colour based on the RGB value.

UI Components:
Label, Horizontal Arrangement, Button, Notifier

Blocks

Initialisation

In this project, we will break our code into two main functions:

generateQuestion – This function will generate the RGB values for the answer options, a random index as the correct answer, and the string for questionLabel
updateUI – This function will update the mobile app UI

When the main screen initialised, call the generateQuestion and updateUI functions

Generate Question

First, generate a number randomly between 1 to 3 and store it into the answer variable. This number will be the index of the correct answer.

Next, create a variable buttonColours to store the RGB values for all three buttons. Each RGB value is saved as a list with three numbers between 0 and 255, representing the intensity of red, green, and blue respectively. Essentially, buttonColours is a list with three lists.

Create a for loop that counts from 1 to 3. In each loop, generate an RGB value and push it into buttonColours. If the loop variable is equal to answer, generate a string with the RGB value and store it into the question variable.

Update UI

In updateUI function, update the background colour of all three buttons based on the value stored in buttonColours and the value of QuestionLabel.

Check Answer

Create a function checkAnswer to check if a user clicked the correct button. The checkAnswer takes a parameter and the argument is the index of button clicked. When the function is called, we first check if the clicked button index equals answer. If so, update the score. Else, reset the score to zero and display a dialog notifying the user the game is over. Next, call the generateQuestion and updateUI functions to start the next question. Finally, update the score label to display the latest score.

Complete Program

The Nim Game – MIT App Inventor Tutorials

Nim is a mathematical strategy game which two players take turn to remove any number from different piles. There are many variations of the game, in this tutorial, there will be three piles with number three, four and five respectively. The winner is the player who takes the last number.

UI Components:
Label, Horizontal Arrangement, Button, Notifier

Blocks

Start Game

Create three variables to keep track of the number in different piles and also a variable to keep track the player’s turn. This below example, updateButton procedure is created to update the text of all three buttons when any of the number changes. When RestartGameButton is clicked, reset the variables and UI.

Button Click

When user clicked any of the three buttons, we will use Notifier text dialog to ask for the number user will be taking away from the selected button. After user input a number, we will need to check for several invalid input conditions:

  1. Input number should be less than remaining number on the button
  2. input number should not be less than zero

If input is valid, we will then check for the winning condition. If the sum of all three piles is zero, then the player wins the game.

Above example shows only the logic for Button1, the same logic needs to be done for Button2 and Button3. If the winning condition is not met, update the isPlayerOne variable. We will also change the UI to indicate different player’s turn.

Complete Program

MIT App Inventor Generate QR Code Offline

This app will generate a QR code using string input by user. The QRCodeCreator extension was used for the QR generation. Add BarcodeScanner and File components to provide required dependency and permission for the app to function correctly.

Complete Program

Common Error

Failed resolution of: Lcom/google/zxing/ EncodeHintType

This error is caused by missing dependency. Solve this problem by adding the BarcodeScanner  component into your application

Error 908: The permission Write_External_Storage has been denied

Your application needs to ask for WRITE_EXTERNAL_STORAGE permission during initialization or runtime.

Permission name: android.permission.WRITE_EXTERNAL_STORAGE

If the access is denied even after permission is granted. Add the file component to allow storing and retrieving of files on your device.

Learn Kodular, Thunkable & App Inventor – Start with Programming Basics

learn-kodular-thunkable

The rise of low-code/no-code platforms allow anyone to easily create mobile apps. In the low-code/no-code mobile apps development space, three notable platforms are MIT App Inventor, Thunkable, and Kodular. Both Thunkable and Kodular originated from MIT App Inventor, hence they all have similar interfaces and mechanics on the app building process. MIT App Inventor is maintained by Massachusetts Institute of Technology for educational purposes while the latter two aimed to help users create commercial applications.

All three platforms use Google’s Blockly visual programming language as their foundation for app development. Even though no code needs to be “written” and the complex programming syntax is abstracted away with Blockly, users ought to understand the fundamental concepts of programming in order to achieve different results effectively. Here are some of the fundamental concepts in programming that will help you in your app building process:

  1. Variables & Data Types
  2. Operators
  3. Conditional
  4. Iteration / Loops
  5. Function / Procedure

You learn these programming concepts with our interactive Blockly programming platform.

Variables & Data Types

In computer programming, a variable or scalar is a storage location (identified by a memory address) paired with an associated symbolic name, which contains some known or unknown quantity of information referred to as a value.

– Wikipedia

You can think of variables as containers used to store information during a program execution. We can retrieve the information and reuse them throughout our program. Different programming languages have different ways of creating variables inside a program. In programming languages such as C, C++, and Java, data type of the variable need to be specified during creation and you will only be able to store the specified data into the variable. However, in Blockly we do not need to specify the data type and variable can be used to store any type of value. This is similar to programming languages such as JavaScript, Python, and PHP. Some of the basic data types in Blockly:

Primitive Data Type

  • String
  • Number
  • Boolean
  • null / undefined (special data types)

Composite Data Type

  • Object / Dictionary
  • Array / List
  • Function / Procedure (Not assignable in Blockly)

Examples of creating variables with different data types in Kodular.

Operators

Operators are used to perform mathematical, relational or logical operation. We can combine more than one math operator to perform a more complex calculation. Computation of result follows convention math precedence that is:

  1. Parentheses
  2. Exponents
  3. Multiplication and Division
  4. Addition and Subtraction

Mathematic Operators

Relational Operators

A relational operator is used to create conditional expression which will return a Boolean – either true or false. Using it with if statements, we will be able to create algorithms where program can make decision to execute different code based on the given conditional expression.

Conditionals

In programming, conditional statements are used to decide different computations at run time. There are several types of conditional statements:

  • if statement
  • if…else statement
  • if…else if…else statement
  • switch statement (not available in Blockly)

The if statement checks whether a given conditional expression evaluates to true, if so, the statement will be executed.

If the conditional expression of an if statement evaluates to false, then the else statement will be executed.

The else if statement adds another condition to check when the first if statement is false.

Iteration / Loops

In programming is used to repeat a block of code until a specific condition is met. There are two main types of loop:

  • for loop
  • while loop

A for loop requires an initialization statement to declare a loop control variable, a test statement to test against the variable and an increment statement to update the variable. The test statement will be evaluated after every loop and if it is true, the process repeat itself. In the example below, the code blocks in the for loop will be executed for 5 times.

A while loop allows code to be executed repeatedly until a given conditional expression is evaluated as false.

Function / Procedure

Even a simple computer program contains hundreds if not thousands of lines of code. Most of the time, part of these codes is repeated. Instead of typing out the same instructions over and over, we can group them into chunks called function or procedure. Value can also be passed into a function as variables, they are also known as parameters.

Function can have return values – the values that a function returns when it has completed.

Conclusion

In order to develop any logic in your mobile app using either Kodular, Thunkable or MIT App Inventor, understanding the basic concepts of programming give you the ability to achieve it effectively. Diving in without the fundamentals is like solving complex equations without know basic algebra. Our interactive block-based coding platform is designed to help students learn the fundamentals so that they have the skill to build more advance application.

Number Memory Game – MIT App Inventor Tutorial

memory-game-app-inventor

In this app, numbers will appear in a 4×4 grid for a certain amount of time. User needs to remember all the numbers and tap on the buttons according to number sequence from 1 to 16.

UI Components:
Label, Horizontal Arrangement, Button (lots of button 😱), Horizontal Arrangement, Clock, Notifier

Clock – Enabled (false), TimeInterval (5000)

Blocks

Generate Random Number Sequence

First, generate a list with incremental numbers from 1 to 16. Then, apply Fisher-Yates algorithm to shuffle the list to have random permutation.

Show Numbers when Game Start

When the start game button is clicked, generate the random number list and show the numbers on all 16 buttons from left to right.

Enable the clock when game start to start the timer. In this example, the time interval was set to 5000ms and once the Clock.Timer event called, disable the timer and hide all the text on buttons.

Finally, we need a variable to keep track of the button clicks and the number will be displayed using the top label.

Game Play

For each button click, increase the clickCount variable by one and check if the number on the button matches the number in our generated array based on its sequence. In below example, checkClick function will take in an argument which will be used as index to get the value in the generated list.

Complete Program

Drawing Canvas – MIT App Inventor Tutorial

Create a drawing canvas on app inventor that allows you to pick colour from all spectrum. In this app we will also add several drawing tools such as drawing straight line, circle, and rectangle. On top of that, you will be able to share your drawing through any other applications on your phone!

UI Components:
Horizontal Arrangement, Vertical Arrangement, Horizontal Scroll Arrangement, Button, Slider, Sharing, Canvas

All three sliders – Min value 0, Max value 255

Blocks

RGB Colour Mixing

All colours can be produced by combining red, green and blue. Each colour’s intensity is represented using a value between 0 and 255. In the project, three sliders are used to modify the intensity of each colour and when the value of any slider changed, we will display the resulting colour using the ColourButton and update the canvas paint colour at the same time.

Pen Tool

The variable tool is created to keep track of the drawing tool we are using so the functionality of each tool will not overlap. Update the tool variable when PenButton is clicked. When your user interacts with the canvas by dragging their finger on it, the Canvas.Dragged event will be triggered. Call the Canvas.DrawLine function if the tool in use is “pen”.

Eraser & Clear Tool

The clear button will clear the canvas which can be implement easily by simply calling the Canvas.Clear function.

In MIT App Inventor, there isn’t any function to erase paint on canvas. However, we can simulate the eraser effect by drawing lines with the paint colour set to the colour of your canvas.

Line Tool

Line tool is used to create a straight line on the canvas. First, use variables to store the coordinate when the user touch down on the canvas. When user release their touch on the canvas, join the coordinate at that point with the initial stored coordinate to form a line.

Circle Tool

To draw a circle using Canvas.DrawCircle function, we need to provide a value for circle radius. We will use the coordinate of touch down as the center of circle and the coordinate of touch up as the edge of circle. Then, calculate the radius by finding distance between two coordinates using formula below:

In this example, we created a function named calculateRadius, calculate the result and return it as an argument for the Canvas.DrawCircle function.

Rectangle Tool

Create a function named drawRectangle, that takes two diagonal points as arguments. We will able to create a rectangle using Canvas.DrawShape function by providing a list of all four points of a rectangle as below:

Share Drawing

When the function Canvas.save called, it will return the path where your drawing will be saved. We will then use the Sharing.ShareFile to share the file at the path.

Complete Program

Dungeon Whack – MIT App Inventor Tutorial

dungeon-whack-mit-app

We will build a game similar to the classic Whac-A-Mole game. The user will need to tap on the orc that shows up randomly on the screen within a limited time.

UI Components:
Canvas, Sprite, Label, Horizontal Arrangement, Button, Clock, TinyDB, Sound
Clock – Disable both clock by default

Assets:
Sprite image – https://csplayground.io/wp-content/uploads/2021/01/skull.png
Hit sound – https://csplayground.io/wp-content/uploads/2021/01/hit.wav

Blocks

Countdown Timer

The default value of CountdownClock’s time interval property is 1000, which means the event will trigger every 1000 milliseconds (one second). When the start game button clicked, we enable the CountdownClock to start the clock. Every time the clock event is triggered, update the countdown value on the screen and reduce the value of the counter. If the countdown value equals zero, disable the clock.

Moving the Sprite

Create a procedure and in the procedure, we move the sprite to a random X and Y position from 0 to the end of the canvas. Similar to the countdown timer, enable the MoveSpriteClock when StartGameButton click. In the MoveSpriteClock timer event, we call the moveSprite procedure. If the countdown equals zero, we stop the clock.

Updating Score

Create a variable to keep track of clicks on the sprite. Use the canvas touched event, check if the sprite is touched. If so, increase the value of the score and update the ScoreLabel. The touchedAnySprite parameter is a Boolean value.

Reset Game State

Create a procedure to reset the game states when prior to game starts.

Make Sprite Clickable Only During Gameplay

Create a variable with a Boolean value to keep track of the current state – started (true) or end (false). Add an if statement to the canvas touched event so that score will only be updated when the game has started. In the below example we used a compound operator AND to join two conditional expressions.

Update the game state when the countdown ends. Here, the code was refactored into a procedure.

Sprite Clickable Only Once Per Interval

Create a variable isHit to keep track if the sprite is hit within the time interval. Modify the canvas touched event so that the score will only be updated when all three conditions are satisfied.

Complete Program