Starbeamrainbowlabs

Stardust
Blog


Archive


Mailing List Articles Atom Feed Comments Atom Feed Twitter Reddit Facebook

Tag Cloud

3d 3d printing account algorithms android announcement architecture archives arduino artificial intelligence artix assembly async audio automation backups bash batch blender blog bookmarklet booting bug hunting c sharp c++ challenge chrome os cluster code codepen coding conundrums coding conundrums evolved command line compilers compiling compression conference conferences containerisation css dailyprogrammer data analysis debugging defining ai demystification distributed computing dns docker documentation downtime electronics email embedded systems encryption es6 features ethics event experiment external first impressions freeside future game github github gist gitlab graphics guide hardware hardware meetup holiday holidays html html5 html5 canvas infrastructure interfaces internet interoperability io.js jabber jam javascript js bin labs latex learning library linux lora low level lua maintenance manjaro minetest network networking nibriboard node.js open source operating systems optimisation outreach own your code pepperminty wiki performance phd photos php pixelbot portable privacy problem solving programming problems project projects prolog protocol protocols pseudo 3d python reddit redis reference release releases rendering research resource review rust searching secrets security series list server software sorting source code control statistics storage svg systemquery talks technical terminal textures thoughts three thing game three.js tool tutorial twitter ubuntu university update updates upgrade version control virtual reality virtualisation visual web website windows windows 10 worldeditadditions xmpp xslt

Happy Christmas!

A Random Snowflake

Happy Christmas!

Posts will resume in the new year.

I have a random snowflake generator for you that I wrote a while ago - my current project is taking longer than I thought :D

Edit: It can be found here Random Snowflake Generator).

Pepperminty Wiki: A Wiki in a box

Recently I found a post on reddit by someone called am2064 about a 'one file wiki' called 'Minty Wiki' written in PHP. I took a look and whilie it was cool, I found it to have some bugs in it. I also found that it needed an extra PHP file to parse markdown to make it work properly. Still, I thought it was a cool idea so I decided to have a go myself.

694 lines of code later, I had something that worked and I thought that I might post about here on my blog. It is by no means finished, but it is in a somewhat usable (hopefully secure) state. I decided that markdown was the most logical choice for editing pages, so I modified Slimdown (by Johnny Broadway) to add internal link parsing and tweaked the bold/italics code to be mroe like Gmail's chat amongst other things. I first found Slimdown when looking for a lightweight markdown parser for comments on this blog.

I named my creation 'Pepperminty Wiki' (after the wiki that gave me the idea). It currently allows you to create and edit pages (although you need access to the server's files to delete pages currently), list all current pages, and view a printable version of a page. It even has a 'search' box that allows you to type in the name of the page you want to view. The search box has an HTML5 <datalist> to provide the autocomplete functionality.

To use it yourself, simply download index.php in the github repository below and put it in a folder on your server. Make sure that you have enabled write access to the folder though, or else you will start to see to rather strange error messages :)

To configure it, simply open the file you downloaded with your favourite text editor. You will find the settings (along with an explanation of each) at the top of the file. Make sure that you change the usernames and passwords!

You can find it on github here: Pepperminty Wiki

A (uneditable) version can be found here: Demo

Soon I will write up a technical post about my efforts to improve the performance of Pepperminty Wiki.

Imaanvas!

Today marks the release of a larger project that I have been doing, called Imaanvas. It has been in the works for months and is meant to be a web based version of a program called MSW Logo, which is now called FMS Logo. It has a few tweaks, though, to make it slightly easier to use. It was orignally written for a year 5 class in a primary school.

It also does not come with all the commands present in Logo, so if you find that a command is missing please comment below and I will try to add it for you as soon as I have some spare time. (You can also write the command yourself, and I can add it that way, but will probaby need the original source code for that - gulp is used to compact the code - send me an email if you want the code)

Immanvas is a horribly complex piece of code - so if you encounter any bugs (which is likely), please either leave a comment below, or send me an email. Remember to be descriptive about the bug that you have found, otherwise I won't be able to track it down and fix it! Also remember that Imaanavs is meant for modern browsers, so if Imaanvas doesn't work in your browser, try upgrading it to it's latest version.

This post is late since essential maintenance work had to be carried out to try and reduce the amount of spam that is being posted.

Behind the Parallax Stars

Unfortunately I have been busy, so I have been unable to write this post up until now. Anyway, welcome to the second technical post on this blog. This time, we will be looking behind the Parallax Stars.

The FPS and rendering time graphs are drawn by a slightly modified version of stats.js, by mrdoob. It's original github repository can be found here, and the slightly modified version can be found here. The modifications I made allow both the FPS graph and the rendering time graphs to be displayed at once.

The interesting code that makes the stars work is found in stars.js. The function is a constructor that returns an containing everything needed to make the stars appear and animate.

this.build = function() {
    this.data = [];

    for (var i = 0; i < this.number; i++)
    {
        this.data[i] = new star();
    }

    if(this.depthsort == true)
    {
        this.data.sort(depthsort);
    }
};
function star()
{
    this.z = Math.random()*(0.7) + 0.3;

    this.x  = rand(canvas.width);
    this.y  = rand(canvas.height);
    this.radius = Math.floor(this.z * 7);

    var r, g;
    r = rand(200, 255);
    g = rand(200, g - 20);

    this.colour = "rgb(" + r + ", " + g + ", " + 0 + ");"

    this.speed = this.z * 3;
}

The build() function contains some setup code that populates an array with stars, which are constructed by a different function, star(). Each star is assigned an x, y, and z co-ordinate. The x and y co-ordinates determine it's position on the screen. and the z co-ordinate determines it's size and speed. The stars are also given a colour too. The function rand() is a small utility function I sometimes use for generating random numbers:

// EXAMPLES:
// rand(256) returns a whole number between or equal to 0 and 255
// rand(100,201) returns a whole number between or equal to 100 and 200
// rand() returns a decimal between or equal to 0 and less than 1
function rand()
{
    // takes 0-2 arguments (numbers)
    var args = arguments, num;
    if (args[0] && !args[1]) { 
        num = Math.floor(Math.random()*(args[0]));
    } else if (args[0] && args[1]) {
        num = Math.floor(Math.random()*(args[1]-args[0])) + args[0];
    } else {
        num = Math.random();
    }
    return num;
}

The array that hold all the stars is also depth sorted before we start and on each frame to keep the stars in order since stars are leaving the screen and new one coming onto the screen on every frame. The standard array .sort() function is used, along with a custom sort function:

function depthsort(a,b) {
    if(a.z < b.z)
        return -1;
    if(a.z > b.z)
        return 1;
    else
        return 0;
}

The updates that happen every frame are split into two different functions. step() deals with incrementing co-ordinates and keeping the depth sorting up to date, and render() takes the current state and renders it on the canvas.

this.step = function() {
    for (var i = 0; i < this.data.length - 1; i ++)
    {
        this.data[i].x += this.data[i].speed;

        if(this.data[i].x > canvas.width + this.data[i].radius + 1)
        {
            this.data[i].x = new star();
            this.data[i].x = -this.data[i].radius - 1;

            if(this.depthsort == true)
            {
                this.data.sort(depthsort);
            }
        }
    }
}

The this.data array holds all of the stars. For each star, it's x value is incremented by it's speed. If this moves the star off the screen, we replace it with a new star that starts off at the left hand side. The stars are then depth sorted again to keep all the further away stars behind the stars that are (supposed to be) closer to the front.

this.render = function() {
    context.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < this.data.length - 1; i ++)
    {
        context.globalAlpha = 1;
        context.globalCompositeOperation = "destination-out";

        context.beginPath();
        context.arc(this.data[i].x, this.data[i].y, this.data[i].radius, 0, Math.PI*2, true);
        context.closePath();
        context.fill();

        context.globalAlpha = this.data[i].z;
        context.globalCompositeOperation = "source-over";

        context.fillStyle = this.data[i].colour;

        context.beginPath();
        context.arc(this.data[i].x, this.data[i].y, this.data[i].radius, 0, Math.PI*2, true);
        context.closePath();
        context.fill();
    }
}

To start off the rendering, the canvas is cleared. After that, For each star, a hole in the canvas is cleared with the destination-out drawing mode. The reason for this is that the z co-ordinate is also used as an alpha value for each star to make it dimmer the further away it is. This gives a slightly more realistic 3d appearance. After clearing a hole, the drawing mode is rest to the default (source-over), and the alpha and fill colours are set up according to the star's current z co-ordinates and colour respectively. Then the star is drawn. Since when this script was written we did not have a canvas drawing function to draw an ellpise, the context.arc(this.data[i].x, this.data[i].y, this.data[i].radius, 0, Math.PI*2, true); code is used to draw circles via context.beginPath() and context.fill().

Finally, One nice neat update() function is provided that calls render() and step() in sequence:

this.update = function() {
    this.render();
    this.step();
}

That concludes this technical post! If you have any questions, please post them below and I will try my best to answer them.

How the trianglfier works

This technical post will be all about how the recently released Image Trianglfier works.

The visible <img /> element that shows the original image has a function called drawimage() attached to it's load event such that every time a new image is selected, it updates the first of two invisible <canvas> elements:

The above code takes the newly loaded image, calculates new dimensions for the image if either side of the image exceeds 1000 pixels, and draws it to the imagecache canvas.

When the render button is clicked, a second <canvas> with an id of main is put to work:

After grabbing a few references to the main canvas (the one we want to draw the image on) and the imagecache canvas (the one with the scaled original image on it), we then extract the pixeldata of the imagecache canvas on line #5 of the gist so that we can use it to out colours for each triangle later.

We then enter a for loop and start drawing triangles. A triangle is drawn by picking 3 random points within a box with a diameter set by the trianglesize setting, and setting these to be the 3 vertices. The central point of the box is picked on lines #17 and #18, and the 3 points are picked on lines #20 through #33.

The colour of the triangle is also set at this point by averaging the colour in a box centred on the central point we picked on lines #17 and #18. This boxes size is set by the coloursampleradius setting. The algorithm is passed the pixeldata we extracted earlier, along with the canvas size, the coordinates of the centralpoint, and the box's diameter and calculates the average by simply adding up all the colour components of each pixel in the box and dividing it by the number pixels it added up the components of. This algorithm is not particularly optimised and is one of the main causes for the hanging that occurs during the rendering process. This algorithm can be found here.

After the colour and point coordinate calculations, all that is left to do is draw the triangle itself. This is done on lines #36 to #42.

After all the triangles have been drawn, the rendering is complete. The finished image is then converted into a jpeg image is displayed on the right hand side.

Got a question? Spotted a mistake? Leave a comment below.

Suggestions for improvement are always appreciated

Image Trianglifier

A sample trianglfied image

Along with the new site design, I have released a small project of mine - an image trianglifier. Although it has a weird name (that is even more difficult to spell!), it's function is quite simple: It draws a customisable number of triangles on an image of your choice.

You can find it here.

To use it, simply drag an image onto the page or click "Choose file". When the image has loaded, your image will appear in the left. Click the render button to trianglify your image. The image size is limited to 1000 pixels due to a bug that crashes chrome when you try to render large canvases to a file. If anybody has any idea how to fix this, please leave a comment below.

You can also change the settings at the right hand side in the dat.gui interface. Each setting is explained beifly below:

Property Description
iterations The number of triangles drawn.
trianglesize The size of the bounding box in which each triangle is drawn.
coloursampleradius The size of the area from which an average colour is picked for each triangle. Warning: Setting this to a high value can cause lots of lag!
render Render the image and display the result to the right.

More information about each setting can be found by clicking "Click to toggle description" below the blue box. Still don't have an answer to your question? Leave a comment below.

Suggestions for improvement are always appreciated.

Art by Mythdael