All posts tagged with web

Bevy in the Browser!

July 08, 2021 - Søren Alsbjerg Hørup

After finishing “Some Tank Game” and posting about it I wanted to see how, if possible, I could port this to the web without replacing Bevy.

To get started, I spun up a fresh Bevy project to see if I could get rendering, kira audio, window management and Bevy UI to work in the browser.

It turns out I actually could!

hello bevy web

Source can be found here.

Firstly, not all of the features of Bevy is compatibile with the web, hence first step is to disable the default plugins when targeting web assembly.

This can be done through the Cargo.toml:

[target.'cfg(target_arch = "wasm32")'.dependencies] bevy = {version = "0.5", default-features = false, features = []}

Here we simply disable all optional features.

Secondly, Bevys default rendering backend does not support the Web, hence we need a ‘web specific’ plugin. Luckiliy, I found bevy_webgl2 which provides a webgl2 backend for bevy.

bevy_webgl2 = "0.5.2"

This dependency will pull in bevy_winit and thus allow for Window creation using a Canvas element, bevy_render for rendering and Bevy png support for png loading and displaying.

Thirdly, wasm-bindgen is used to generate the bindings for JavaScript and wasm-pack is used to compile a bundle targeting web using:

wasm-pack build --target web

My index.html simply loads the module as such:

<script type="module"> import init from './pkg/bevy_web_test.js'; var res = await init(); res.start(); </script>

One issue that a struggle with were the fact that my Canvas was fixed sized and unable to resize with the Window. I inserted some JavaScript to force the Canvas to a certain size, but this had no effect of the internals of Bevy - hence my stuff was not rendered properly.

winit apparently does not support this out of the box, so I implemented a web_canvas_resizer system that polls the dimensions of the window and ensures that the Bevy renderer has the correct size.

Lastly, I added a dependency to bevy_kira_audio and saw that kira more or less works out of the box in the browser. Only issue I had were the fact that Chrome will not play sound unless the Window has had some kind of interaction. I found this JavaScript snippet that works around the issue by tracking AudioContexts and ensuring they play when allowed to.

That’s is! Bevy is now running in the browser!

Next step for me is to merge these changes into some-tank-game-rs and see if I can get my game to run in the browser.

Bevy - A Rust Game Engine

March 29, 2021 - Søren Alsbjerg Hørup

In the past months I have been focusing on using the Rust programming language in relation to game development.

I wanted a setup where I could implement a game that could build for both native, such as Microsoft Windows, and WASM, targeting modern browsers such as Chrome.

To achieve this I have been working on a pet project called Blueprint. Intention with Blueprint was to create a Rust template that could be quickly generated using cargo-generate and that provided several features out of the box. Features included:

  • 2d and 3d rendering.
  • many thousands of sprites using VBO batching.
  • entity component setup using Hecs.
  • pre-defined systems such as movement system, physics systems.
  • multiple template games such as platformer, shooter, etc.

My primary motivation was a template where I could quickly prototype game ideas using Rust. Previously I have been using Typescript + PIXI.js or THREE.js. But since I am a huge Rust fanatic, I wanted to see if I could conjure up a similar setup using Rust + libraries such as winit, wasm-bindgen, glow, etc.

Recently however, I stumbled upon Bevy, a data driven game engine written in Rust. Bevy more or less ticks all the boxes above, except for WASM support. I want to build my games such that they can be quickly shared in the browser for other to see, thus WASM is a non-optional thing.

However, it seems that WASM support is a focus area of Bevy and it seems it is currently possible to run Bevy in the browser using webgl plugins, atleast if one uses the master branch of github and not version 0.4 currently published on

In any case. I have decided to put my own Blueprint project on hold and fiddle a bit with Bevy before continuing down a path which seems to be well underway by the community!

If all goes well, I can ditch my efforts on my own brewed Blueprint and make a Bevy template!

Scheduled Deployments for Netlify using Github Actions

June 02, 2020 - Søren Alsbjerg Hørup

I am working on a Gatsby site which sources my weight data from a google spreadsheet to generate a site which shows my weight trend. The spreadsheet is updated every morning, typically at 06:00, where I record my weight.

Netlify does not automatically build and deploy when the spreadsheet is updated, since Netlify does not know that the spreadsheet is updated. The simplest approach is to schedule a build and deployment of the Gatsby site every day, such that new weight data is automatically sourced, deployed and thus made public.

Netlify does not provide any means to schedule deployments. As far as I can see, Netlify only supports git push triggering and build hooks. Build hooks are an unique URL triggered by, e.g. Curl, starting a new build & deploy.

This hook can be called in a schedule manner, thus enforcing a scheduling of the build and deployment in Netlify.

The simplest approach I have found is to use Github actions to invoke the build hook with Curl. The following action calls the web hook every day at 8:00 UTC.

name: Every day

    - cron: "0 8 * * *"
    runs-on: ubuntu-latest
    - uses: actions/checkout@v2
    - name: POST hook
      run: curl -X POST -d {}{UNIQUE_HOOK_ID}

With this in place, Github will trigger a build & deploy in Netlify without requiring any push to the repository.

Migrated to Gatsby

May 21, 2020 - Søren Alsbjerg Hørup

I initially started this blog the 3rd of January 2017 on, which is a hosted / SaaS / platform of the open source WordPress CMS: I just needed a place to blog, nothing more and nothing less, with no clear requirements on plugins, speed nor look and feel.

Early 2020, I heard about GatsbyJS from one of our DevOps consultants, a static site generator that leverages React to generate “blazing fast sites”. GatsbyJS sources data from one or more data sources, transforms the data, exposes the data through GraphQL and generates one or more webpages using server side React that can be deployed to CDNs (Content Delivery Networks) such as Netlify, GitHub Pages, or any web server that can serve static files. In addition, the static pages are ‘rehydrated’ after rendering in the browser, allowing React to be used in the DOM even though the site is pre-rendered and served as ‘static’ files.

This has many benefits:

  • Serving HTML directly to the browser via a CDN is very cost-efficient, due to the distributed nature of CDNs and due to the static files being static and thus highly cache-able. This is harder to achieve when using server side generated pages, since a server is responsible for generating the pages upon requests from a browser.

  • The browser can ‘stream the resources into the DOM’ while downloading, to provide an early partial rendering of the page. This makes the speed of the website seem very fast, since the DOM is changing the moment the user enters the site. SPAs (Single Page Applications), such as many React apps, typically lack this behavior since they need to download a JavaScript bundle, manipulate the DOM and then display the resulting page, which can easily take a few seconds.

  • Compared to a SPA, since the page is statically generated, the initial DOM is contained in the HTML files and thus easier for Google and other search engines to traverse, increasing the ‘SEO Score’ of the site.

  • Dependent resources, such as images, can be transformed before being outputted to fit the generated page, e.g. a 4K image can be transformed to fit the 800px of a div without requiring manual image manipulation software.

There are drawbacks as well:

  • Since the site is ‘static’ no dynamic behavior from the server can be achieved, only DOM manipulation from a client side library such as React can change the page after initial rendering. GatsbyJS uses the re-hydrate feature of React to enable ReactDOM after the initial page rendering, but if the site is primarily consuming a data source which is server side, such as an SQL data source, React in the browser has no chance of consuming this and can thus not update the site.

  • Updating the site with new changes to the server side data sources requires a rebuild of the site and upload of all the static resources. This can easily take minutes when doing a big site, meaning that content update is not visible to the user before a new deployment (like the good old days :-P)

  • If using CDNs, there can be a delay between the upload of the site and the propagation through the network.

In any case, May the 11th I started migrating from to a ‘Gatsby generated site’. To achieve this, I had to do several things:

  • I needed to export and import all my WordPress blogs into a format GatsbyJS could understand. GatsbyJS can source data from Markdown and transform this into HTML, so I decided to leverage this functionality and convert all blog posts into Markdown using a mixture of homebrew and standard tools (a blog post on its own)

  • I needed to implement the blog using React and hookup the markdown data source. Luckily for me, the blog starter provided this out of the box: and I could simply copy and paste :-)

  • I needed to implement tag support, since this was not provided by the blog starter and my WordPress site uses tags.I had to extend the markdown with tags and extend the gatsby-node.js file such that ‘tag pages’ could be generated. (also a post on its own)

  • I wanted a look and feel similar to my WordPress site, so I made several smaller adjustments to the way the site was generated, with the primary adjustment being that all posts are served from /index.html including the content of the blog posts. Lucky me, the blog starter do lazy loading of all images so I simply output all blog posts without issues. This might not scale when I have 1000+ posts, but hey! that’s a problem for a future time.

  • I needed a simple way to update my site with new blog posts. A bit of googling and I found Netlify-CMS, an open source SPA that can be embedded into a site and be used to read and write markdown directly into GIT. (also a post of its own)

  • I needed a place to put my generated site. Initially I had chosen Github, but with the googling of Netlify-CMS I decided to tryout Netlify and host my site there.

  • Lastly, I needed to redirect my routes such that when I point to Netlify, Google gets a 301 in its face when asking for paths from the old WordPress site. Netlify supports the writing of a _redirects file, where one can redirect from X to Y, making it easy to enforce a redirect from the WordPress format to the new Gatsby format.

That’s it! My Gatsby blog is now alive.

Stuff I still need to do:

  • Fix some conversion errors in the old blog posts
  • Add the ‘about me’ page, which I have not yet moved from WordPress.
  • Improve look and feel a bit more after getting some feedback.
  • Improve SEO
  • Analyze the speed of the site and fix potential bottlenecks.


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, 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.


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.

VSync and Browsers (lack-of)

March 21, 2018 - Søren Alsbjerg Hørup

While developing my HTML5 game, LaserDefence, I stumbled upon vsync issues in Chrome - specifically that my game stuttered several times throughout the gameplay.

I tracked the issue down to the specific Chrome version installed as standard webview on Android 6.0 and I was able to fix the issue by compiling my HTML5 game using Crosswalk.

However, investigation of the issue showed that all browsers (more or less) have vsync issues. This has also been reported by, a site where one can test a browsers vsync capabilities.

For Chrome on Windows, vsync more or less works - i.e. no dropped frames, however on my Android phone a Galaxy S5 running 6.0 frequently showed dropped frames using Chrome. Other browsers exhibited similar issues.

According to, both Firefox and Chrome implement vsync “wrongly” meaning that dropped frames will happen resulting in stuttering in the gameplay and or animations.

One is met with the following messages when visiting from Firefox and Chrome:

“Firefox is hopelessly broken (timers/vsync/etc) — DO NOT USE!” “Google Chrome has VSYNC issues — You can help get Chrome fixed!”

Funny enough, Edge seem to be the browser which implements vsync properly, but even so, Edge does not support high refresh-rate displays which clearly puts the browser at a disadvantage compared to Chrome and Firefox.

As of 2018, no browser seem to implement proper vsync with high-refresh rate support. VERY disappointing considering that more applications are moved to the web, which includes graphical demanding applications.

Lets hope 2018 is the year where atleast Chrome and Firefox mets the quality test of…


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

I stumbled upon a cool tool named Nativefier which converts a website into a desktop application, i.e. wrapping it in an executable. Can be installed from NPM and invoked like so:

npm install nativefier -g nativefier

This downloads all resources from the URL and wraps these in an Electron application which can be distributed.

The resulting application is however a bit fat, easily consuming 90MB of storage. This is primarily due to Chromium and NodeJS being a part of Electron.


December 13, 2017 - Søren Alsbjerg Hørup

I recently encountered a problem with one of my many Azure services. The service in question provides an API to download files from a Azure file share; this worked perfectly on some endpoints but not on others.

It took me a while to nail the issue which was due to a violation of MinResponseData rate limit in Kestrel. On endpoints with a stable Internet connection, everything was OK, but on others were the Internet connection was less stable the download frequently failed.

Even if the endpoint had OK bandwidth, the download would still fail since the connection might be gone for a few seconds. According to the docs:

MinResponseDataRate: Defaults to 240 bytes/second with a 5 second grace period.

This can be disabled by

.UseKestrel(options => options.Limits.MinResponseDataRate = null)

Recharts vs Chart.JS

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

For my latest project I required about 50 x 250px x 250px charts on one page. Initially, I used Recharts because it looks freaking great and integrates nicely with React.

I quickly realized however that Recharts does not scale well because it is DOM heavy. For my applicaiton I quickly reached 12,000 DOM nodes. Loading performance is pretty bad when so many DOM elements needs to be initialized - however, the performance when initialized is actually OK.

In any case, I replaced Recharts with Chart.JS and saw a big performance improvement. My DOM nodes were reduced from 12,000 nodes to about 2000 nodes. Loading time was substantially improved and the performance of the application feels much better.

The biggest difference between the two charting components isthat Recharts is implemented using SVG elements while Chart.JS is implemented using a 2D canvas. The canvas only requires a single DOM node, while SVG requires several DOM nodes for data, chart configuration, etc.

In any case, for chart heavy applications with many charts, Chart.JS is my charting component of choice.

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:

This API is not yet implemented in all browsers, and I thought that I had to look elsewhere. But then I found this: 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", 
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 :-)

Google AMP

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

Google’s Accelerated Mobile Pages (AMP) has begun to see some widespread usage across the internet - atleast for the sites that I visit. I have always been skeptical regarding the AMP project, but I must admit that the AMP powered websites I visit using my phone are indeed fast to load.

AMP enabled pages are just HTML pages extended with AMP specific properties, such as amp-boilerplage and sets a number of restrictions to increase speed. The restrictions are however very restrictive, meaning that not all applications can be AMP enabled.

Restrictions include:

  1. No JavaScript apart from the JavaScript provided by AMP. Thats right, AMP powered pages cannot have homemade or third party JS.
  2. No input elements, i.e. no form support. AMP powered pages are one direction only.
  3. No external styles or inline styles, only style within a single style tag. In addition, the limitation for the style is 50kb.

Due 1. and 2., AMP targets to make content-heavy pages load very fast: news-sites, blogs, etc.

Google also provides AMP caches, where the content of a site can be loaded even faster. When googling for content on a smartphone or tablet, one can see that a site is AMP enabled by looking at the lightning icon. is obviously AMP enabled

Although I prefer to use AMP powered content on my phone, I do not believe this is the way forward. One should improve the performance of one’s one site using standard techniques, such as reducing the number of DOM elements and reducing the number synchronous scripts.

Todays site are typically very slow due to all the garbage that is pulled in from external sites. This includes ads and especially modal windows showing up and blocking the page.

Tagged: Web

Web.config Rewrite

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

Rewrite rules allow for rewriting an URL to another URI, e.g. accessing / can be rewritten as if the browser had access /abc. This is done on the server side, no 301 redirect is issued back to the client. This allows for prettier URLs.

A web project I am working on consist of a C# Web API 2.0 backend with a Javascript frontend. I wanted to keep all frontend stuff in the /Frontend folder while API stuff in the /Backend folder.

Looking from the perspective of the browser, I wanted that GET /api would rewrite everything to the C# Web API 2.0 backend, while GET / would rewrite everything to the /Frontend folder.

So when requesting e.g. /index.html, the server would rewrite the URL (behind the scenes) to /Frontend/index.html. Nice seperation IMO. This can be done from the Web.config file by writing two rules:

The first rule rewrites /api to /api and stops processing of further requests. This is needed such that the second rule is not processed.

The second rule rewrites /anything to /Frontend/anything, making it possible for me to save my frontend stuff inside the Frontend folder. Very nice indeed.