Drawing random letters on a web page with blacksmith's ascii tongs.


Drawing with a pair of tongs is not as easy as it looks.

Today, I worked on a web user interface in color ascii. At the end I’ve got an ascii display system with a custom ascii cursor and a mouse-down “paint” interaction.

The DOM architecture is made up of multi <pre> elements as colored text layers. This avoids, for example, to wrap each letter in a <font> or <div> element which could tend to orient js scripting towards a complex dom/objects mapping. Besides, why not make it possible to superimpose the color text layers?

<pre class="black"></pre>
<pre class="red"></pre>
<pre class="green"></pre>
<pre class="yellow"></pre>
<pre class="blue"></pre>
<pre class="magenta"></pre>
<pre class="cyan"></pre>
<pre class="white"></pre>
...

On the javascript side I’ve got a time updated pair of arrays used to animate text and part what is definitely “painted” on the text-grid from whatʼs just passing through (like blacksmith’s tongs).

var layers = document.getElementsByTagName("pre")
var colors = []
var displays = []
...
function draw(){
    ...
    // setup display
    for( var i = 0; i < layers.length; i++ ){
        displays[i] = colors[i]
    }
    ...
    // apply to dom
    for( var i = 0; i < layers.length; i++ ){
        layers[i].textContent = displays[i]
    }
    // next frame
    setTimeout(function(){
        draw()
    },50)
}

Still in javacript, I’ve implemented a sort of ad hoc file format parser using js fetch requests to load ascii drawings in the above-mentioned system.

function load(file){
    var graphic = {}
    return fetch("./src/txt/interface/"+file+".txt")
    .then(response => response.text())
    .then(text => {
        text = text.split('\n')
        graphic.x = parseInt(text[0].split(',')[0])
        graphic.y = parseInt(text[0].split(',')[1])
        graphic.template = {}
        var color_index = false
        var color_layer = ""
        text.forEach((l,i) => {
            if(l[0] == '$'){
                if(color_index) {
                    graphic.template[color_index] = color_layer
                    color_layer = ""
                }
                color_index = l.substring(1)  
            }else{
                if(color_index){
                    color_layer += l+'\n'
                }
            }
        })
        graphic.template[color_index] = color_layer
        return graphic
    })
}

Which result in json objects like this :

graphic : {
    template: {
        8: "███_._███_._\n█-~_--°█°--_~-\n| |█████████| |\n█\\ `-.___.-'
            /█\n██`-._ ¤ `\\-'\n████/ `°\\ \\\n███( (██) )\n███| |██| |\n███| )██(
            |\n███| |████| |\n███| |████| |\n███| |████| |\n███| |████| |\n███|
            |████| |\n███| |████| |\n███| )████(
            |\n███||██████||\n███||██████||\n███||██████||\n███||██████||\n███||██████||\n███|
            )████( |\n███| )████( |\n███| )████( |\n███| )████( |\n███| )████(
            |\n███| )████( |\n███| )████( |\n███\\ \\████/ /\n████| )██(
            |\n████(/████\\)\n"i,
       15: "███_._███_._\n█-~███°█████~-\n██████████████|\n███`-.___████/█\n███████¤█`\\██\n
            ████/██████\\\n███(██(█████)\n██████|█████|\n██████)█████|\n█████|██████|\n
            █████|██████|\n█████|██████|\n█████|██████|\n█████|██████|\n█████|██████|\n
            █████)██████|\n████|███████|\n████|███████|\n████|███████|\n████|███████|\n
            ████|███████|\n█████)██████|\n█████)██████|\n█████)██████|\n█████)██████|\n
            █████)██████|\n█████)██████|\n█████)██████|\n█████\\██████/\n██████)████|\n█████/█████)\n\n"
    },
    x: 7,
    y: 1
}

From .txt files like this :

7,1
$8
███_._███_._
█-~_--°█°--_~-
| |█████████| |
█\ `-.___.-' /█
██`-._ ¤ `\-'
████/ `°\  \
███(  (██)  )
███|  |██|  |
███|  )██(  |
███| |████| |
███| |████| |
███| |████| |
███| |████| |
███| |████| |
███| |████| |
███| )████( |
███||██████||
███||██████||
███||██████||
███||██████||
███||██████||
███| )████( |
███| )████( |
███| )████( |
███| )████( |
███| )████( |
███| )████( |
███| )████( |
███\ \████/ /
████| )██( |
████(/████\)
$15
███_._███_._
█-~███°█████~-
██████████████|
███`-.___████/█
███████¤█`\██
████/██████\
███(██(█████)
██████|█████|
██████)█████|
█████|██████|
█████|██████|
█████|██████|
█████|██████|
█████|██████|
█████|██████|
█████)██████|
████|███████|
████|███████|
████|███████|
████|███████|
████|███████|
█████)██████|
█████)██████|
█████)██████|
█████)██████|
█████)██████|
█████)██████|
█████)██████|
█████\██████/
██████)████|
█████/█████)

foo, bar on the first line of the .txt file indicate the x,y anchor point from the ascii drawing. In the video above this is used to place the tongs in a position where the cursor is in the point of contact of the tongs when they move.

$foo indicate the color layer in which the following characters must be placed until the next $foo

$0 black           
$1 red             
$2 green           
$3 yellow          
$4 blue            
$5 magenta         
$6 cyan            
$7 brightBlack     
$8 white           
$9 brightRed       
$10 brightGreen     
$11 brightYellow    
$12 brightBlue      
$13 brightMagenta   
$14 brightCyan      
$15 brightWhite

Hoping it will be comprehensible or at least bareable to read.

If you enjoy animated ascii art I strongly recommand you to check Stone Story RPG press kit which is full of amazing gifs.

You can also find gorgeous ANSI art archives from 90s to today on 16colo.rs

See you !

faure.adel@gmail.com

Comments

Log in with itch.io to leave a comment.

(+1)

This is going to be a hell of an experience (I mean that in a positive way) haha keep it going mate :)

Thanks, I'll try to ;)