PostsAboutGames
All posts tagged with typescript

Babylon.js

March 20, 2020 - Søren Alsbjerg Hørup

I have always been a big fan of THREE.js, a 3D JavaScript library that abstract away some of the complexities of OpenGL. Recently, I tried another library, Babylon.js, written in TypeScript and ofcourse for the browser.

I found Babylon to be on par with THREE on all the areas I needed, except for Camera control where Babylon really shines with it’s built in support for many different types.

Looking at npmjs.com, it’s clear that THREE today the ‘go to library’ when doing 3D in the browser. Currently THREE has 304k downloads a week, while Babylon.js has less than 6k of downloads a week, clearly THREE is more popular.

Size wise, I have not done any test on the produced bundle. I find this absurd in today’s world, where a website does a million AJAX request to load commercials anyway…

The only reason I recommend THREE over Babylon.js is because of it’s popularity on npm. Else, go with any library - they both solve the three-dimensional problem equally well in my opinion.

TypeScript Readonly and Pick

April 28, 2019 - Søren Alsbjerg Hørup

An awesome feature of TypeScript is the ability to generate inferred types. C# supports this feature only for anonymous types, e.g.:

 var t = new { A = 1, B = "b" };

Creates a new object with an anonymous type having two members: A and B.

Similar can be done in TypeScript:

let t = {a:1, b:"b"};

Where t is also an anonymous type having two members: a and b.

TypeScript provides many advanced typing features that can be used to increase type safety.

An example are built-in generics such as Readonly and Pick.

Readonly is pretty simple, it takes a type and returns a new type where all properties are read only. Example:

let t = {a:1, b:"b"};
t.a = 2; // OK.

function makeReadonly<T>(t:T):Readonly<T>
{
   return t;
}

let tt = makeReadonly(t);
tt.a = 2; // not OK

The makeReadonly function simply takes a value of type T and returns the same value but changing its type to Readonly. This throws and error at compile time, thus stopping us from mutation the properties of the object.

Another great built-in generic is Pick. Pick allows us to construct a new type based upon the properties of another type.

Consider the following unsafe example, where we have a pick function that takes an object and returns a new object with only a single property taken from the original object.

let t = {a:1, b:"b"};
function pick<T>(t:T, property:string)
{
   let o = {} as any;
   o\[property\] = t\[property\];
   return o;
}
let o = pick(t, 'c'); // compiles, but c is undefined

Compiles but will fail at run-time since ‘c’ is not defined. This can be made much more type secure by introducing another generic K, which is a set of the keys of the object:

let t = {a:1, b:"b"};
function pick<T, K extends keyof T>(t:T, property:K)
{
   let o = {} as T;
   o\[property\] = t\[property\];
   return o;
}
let o = pick(t, 'c'); // no longer compiles!

Since c is not defined in T, the compiler throws an error. However, type safety is still not guarantee 100%. Consider this example:

let o = pick(t, 'a'); // compiles as expected.
let b = o.b;          // compiles, but b is not defined!

Since we picked ‘a’ from T, the compiler is OK on line 1. The compiler is also OK at line 2, since ‘b’ is defined in type T. However, this will fail at run-time due to ‘b’ not being defined. This can be fixed by using Pick!

let t = {a:1, b:"b"};
function pick<T, K extends keyof T>(t:T, property:K):Pick<T, K>
{
   let o = {} as Pick<T, K>;
   o\[property\] = t\[property\];
   return o;
}
let o = pick(t, 'a'); // compiles as expected.
let b = o.b;          // no longer compiles!

With the introduction of Pick, the function now returns a new Type containing a subset of type T. In the example above, we picked ‘a’ and thus generated a new type containing only ‘a’. The last nine now throws an error at compile time, since ‘b’ is no longer defined.

Using these built-in generics can in the end safe the day, with the added benefit of providing improved intellisense.

Material-UI for React

April 25, 2019 - Søren Alsbjerg Hørup

I have for a long time been a Bootstrap fanboy, but with the introduction of React into my developer life I have been looking for a good UI library that fits my needs.

Typically, I simply used Bootstrap and decorated my components with CSS from Bootstrap - but then I stumbled upon Material-UI a React component library that implements Google’s material design.

Available on NPM here: https://www.npmjs.com/package/@material-ui/core

One simply needs to install a single package which includes typescript definitions also:

npm install @material-ui/core

and if one wish to use the Roboto font, add a reference to it in the TSX or HTML:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />

With the package installed, we can use materialized components out of the box, by import, e.g.:

import {Button} from '@material-ui/core/Button';
import {Card} from '@material-ui/core/Card';
import {Dialog} from '@material-ui/core/Dialog';

https://material-ui.com/ has a lot of examples on how to use the different components.

With it’s 1 million weekly downloads, you can’t go wrong with this component library!

Apache Thrift - not a replacement for Protobuf *yet*

April 23, 2019 - Søren Alsbjerg Hørup

I frequently need to share typed structures between applications, such as between an ASP.NET C# Backend and an Typescript React single page application.

For this, I have used Google’s protobuf, a binary serialization library.

In protobuf, one defines the intended information in .proto files and uses a Protobuf compiler to auto generate language specific source files.

syntax = “proto3”; message Position { float x = 1; float y = 2; }

Here I define a message called Position, containing two simples float values: x and y. 1 and 2 denotes the order of which the fields appear during the serialization process - for backward compatibility reasons changing the name is allowed but changing the numbers are not since this will change the order on the wire!

Using a Protobuf compiler, such as protoc, language specific versions of the messages can be generated to fit the required language. For C#, the message above results in a class called Position with public Properties called X and Y, including several serialization methods and Properties such as WriteTo, MergeFrom and Parser.

For the web, protobufjs exists, which is a protobuf compiler implemented in JavaScript. This compiler can generate JavaScript and TypeScript source files to be consumed both in node.js and in the browser. I typically generate files for node.js and use a bundler such as parcel-bundler or webpack to bundle for the browser.

This provides binary transport of my messages from backend to frontend, with type security - very nice indeed.

Lately, I have looked into Apache Thrift, which is very similar to Protobuf but with support for many more programming languages out of the box, and with the added bonus of also supporting Remote Procedure Calls (RPC) . (although RPC can be achieved in Protobuf using gRPC)

The syntax of Thrift messages are very similar to Protobuf, the same message above would be written as:

struct Position { 1: double x, 2: double y }

Note: floats are not supported by Thrift, only doubles.

Looking at the supported languages, it seems to dwarf that of protoc (the default compiler of Protobuf) - with support for nearly 30 languages of the the box. Very nice indeed.

C# and TypeScript is also supported, making the Thrift a prime candidate for my typical needs. However, diving a bit deeper into what support means, it quickly shows that not all languages are equally supported, this includes TypeScript.

Generating browser compatible TypeScript that supports binary serialization is not supported. Node.js compatible TypeScript can be generated that supports binary serialization, but this generated code cannot be consumed by bundlers such as WebPack or Parcel Bundler. RPC is also not supported in the browser, although not required for the project in which I decided to test out Thrift.

Looking through NPM, I found “browser-thrift” - a patched version of node thrift that can be consumed by bundlers, only requiring that require(‘thrift’) is replaced with require(‘browser-thrift’) in generated thrift code.

After a few tries, I never got this approach to work and reverted back to using Protobuf.

Summary: Binary serialization is not natively supported by Thrift in the browser - making Protobuf the obvious choice until this is implemented in Thrift.

Parcel-Bundler

May 01, 2018 - Søren Alsbjerg Hørup

Parcel-bundler is a zero configuration web application bundler similar to webpack. It sports multicore compilation and filesystem cache for faster build times, with out of the box support for the most common file types.

Setting up a project using Parcel-Bundler for TypeScript + React is a piece of cake.

Simply create an index.html file which references the index.tsx file directly and invoking the following command from cmd:

parcel index.html

and we are off!

Build wise, parcel will automatically use index.html as entry-point, invoke the TSC compiler for the TypeScript source and include referenced CSS files in the build.

In addition, it will automatically host the bundle on port 1234 and do hot replacement upon changes to the underlying source.

Build wise, it is about twice as fast compared to webpack on my Quad core while sporting even faster build times during incremental builds.

Parcel-Bundler will definitely replace my use of Webpack on most of my projects.

Laser Defence

February 23, 2018 - Søren Alsbjerg Hørup

I implemented my first ever (finished) HTML5 game called Laser Defence.

I used PIXI.JS v4 and TypeScript for the implementation. Visual Studio Code was used as the IDE.

For fun, I wrapped the project into Cordova and published it to the Google Play Store:

https://play.google.com/store/apps/details?id=dk.hrup.laserdefence

I had some issues with consistent frame-rates using Cordova on my Galaxy S5 phone. The fix was to use the Crosswalk Cordova plugin. This plugin comes with its own Chromium instance, which is far superior to the default webview provided by Android 6.0.

The con is a fatter APK, about 20MB - but the pro is a much more consistent experience.

Screenshot of laser defence!

Reactstrap

September 20, 2017 - Søren Alsbjerg Hørup

Bootstrap is my favorite CSS framework and React is my favorite JavaScript library for frontend development.

Reactstrap combines the two, by more or less implementing all of Bootstraps CSS classes into React components.

Usage is super easy, just import the component one needs into a React project and use it as any React component:

import React from 'react';
import { Alert } from 'reactstrap';
const alert = (props) => { 
  return <Alert color="success">Success!!!</Alert> };

Nothing more to it.

When using TSX instead of JSX, one also gets type support which is super great when dealing with a huge project.

VSCode 1.14 and tasks

August 15, 2017 - Søren Alsbjerg Hørup

I recently started a new Electron Typescript project using version 1.14 of VSCode. Getting the task runner up and running using CTRL+B did not initially work, due to the fact that tasks.json is auto-generated as version 2.0.0 compared to version 0.1.0 which was the default in VSCode 1.13.

In addition, the new VSCode supports task auto-detection which confused the hell out of me due to it detecting tsconfig.json and asking me if I wanted to compile some typescript, even though my Tasks.json file was not yet created.

Apparently, MS added task-auto detection to the mainline during my vacation rendering tasks.json as an optionel part of a VSCode project. tasks.json is still required if one wish to create custom tasks or scan and parse the auto-detected tasks shell output.

This feature is great! since now I can make all my tasks in NPM without having to re-define them in tasks.json. VSCode can now detect these tasks automagically.

2017-08-15_08-53-02.png

Although I still have to add the tasks in tasks.json if I want to define the default task addition to allowing VSCode to scan for problems.

PolyK.JS

July 12, 2017 - Søren Alsbjerg Hørup

I needed a polygon library for my latest fun project (a TypeScript Build Engine). Google and NPM showed me the way to PolyK.JS, a very simple Polygon library that can do calculations on simple polygons, including Convex ones.

To my suprise, the library includes TypeScript  definitions making the lib super easy to consume for my application. Supported operations include:

  • GetArea Gets the area of the polygon.
  • Triangulate Triangulates the simple polygon
  • Slice Slices the polygon.
  • Raycast Finds the closest point on the polygon given the intersection of a ray.
  • ClosestEdge Finds the closest edge of the polygon.
  • ContainsPoint Checks if a given point is within the polygon.

The library assumes that the polygon’s vertices are defined in an number[] array of X,Y coordinates. Super easy to use and highly recommended!

Wolf3D using THREE.JS

June 26, 2017 - Søren Alsbjerg Hørup

I stumbled upon three.js and Javascript 3D library which abstracts away WebGL. I have always been a fan of OpenGL and WebGL, but I recently just wanted to get some 3D stuff to work in the browser without having to deal with the complexity of the WebGL statemachine - and shaders.

Three.js is just this, an abstraction ontop of WebGL which takes care of the lower level stuff while exposing objects such as Geometry, Texture, Material, Camera etc. Getting a 3D scene up and running with correct perspective is super easy if one has a basic understanding of 3D. Typings are also available for three.js, meaning full Typescript support.

For fun, I implemented a Wolf3D engine using the original textures and sprites using THREE.JS. The entire renderer code is less than 220 lines, and this includes alot of copy pasting and commented out experimentation. My guess is that the code could be leaned to less than 150 lines. Source available at GitHub: https://github.com/horup/wolfts

2017-06-26_07-43-54

Chart.js

March 09, 2017 - Søren Alsbjerg Hørup

In the past I have used D3.js and even Highchart.js for my charting needs. Today, I decided to tryout yet another Open Source alternative: Chart.js.

Chart.js is available through npm and @typings also exists for TypeScript fans such as myself:

npm install chart.js —save

npm install @typings/chart.js —save

Chart.js can be included with the script tag, CommonJs, ES6 and RequireJS. Although for HTML5 programming I always do the legacy route using script tag (I know.. I need to move with the tech).

Chart rendering happens in a canvas, nothing fancy DOM manipulation which I really like, especially when working with ReactJS. The chart look and feel is very generic, nothing fancy here.

I really like the tool-tips though:

chartjs.png

Chart.js is also responsive, thus scaling to different screen sizes. I have yet to tryout this feature though. Apart from this, it supports animation, multiple axis, mixed chart types, and more.

8 chart types are provided out of the box. Definitely recommended.

Browser saveAs

February 24, 2017 - Søren Alsbjerg Hørup

The latest feature request required the ability to export the data contained within an HTML table to a file on the disk. To do this, I looked at the W3C Writer API: https://www.w3.org/TR/file-writer-api/

This API is not yet implemented in all browsers, and I thought that I had to look elsewhere. But then I found this: https://github.com/eligrey/FileSaver.js/ an implementation of the W3C standard usable by modern browsers.

Including FileSaver.js into my document allows me to call saveAs as if my browser natively supported. Saving some text to disk is as simple as making a Blob with the text content, correct mime-type and then calling saveAs:

let blob = new Blob("text", 
{
 type:"text/plain;charset=utf-8"
});
saveAs(blob, "exported\_text.txt");

Using this in TypeScript requires the correct typings for saveAs. I didn’t find them for this project, I simply declared saveAs as any type:

declare var saveAs;

Super easy, and verified to work on my PC using latest Chrome and IE :-)

PixiJS Interactive

February 21, 2017 - Søren Alsbjerg Hørup

Interacting with Pixi v4 objects, such as mouse clicks or taps, can be done by setting the interactive flag to true. The documentation related to Pixi v4’s interaction was a bit scarce - it took me some time to figure this out.

obj.interactive = true;

This instructs the Pixi engine that the object can be interacted with. It is then possible to attach even handlers to the object:

obj.on("mousedown", (e:PIXI.interaction.InteractionEvent) =>
{
});

Similarly, when on a touch-enabled device, one can attach touch events such as touchstart:

obj.on("touchstart", (e:PIXI.interaction.InteractionEvent)=>
{
});

I had some issues regarding PIXI.Graphics where my touch/click events would not be registrered. The issue was due to the hitArea being zero. Apparently, one has to manually set hitArea on a PIXI.Graphics instances:

graphics.hitArea = new PIXI.Rectangle(0, 0, width, height);

PixiJS is really simple to use when it comes to its interactive abilities.

Shared Modules between Node and Browser

January 25, 2017 - Søren Alsbjerg Hørup

I am currently prototyping a game built using TypeScript + Node. Node will host some REST API’s + act as HTTP server + act as WebSocket server. The HTTP server part will host a React frontend also built using TypeScript.

What I want is the ability to share TypeScript code between the two parts of the application.Typically, I have always used outFile when working with React in the browser, because I find it very easy to embed into my index.html. This approach is however not feasable on the server side (it can be hacked, but is ugly as hell), since the server needs to import modules from node_modules using the ES6/TypeScript import syntax.

TypeScript supports the ability to emit ES5 JavaScript code using different module types, such as AMD, systemjs, etc. For this project I have experimented in using modules on both the server and the client portion of my code.

My structure is as follows:

  • /client contains all client related .ts files
  • /server contains all my server related .ts files
  • /library contains all my shared .ts files

This setup allows me to easily import modules from library in either client or server:

import someClass from "../library/someClass";

/client and /server has their own tsconfig.json file which tells the compiler on how to emit JavaScript code. On the /client, I have specified that I want to emit ‘AMD’ modules while on the /server I want to emit commonJS used by node.

When building, I invoke tsc on both /client and /server, which will emit more or less the same JavaScript output but where the module format differs. In the browser, I can easily include the AMD module loader and load all my stuff. I can even concatenate the output of the client (for my own modules) using outFile if I make sure to manually load the output in the browser before passing everything to the AMD module loader.

On the server, Node can use commonJS and require to load my modules without any issue, since I built the node part using commonJS as module loader.

The only con I have found is that /library directory gets compile twice, which is OK in my book since we are talking about different run-time environments (node vs the browser).

I need to test this setup a bit more, and see if it scales as well as I hope!

Debugging *this*

January 22, 2017 - Søren Alsbjerg Hørup

I recently had some issues with vscode and its TypeScript debugger when trying to read the content of the this variable. The debugger printout of the value of a variable when hovering above the variable - but the this variable was undefined.

I believed it was my closures that were not correct, thus making me replace all my functions with fat arrows. This was however not the case, since the application ran perfectly in node.

The issue turned out to be that this was not correctly source-mapped to _this. Recall that this within a TypeScript class is compiled to _this such that calling context issues are avoided. The debugger however failed to grasp the concept, making the mouse-over fail.

One has to manually expand the Closure in the debugger tab in vscode and look for _this if within a fat arrow calling context.

Visual Studio Code and Source Maps

January 20, 2017 - Søren Alsbjerg Hørup

It has been some time since I last required vscode’s JS debugging functionality. Today I ran into an issue using the latest version of vscode + TypeScript source mappings. Specifically, my debugger was unable to find the TypeScript source thus unable to hit any breakpoints.

I have all my TypeScript source saved into the /src folder. tsc compiles and stores the result into the /bin folder along with source mappings between the .js files and the .ts files.

My debugger was unable to locate the source files, even when the js.map files contained the absolute path to my src folder.

Apparently, one has to add outFiles to launch.json with a correct path to the /bin folder for this to work. vscode cannot automatically detect the the presence of map files along the out .js files. This is a bit puzzling, since my launch.json contains the path to the JavaScript file I want to launch.

"outFiles": \["${workspaceRoot}/bin/\*\*.js"\]

This snippet did the trick for me.

And yes! I know that /bin might not be correct naming since JavaScript files are not binary :-)