← Back to articles

spideysensi v.001

· by @Elout de Kok · View on fxhash · IPFS · 64 editions

eloutspideysensi

for latest updated version check : update: spideysensi v.2xxx

https://www.fxhash.xyz/article/spideysensi-v.2xxx

at the moment

.png supported only

and all images should be the same size!!else it throws an error
the canvas will scale, depending the first image it loads!

and you need to test it on a webserver, online.. or running a local apache like webserver
[since running it local from hd, and loading images from your hard-disk... drops a security error]

depending on use, i might add extra's upscalers etc. and special fx

work in progress!!
as welli

note: I did an update. spideysensi v.2 is out now! fixed some bugs. see link at top of page!!!


still archieved the old one: 
(that got a small .css error-warning at the start. that is fixed in the updated version! )

see it running
https://elout.home.xs4all.nl/drawz/spideysense001c/

download the big project .zip (including my images and all the source)
https://elout.home.xs4all.nl/drawz/spideysense001c/spideysense001c.zip

fxhash first raw test release
https://www.fxhash.xyz/generative/slug/spideysensi-v001c

what you need:

the index.html and the fxhash.min.js file
your images
and the script adjusted, [for now..by hand]  to set the correct names and numbers.. for the images you use
minimal animation, example;  dice

see it running
https://elout.home.xs4all.nl/2024/jun/dice/

download zipfile (1.87mb) with index and images
https://elout.home.xs4all.nl/2024/jun/dice/dice.zip
(you can also copy the source from the fxhash website and mod that next)

another simple example below

flamer

see it in action:
https://elout.home.xs4all.nl/2024/jun/flamer/
reload for a random combination

download project 22kb (.png images, index.html and fxhash.min.js)
https://elout.home.xs4all.nl/2024/jun/flamer/flamer.zip
[or right click save the html file etc.]

//______________________________________________________//
basicly you need to have the index.html and fxhash.min.js

-an 16x 16 image for the favicon

-your images prepared in different folders  layer1 layer2 etc.

-adjust the script, 
---- for the correct image names it should load
---- and the number of images you use in each layer

zip it up, [i use 7zip] and upload it to fxhash

more tech
i just use 1 canvas and load 1 image at the time [to keep memory use low]
and I stamp that loaded image on my drawing canvas [like a brush]

later i/you also can add animations etc, random positions or mirroring and special fx

when testing with url fxhash key for determination..
better trust it works, or do that on an online webserver, where you can check the index.html
[since my local apache webserver got stuck on that, and didnt refresh]

YouTube video https://www.youtube.com/watch?v=_CsuFJnnxJc

vid on youtube
sorry for the low sound volume on this one..
so watch your eardrums when switchin back

btw you don't need to run an apache server at home, for testing, you can test it also online (on a website) or directly upload it to fx
if you prepare your images, and have the names xxx correct in the script, it should run on fxhash
javascript that does it all below, besides the fxhash snippet for random and snapshot
<!doctype html>
<html>
<head>

 <!--a favicon 16x16 .png -  created at www.base64-image.de (if you got no favicon, it can throw an error) -->
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wAAAAAzJ3zzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH6AYCFTM03Lj+egAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAC/klEQVQ4y52TW0ybdRjGn///+4CvrOX0tbBKD19ZS1cZXRE5CJGj0W0pkqAkwoUSN5ZszcZmJkS80SsviAkxhjswEhJjPF3gsgtQxuIy5Qymgs4NCNWuQ23Xjxb69fD3YsHoPCV7r968T57fe/G+D/AQ5Z25ygPA2vxXFJ9/OKxljNHn3E2eh4FRAHueky84v5lf7nfYTLf3hdGht+l/GWsqXMONtZUesj9wOizLK6vrR63SI5uSZB7SF+Qb4rG9GpPRtBMMBZPe1e+TVovkHf1o/EKpw7rCGJvUacWn/yDWVbu29nubxeDPPpDR8eDWXs9JfVNdtVzqONQKABWukg0OAIqlgyfUao39dFfHanQ3lhOJRB7zbwf7HgRcn13cWd/0vWWVjO0HMgW7Vsz7lQBAc30VC9wJeHVinhySIxuBu9uHjjx6+KggCFw0Io9NXpvt+jOoodKZv6Mkp+aWvCW0sCCvMxyWE6FwxE44vrznTPfi88+69TqtmF7mLOVEMf+l5ierkgDQUFtxqsikb3W3tuTwPKcAAJelURGdNidwLyxHw/KOtUgy19jt1h/NJuPNVDLlr697YqCtxT1YW1WWq8nKKo5Edt+bnLp27lhTne36zKJCBUFYef2ViyNKTDkYjUZllSBokonk42CsUszL5YK/hdwTV6ffuTGzMCKZDCc629umJbMJPEdTAEBsRYX44ZYPBr12PY3nNp95qrG+3OVCijEADCpBhdM9r8JiMSMZj8PT/TK+/W6NfTZ++cYnY+830riigBACjhIQSgcnvpze8N8JICzL4DgewVAIL3a0Y8v3M/yBbcwsLOGDjz8lzhLHuzdv3xIhGfP/cqrDVtMXGnXapTQOHpulcC0jnQyoBH5OoxYUtVpguTlqpUCXu3rpbLcaAIhRL2I3FgcYy8zO1mQmEomMTd/dn/7pfRljlBCS+ptwvLEaRoP2f4PTe+4UBYA3X+uh/RfP0P0w4crU19jy/fKvxr7z9408z+ONvvM0HouDkvsx+h359hY9zfUu6AAAAABJRU5ErkJggg==" />


 <!--for the  css stylesheet -->
<style type="text/css">
body
{
    background-color: rgb(40,40,40);
    margin: 0px; padding: 0px;
    width: 100vw; height: 100vh;
    overflow: hidden; display: flex;
    align-items: center; justify-content: center;
}
.info_css
{
    color: rgb( 120,  220, 220); 
    font-family: Verdana, Arial; font-size: 12px;    
    z-index:31; position: fixed; top:0px;left:0px; 
    border-style:none; border-width:0px;
    margin:0px 0px 0px 0px; padding:2px 2px 2px 2px;
}
.canvas_css
{
    max-width: 100%; max-height: 100%; z-index:20; position: fixed; 
}
.workbench_css
{
    max-width: 100%; max-height: 100%; z-index:10; position: fixed; 
}

</style>

<!--fxhash snippet canvas#my_canvas  -->
<script src="./fxhash.min.js"></script>


<!--here the javascript kicks in -->
<script type="text/javascript">

// wip early bird version

// !!!running the html - because: loading images is not working from local file/harddisk (due security in browser)
// only if you running  a (local)server! 
// !! or ftp-upload your project online on a server-website for testing - now
// https://developer.mozilla.org/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server
// myself i use a simple python server at home, incase i want to work with loading images and javascript
// console, i can start it up [at like win10] 
// cd documents/esrc_2024/html/spideysense/spideysense001c
// python -m http.server
// result in http://localhost:8000/


// fxpreview() from canvas - name:  canvas#my_canvas


// incase testing deterministic: add key to index, you can change random numbers / letters as well
// index.html?fxhash=ooZ1XdEpg4V2ci6UgaSh6gspLCF8gCPS5q4bi8sCukBuhM4yXwt


// yo yo yo. starting from scratch
// some tech stuff i need  at start
var mylayerdata = new Array();
var p=0; 
// NEXT:  init and settings


// !!!!!!!!!!!! ---------------SETTINGS-------------- for your images!!!!!!!

// currently only .png supported - and all images the should be the same size

// name of your project and also the save-file name 
var cversion="spideysensi_v001b_";

// make sure you got the names correct! (without numbers! and .png i add that later)
// layer 1 name - first layer with names background1.png background2.png etc 
mylayerdata[p++]='./layers/layer_1/background'; 
mylayerdata[p++]=4; // i got 4 images  in the folder layer_1


// layer 2 name -second layer with names labfiles1.png labfiles2.png etc etc.
mylayerdata[p++]='./layers/layer_2/labfiles'; 
mylayerdata[p++]=6; // i got 6 images for the second layer  

// layer 3  name - third layer with hit1up1.png hit1up2.png etc 
mylayerdata[p++]='./layers/layer_3/hit1up'; 
mylayerdata[p++]=5; // nmr. of images in layer_3 folder  now

//layer 4
mylayerdata[p++]='./layers/layer_4/fatmarker'; //name
mylayerdata[p++]=7; // nmr. of images

//layer 5
mylayerdata[p++]='./layers/layer_5/buzz'; //name
mylayerdata[p++]=7;// nmr. of images

// 4 6 5 7 7 = 5880 combinations now

// if you want to add more layers etc
// you can do it here, make sure you got the names and numbers right of your files
//mylayerdata[p++]='./layer_6/xxx'; 
//mylayerdata[p++]=4;  


// extra settings  for testing etc.

var anim_loop =  true; // false; animation - redraws image x seconds
var show_fps =   false; // false; show fps




//next is: an basic engine 'n tech for running the thing.. 
var cur_stack=0;
var ran_stack = new Array();

var big_init=false; // big init starts... when the 1st image is loaded

var my_load_img= new Image();

var my_load_img_state = false;
var my_load_img_w = 1024;
var my_load_img_h = 1024;

var load_counter=0;
//var startup=true;
//var imagenumber=0;

//forced image width
var im_w=1024; // gets reset after first image has loaded
var im_h=1024;

var pix_r = new Uint8ClampedArray();
var pix_g = new Uint8ClampedArray();
var pix_b = new Uint8ClampedArray();
//var pix_a = new Uint8ClampedArray();

var mode=0;  

document.title =cversion; // sets window title + also image savename!!

// some global vars I use 

var anim_counter=0; // part of animation drawing
var anim_runner=0;
var mycounter=0;
var countertreshhold=900;

var do_fxhash_preview=true;
var save_image=false;

var win_w=window.innerWidth;
var win_h=window.innerHeight;

var test=""; // needed for testing, text etc

//---legacy code dirty fps counter 
var my_timer=setInterval(function(){timer_fps()},1000);// interrupt - gets triggers every 1sec
var counter_fps=0;
var timeCurrent, timeLast = Date.now(); 


// page 1st time loading ?
window.addEventListener('load',init_mywindow, false ); 
//loaded? kicks off ' this javascript next
function init_mywindow() 
{
    //random stacker
    gogo_stacker();

    // check for window resizing
    window.addEventListener( 'resize', onWindowResize, false );

    win_w=window.innerWidth;
    win_h=window.innerHeight;

    // !!! blur or sharp pixels? !!!!
    document.getElementById('my_canvas').style.imageRendering =  'pixelated';

    var c=document.getElementById('my_canvas');
    var ctx=c.getContext("2d");
    c.width = im_w; 
    c.height = im_h;    

    //show/hide html layer-  - fps text counter  bar in screen
    if(show_fps==false){document.getElementById('infoblock').style.visibility = "hidden";}
    else {document.getElementById('infoblock').style.visibility = "visible";}

    // keyboard event
    document.addEventListener('keyup', function(event) 
    {
        //alert('  key: '+ event.keyCode); // to test keyboard
        if(event.keyCode == 83 ) {save_image=true;  } // s or S: save image
    });

    // kicks off-starts animation now at 60fps
    animate();
}

function gogo_stacker() // sets random now
{
    var count=0;
    while(count<mylayerdata.length) // simple randomizer
    {
        var r=mylayerdata[count+1];
        ran_stack[count]= get_rand_int(r)+1;
        ran_stack[count+1]= mylayerdata[count+1];
        count+=2;
    }
}

function init_loadimage(loadname,canvasname,mode) 
{
    my_load_img = new Image(); 
    my_load_img.onload = function()
    {
        // when image is finally loaded.. go do this
        // !!!! when first time image gets loaded !!!
        if (big_init==false)// first image sets canvas size now
        {
            im_w = my_load_img.width; // sets canvas size based on first image now
            im_h = my_load_img.height;

            // reset my working canvas
            pix_r = new Uint8ClampedArray(im_w*im_h);
            pix_g = new Uint8ClampedArray(im_w*im_h);
            pix_b = new Uint8ClampedArray(im_w*im_h);

            var r=get_rand_int(255); // random grey start 
            fill_array(pix_r,im_w*im_h, r);
            fill_array(pix_g,im_w*im_h, r);
            fill_array(pix_b,im_w*im_h, r);
            big_init=true;
        }
        else
        {
            if(im_w != my_load_img.width || im_h != my_load_img.height)
            {
                alert('image size different then [root] 1st. loaded image');
            }

        }

        if(big_init==true)
        {
            my_load_img_state=true;

            var c=document.getElementById(canvasname);  
            var ctx=c.getContext("2d", { willReadFrequently: true });    
            c.width = im_w <<0;
            c.height = im_h <<0;  
            c.style.width = im_w <<0 +'px'; 
            c.style.height = im_h <<0+'px'; 
            ctx.drawImage(my_load_img,  0,0,im_w,im_h); // draw image on my canvas      
            ic0 = ctx.getImageData(0, 0, im_w, im_h ).data;
            //drawmode hard 
            if(mode==0) // background hard first time init again
            {
                for (var p=0, j = 0; j <im_w*im_h; j++)
                {
                    pix_r[j]= ic0[p] ;  //r hard
                    pix_g[j]= ic0[p+1]; //g
                    pix_b[j]= ic0[p+2]; //b
                    p+=4;   
                }       
            }
            // drawing mode 1 mix'n transparent
            else if(mode==1)
            {
                for (var p=0, j = 0; j <im_w*im_h; j++)
                {
                    var alp=ic0[p+3];// alpha
                    var inv=255-alp;
                    pix_r[j]=((ic0[p]*alp) + (pix_r[j]*inv) )/255 <<0;;  //r 
                    pix_g[j]=((ic0[p+1]*alp) + (pix_g[j]*inv) )/255  <<0;  //g
                    pix_b[j]=((ic0[p+2]*alp) + (pix_b[j]*inv) )/255  <<0; //b
                    p+=4;

                }   
            }
        }
    };
    my_load_img.src = loadname;
}

function onWindowResize() //  window resized? not used yet
{
    win_w=window.innerWidth;
    win_h=window.innerHeight;   
}


// kick it off - start the animation interrupt
// also lower energy, when hidden away in tab it won't animate..
function animate() 
{
    requestAnimationFrame( animate );

    anim_runner++;
    if(anim_runner<0){anim_runner=0;}// overflow check

    if (show_fps==true){counter_fps++;}

    my_animation(); // global animation script - gets called at 60fps

    if(big_init==true)// first images been loaded
    {
        if((anim_runner%10) == 0) // redraw screen 6 times a second
        {
            var c=document.getElementById('my_canvas');
            var ctx=c.getContext("2d");

            c.width = im_w; 
            c.height = im_h;
            c.style.width = im_w <<0 +'px'; 
            c.style.height = im_h <<0+'px';         
            var img1 = ctx.createImageData(im_w, im_h); //var

            for (var p=0, y = 0; y < im_h; y++)
            {               
                var p1=(y*im_w)<<0;
                var r=get_rand_int(255);
                for (var x = 0; x < im_w; x++)
                {               
                    var p2=p1+x<<0;
                    img1.data[p++] = pix_r[p2];//(pix_r[p2]+r) /2 <<0;
                    img1.data[p++] = pix_g[p2];//(pix_g[p2]+r) /2 <<0;
                    img1.data[p++] = pix_b[p2];//(pix_b[p2]+r) /2 <<0;
                    img1.data[p++] = 255;
                }   
            }   
            ctx.putImageData(img1, 0, 0);

            if(save_image==true)
            {
                    var my_hash=$fx.hash; 
                    var imagename= cversion+'_'+my_hash+'.png'; //inc genify hash
                    var my_download = document.createElement('a');
                    my_download.setAttribute('download', imagename);            
                    var mcanvas = document.getElementById('my_canvas');
                    mcanvas.toBlob(function(blob) {
                                    var url = URL.createObjectURL(blob);
                                    my_download.setAttribute('href', url);
                                    my_download.click();    
                                    });         

                save_image=false;
            }
        }

    }
}

// dirty fps counter
function timer_fps()
{
    timeCurrent = Date.now();
    if(timeCurrent > timeLast) // 
    {
        timeLast = timeCurrent;
        if (show_fps==true)
        {
            set_msg('infoblock',   '.__0 fps: '+counter_fps+' '+test);
        }
        counter_fps=0;      
    }
}

//write html text
function set_msg(div, msg){document.getElementById(div).innerHTML = msg;}
function go_msg(div, msg) {document.getElementById(div).innerHTML += msg;}

// filler
function fill_array(buf,size,value)
{   
    for (var i=0; i < size; i++){ buf[i]=value;}
}

// all  fx random setting at 1 place!! so i don't have to change it later 100times
function get_rand()
{
    return ( $fx.rand()  ); //  Math.random()   = javascript random
}
function get_rand_int(num)
{
    return (($fx.rand()*num)<<0);
}

// global animation script

// here we go again! - running at 60fps
function my_animation() 
{
    // init start my anim
    if (anim_counter==0)
    {       
        mycounter=0;        
        anim_counter=1; // go next anim part
    }

    else if (anim_counter==1)
    {       
        // kicks off loading 1st image 1st layer
        cur_stack=0;
        var name = mylayerdata[cur_stack]; // name
        var num= mylayerdata[cur_stack+1]; // number of images

        var goget = ran_stack[cur_stack];   

        var loadname= name + goget +'.png';
        init_loadimage(loadname,'my_workbench',0);  // 0 mode  hard drawing
        my_load_img_state=false;

        mycounter=0; // for timing animation
        anim_counter=2; // go next anim part
    }

    else if (anim_counter==2)
    {
        if(my_load_img_state==true)
        {
            cur_stack+=2;
            if(cur_stack>=mylayerdata.length)
            {
                mycounter=0;
                anim_counter=100;    // all layers drawn exit   next    
            }
            else
            {
                var name = mylayerdata[cur_stack]; // name
                var num= mylayerdata[cur_stack+1]; // number of images

                var goget = ran_stack[cur_stack];   
                var loadname= name + goget +'.png';
                init_loadimage(loadname,'my_workbench',1);  // 0 mode  hard drawing
                my_load_img_state=false;
                //test=name + ' ' + num;
            }
        }
    }

    // end of anim 
    else if (anim_counter==100)
    {

        //test= 'drawing ready'; // still got check if images are loaded!
        if(mycounter>801 && do_fxhash_preview==true)
        {
            $fx.preview(); // do fxhash thumbnail
            console.log('done fxhash thumbnail');
            do_fxhash_preview=false;
            countertreshhold=200;
        }

        mycounter++;
        if (mycounter>countertreshhold)
        {
            if(anim_loop == true)           
            {
                //random stacker
                gogo_stacker();

                load_counter=0;
                my_load_img_state=false;
                mycounter=0;
                anim_counter= 0; // go to start - reset         
            }
        }
    }   


}// end my_animation()

// end of javascript, some html next
</script>
</head>
<body>
    <div class="info_css" id="infoblock">=_______=</div> 
    <canvas class="canvas_css" id="my_canvas">-__-</canvas>
    <canvas class="workbench_css" id="my_workbench">0__.</canvas>
</body>
</html>