Manyland

The Changer type lets you freely convert creations. For instance, you could create a Changer that shrinks a creation, desaturates it, blurs it, paints new things over it, or anything you can imagine. One you have a Changer in your collection, you can drag any creation that's yours (or clonable) onto it to generate a new spin off. You can also apply the Changer while creating by tapping it in the side panel.

Getting started with Changer code

To get started, just login, press Create, select the type Changer, and draw a bit for testing. To the right of the creator, you'll find a code window. Changers use JavaScript (many resources are available). Every Changer code requires a change function. It receives the data of the creation – its pixels, colors and more – which you can then change. The following example randomly sprays pixel colors all across the image:

function change(creation) { 
    var cellCount = creation.cells.length; 
    var width = creation.cells[0].length; 
    var height = creation.cells[0][0].length; 
 
    for (var cell = 0; cell < cellCount; cell++) { 
        for (var x = 0; x < width; x++) { 
            for (var y = 0; y < height; y++) { 
                creation.cells[cell][x][y] = getRandomInt(0, 10); 
            } 
        } 
    } 
     
    return creation; 
}

The output can contain the cells and colors, plus a name property.

Creation data structure

creation

Converting to full color

Instead of passing back a paletted image, you can also use the native function convertToFullColor and pass back each pixel as {red: 0-255, green: 0-255, blue: 0-255, alpha: 0-1}. The creation is then later reduced to a custom palette again:

function change(creation) { 
    convertToFullColor(creation); 
 
    var cells = creation.cells; 
    var width = cells[0].length;  
    var height = cells[0][0].length;  
    for (var cell = 0; cell < cells.length; cell++) {  
        for (var x = 0; x < width; x++) {  
            for (var y = 0; y < height; y++) {  
                cells[cell][x][y] = { 
                        red: 200, 
                        green: y * 10, 
                        blue: 100 + getRandomInt(0, 1) * 30, 
                        alpha: 1};  
            }  
        }  
    }  
 
    return creation; 
}

Native functions

The following functions are available in addition to JavaScript's native functions:

// True or false, depending on a chance of 0 - 100% 
chance(percent); 
 
// Returns a random integer from minInt to maxInt 
getRandomInt(minInt, maxInt); 
 
// Converts pixels from palette indexes to rgba: 
convertToFullColor(creation); 
 
// Returns a copy of the object so that 
// changes won't affect the original: 
cloneObject(object); 
 
// Limits a value into the numbers, 
// sets to minimum if not numeric: 
toLimit(value, min, max);

Showing a feedback message

You can return data.feedback = '...' to provide feedback:

function change(creation) { 
    if (creation.cells.length >= 2) { 
        // do something... 
    } 
    else { 
        creation = {}; 
        creation.feedback = 'This changer requires at least 2 cells'; 
    } 
    return creation; 
}

Sound

You can add a sound to Changers.

Examples

Blurring

The following applies a convolution filter like blur (also see this overview). What happens is we're stepping through the original image and look at a 3x3 grid of the old image for each position, to apply a certain weight and calculate the new pixel:

function change(creation) {  
    convertToFullColor(creation); 
     
    var blur = [ [1/9, 1/9, 1/9], 
                 [1/9, 1/9, 1/9], 
                 [1/9, 1/9, 1/9] ]; 
 
    var sharpen = [ [ 0, -1,  0], 
                    [-1,  5, -1], 
                    [ 0, -1,  0] ]; 
                                 
    applyFilter(creation, blur); 
 
    return creation;  
} 
 
function applyFilter(creation, matrix) {  
    var maxColor = 255;  
      
    var sourceCells = cloneObject(creation.cells);  
    var cells = creation.cells;   
    var width = cells[0].length;    
    var height = cells[0][0].length;  
      
    for (var cell = 0; cell < cells.length; cell++) {    
        for (var x = 0; x < width; x++) {    
            for (var y = 0; y < height; y++) {    
                  
                var red = 0, green = 0, blue = 0;  
                for (var xOff = -1; xOff <= 1; xOff++) {  
                    for (var yOff = -1; yOff <= 1; yOff++) {  
                        var weight = matrix[yOff + 1][xOff + 1];  
                        var sourceCell = sourceCells[cell]; 
                        var sourcePixel = sourceCells[cell][x][y]; 
                        if (sourceCell[x + xOff] && 
                                sourceCell[x + xOff][y + yOff] && 
                                sourceCell[x + xOff][y + yOff].alpha != 0) { 
                            sourcePixel = sourceCell[x + xOff][y + yOff]; 
                        } 
                        red   += sourcePixel.red * weight;  
                        green += sourcePixel.green * weight;  
                        blue  += sourcePixel.blue * weight;  
                    }                  
                }  
                 
                cells[cell][x][y] = {  
                        red: toLimit(red, 0, maxColor),  
                        green: toLimit(green, 0, maxColor),  
                        blue: toLimit(blue, 0, maxColor),  
                        alpha: cells[cell][x][y].alpha};  
            }    
        }    
    }  
}

Desaturating

Here, we're turning a creation into grayscale, and adding 'gray ...' to its name:

function change(creation) {   
    convertToFullColor(creation);  
  
    toGrayscale(creation);  
    creation.name = prefixName(creation, 'gray'); 
     
    return creation;   
}  
 
function prefixName(creation, prefix) { 
    var name = creation.name; 
    if ( name.indexOf(prefix) === -1 && 
            (prefix + ' ' + name).length <= creation.info.nameMaxLength ) { 
        name = prefix + ' ' + name; 
    } 
    return name; 
} 
  
function toGrayscale(creation, matrix) {  
    var cells = creation.cells;   
    var width = cells[0].length;    
    var height = cells[0][0].length;    
      
    var relativeLuminancePerception = {  
            red: 0.2126, green: 0.7152, blue: 0.0722};  
      
    for (var cell = 0; cell < cells.length; cell++) {    
        for (var x = 1; x < width; x++) {    
            for (var y = 1; y < height; y++) {    
                var color = cells[cell][x][y];  
                var weight = relativeLuminancePerception;  
                var gray = weight.red   * color.red +  
                           weight.green * color.green +  
                           weight.blue  * color.blue;  
                gray = toLimit( parseInt(gray) );  
                color.red = gray;  
                color.green = gray;  
                color.blue = gray;  
            }    
        }    
    }  
}

More...

Also check out the main introductory help. Got a question which isn't answered here, or new ideas and feedback? Have a look here please.