Developing javascript stickman musician api

Joined
Sep 3, 2023
Messages
36
Reaction score
2
Hi, looking for interested programs/etc... that creates an animated 2D stickman musicians (guitar, fiddle, bass, drums, ...). So far I've been using snap.svg, and a stickman that can rotate his arms... I'd like it to be able to analyze audio tracks to determine its movement.
 
Joined
Jul 4, 2023
Messages
366
Reaction score
41
BTW, some suggestions from GPT might be useful ...

  1. HTML5 Canvas and JavaScript: You can create a 2D stickman musician animation using HTML5 Canvas and JavaScript. You'll need to manually code the animations and interactions. For audio analysis, you can use the Web Audio API to analyze audio tracks and synchronize the stickman's movements accordingly.
  2. GreenSock Animation Platform (GSAP): GSAP is a powerful JavaScript animation library that can help you create complex animations. You can use GSAP to animate the stickman's movements and synchronize them with the audio. For audio analysis, you can use additional libraries like the Web Audio API or the Tone.js library.
  3. Adobe Animate: Adobe Animate is a professional animation software that allows you to create 2D animations easily. You can design your stickman musician in Adobe Animate and then use JavaScript to control its movements and sync them with audio. Adobe Animate provides a timeline for animation sequencing.
  4. Three.js (for 3D) or Pixi.js (for 2D): If you want a more 3D-like effect for your stickman musician, you can use Three.js for 3D animations or Pixi.js for 2D animations. You'll need to model your stickman and then animate it using these libraries. Audio analysis can still be performed using the Web Audio API.
  5. Audio Analysis Libraries: For analyzing audio tracks, you can use libraries like Web Audio API, Tone.js, or the more advanced Magenta.js, which is developed by Google and designed specifically for creating music-related applications. These libraries can help you extract information from audio, such as tempo, beats, and other musical features, to synchronize your stickman's movements.
  6. Machine Learning and AI: If you want to take it to the next level, you can consider using machine learning and AI techniques for more advanced audio analysis and synchronization. Libraries like TensorFlow.js or PoseNet can be used to detect musical cues and synchronize the stickman's movements accordingly.
Remember that this project can be quite challenging, especially if you're new to animation and audio analysis. You'll need to invest time in learning the chosen technologies and libraries. Additionally, the level of complexity will depend on how realistic and detailed you want the stickman's movements to be in response to the audio.
 
Joined
Sep 3, 2023
Messages
36
Reaction score
2
I started this off as seeing how well a chatbot could write code and snap.svg was one its suggestions. But it kinda vomits out answers, making random changes to the code, things dont necessarily work, adds code comments like mad (some languages ie perl just a bunch of randomly hashed together licensing comments with and an incomplete sub header), and then forgets everything and needs to explained what you want... But it seem to well with explaining documentation that hard to find and unclear.

I rather try some kind of collaboration with a person. --- I'm not too much js programmer, but have used Tone.js & webaudio & html5 canvas, ... I know smidgens of a lot of languages, but mostly have concentrated on perl, since I frustrated with other languages and some book's author after suggesting such and such, then started complaining that perl was the ugly language, I didnt see anything pretty theirs and it kinda reminds me the old 80's basic in some or other, which is where I started at.
 
Joined
Sep 3, 2023
Messages
36
Reaction score
2
HTML:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE></TITLE>
<script src="snap.svg-min.js"></script>
<script src="stickman.js"></script>
</HEAD><BODY>

<svg id="svg" width="400" height="400"></svg>

<script>


var s = Snap("#svg");




// Limb constructor function
function Limb(x, y, len, rot) {
    this.x = x;
    this.y = y;
    this.len = len;
    this.rot = rot;

    this.grp = s.group( s.line(x, y, x + len, y) );
    
}

Limb.prototype.update = function(){
    var x = this.x;
    var y = this.y;
    var len = this.len;
    var rot = this.rot; if(len<0){ rot = rot * -1; }
    var grp = this.grp;
    
    //grp.transform( "r" + rot + " " + x + " " + y);
    var matrix = new Snap.Matrix();
    matrix.rotate(rot, x,y);
    grp.transform(matrix);
}
Limb.prototype.rotate = function(rot){
    this.rot = rot;
    this.update();
}



//
function StickMan(x,y, rot){
    this.x = dval(x, 100);
    this.y = dval(y, 100);
    this.rot = dval(rot, 0);
    x = 0;
    y = 0;
    

    var attr = {
        fill: "#ffc",
        stroke: "#330",
        strokeWidth: 2
    };
    var attr2 = {
        fill: "#330",
    };

    //head
    this.head = s.group( s.circle(x, y-15, 15) );
    //this.head.attr(attr);
    this.head.eyes = s.group(
        s.circle(x-5, y-17, 2),
        s.circle(x+5, y-17, 2)
    );
    this.head.eyes.attr(attr2);
    this.head.mouth = s.circle(x, y-7, 4);
    this.head.add(this.head.eyes, this.head.mouth);

    var matrix = new Snap.Matrix();
    matrix.scale(1, 0.4, x, y-7);
    this.head.mouth.transform(matrix);

    //body
    this.body = s.group( s.line(x, y, x, y+45), s.line(x-5,y+10,x+5,y+10), this.head);
    this.body.attr(attr);


    this.gtr = new Shape_acgtr(x,y+27,-20, 1, '#990', '#600', -1); // new Guitar(x, y+27, -20);


    this.armr = new Limb(x-5, y+10, -24, 0);
    this.farmr = new Limb(x-29, y+10, -22, 0);
    this.armr.grp.add( this.farmr.grp );

    this.arml = new Limb(x+5, y+10,  24, 0);
    this.farml = new Limb(x+29, y+10,  18, 0);
    this.arml.grp.add(this.farml.grp);

    this.body.add(this.arml.grp, this.gtr.grp,  this.armr.grp);


    this.legr = new Limb(x, y+45, -50, 60);
    this.legl = new Limb(x, y+45,  50, 60);

    this.body.add(this.legl.grp, this.legr.grp);


    this.update();
}

StickMan.prototype.update = function(){
    var x = this.x;
    var y = this.y;
    var r = this.rot;

    var matrix = new Snap.Matrix();

    matrix.translate(x,y);
    matrix.rotate(r, 0,0);
    this.body.transform(matrix);
    

    this.armr.update();
    this.farmr.update();

    this.arml.update();
    this.farml.update();


    this.legr.update();
    this.legl.update();

}
StickMan.prototype.rotate = function(rot){
    this.rot = rot;
    this.update();
}
StickMan.prototype.move = function(x,y){
    this.x = x;
    this.y = y;
    this.update();
}





var p1 = new StickMan(50, 50);
//p1.update();
p1.arml.rotate(40);
p1.farml.rotate(-100);
p1.armr.rotate(15);
p1.farmr.rotate(140);

//p1.move(200,100);


/*function down(){
    Snap.animate(170,90, function (val){ p1.farmr.rotate(val) },
        400, mina.easeinout, up);
}
function up(){
    Snap.animate(90,170, function (val){ p1.farmr.rotate(val) },
        100, mina.easeinout, down);
}
*/


/*
var gtr2 = new Shape_egtr(130,100,-90,1);
var gtr3 = new Shape_acgtr(170,100,-90,1);
var uke = new Shape_uke(200,100,-90,1);
var bj = new Shape_bj(230,100,-90,1);
var fid = new Shape_fid(270,100,-90,1);
var dr = new Shape_dr(330,100,0, 0.7);
var mando = new Shape_mando(230,150,-90,1);
*/


var tm = 0;
var tmx = setInterval( function (){
    var t = tm % 5;
    var rot = p1.farmr.rot;

    if(t === 0){
        Snap.animate(rot, 90, function (val){ p1.farmr.rotate(val) },
        90, mina.easeinout);
console.log('strum down');
    }
    else if(t === 4){
        Snap.animate(rot, 170, function (val){ p1.farmr.rotate(val) },
        300, mina.easeinout);
console.log('strum up');
    }


    if(++tm>50){ clearTimeout(tmx); }
    console.log(tm);   
}, 100);

</script>

</BODY>
</HTML>

JavaScript:
"use strict"

//var s = Snap("#svg");

// sets a default value
function dval(a,b){
    return a==null ? b : a;
}

// get the type object
function type2(a){
    var t = typeof a;

    if(t === 'object'){
        if(a === null){ t = 'null'; }
        else if(a.constructor === Array){ t = 'array'; }
        else if(a.constructor === RegExp){ t = 'regexp'; }
        else{
            var t2 = Object.prototype.toString(a);
            var regex = /^[object (S+?)]$/;
              var matches = t2.match(regex) || [];
 
             t = (matches[1] || t).toLowerCase();
        }

        if(t === 'object'){
            if(a instanceof Shape){ t = 'shape'; }
            else{
                if(a.type != null && ( // is Snap
                    a.type === 'line' ||
                    a.type === 'rect' ||
                    a.type === 'circle' ||
                    a.type === 'ellipse' ||
                    a.type === 'path' ||
                    a.type === 'group'
                    )){ t='snapshape'; }
            }
        }
    }
    else if(t === 'number'){
        if(isNaN(a)){ t = 'nan'; }
    }

    return t;
}




// base object
class Shape{
    constructor(x,y,r, sz, grp, c0, c1, lw){
        this.x = 0;
        this.y = 0;
        this.r = 0;     // rotate angle
        this.s = sz;    // scale
        this.ox = 0;    // ofs
        this.oy = 0;

        c0 = dval(c0, "#FFF"); // fill color 
        c1 = dval(c1, "#000"); // line color
        lw = dval(lw, 2);

        this.grp = s.group(); // line, circle, rect, path, ...
        this.grp.attr( {fill: c0, stroke: c1, strokeWidth: lw} );

        if(type2(grp) !== 'array' ){ grp = [grp]; } //doesnt work
        for(var g in grp){
            var gg = grp[g];
            var ty = type2(gg);
                            

            if(ty === 'snapshape'){ this.grp.add(gg); }
            else if(ty === 'string'){
                try{
                    var b = gg.split(/[ ,]+/);
                    if(b[0] === 'circle'){
                            gg = s.circle(b[1],b[2],b[3]);
                    }
                    else if(b[0] === 'rect'){
                            gg = s.rect(b[1],b[2],b[3],b[4]);
                    }
                    else if(b[0] === 'line'){
                            gg = s.line(b[1],b[2],b[3],b[4]);
                    }
                    else if(b[0] === 'ellipse'){
                            gg = s.ellipse(b[1],b[2],b[3],b[4]);
                    }
                    else{
                        gg = s.path(gg);
                    }

                    this.grp.add(gg);
                }
                catch(e){}
            }
        }
        
        this.move(x,y,r);
    }

    move(x,y,r, sz){
        x = dval(x, this.x);
        y = dval(y, this.y);
        r = dval(r, this.r);
        sz = dval(sz, this.s);

        var ox = this.ox;
        var oy = this.oy;

        var m = new Snap.Matrix();
        m.translate(x, y);
        m.rotate(r, ox,oy);
        m.scale(sz,sz, oy,oy);

        this.grp.transform(m);

        this.x = x;
        this.y = y;
        this.r = r;
    }
    rotate(r){
        this.move(this.x, this.y, r);
    }
    scale(s){
        this.move(null,null,null, s);
    }
    ofs(x,y){
        this.ox = x;
        this.oy = y;
        this.move();
    }

    animate(x1,y1,r1, tm, callback){
        var x0 = this.x;
        var y0 = this.y;
        var r0 = this.r;
        var t = this;

        Snap.animate(0,1,
            function (v){
                var x = (x1 - x0)*v + x0;
                var y = (y1 - y0)*v + y0;
                var r = (r1 - r0)*v + r0;
                t.move(x,y,r);
            },
            tm, mina.easeinout, callback);
    }
}


class Shape_acgtr extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        sz *= 0.75;
        super(x+15,y, r, sz, [
            "M0,0  Q-3,-20,-16,-16  Q-26,-6,-32,-16  Q-52,-30,-59,-8 L-60,0",
            "M0,0  Q-3,20,-16,16  Q-26,6,-32,16  Q-52,30,-59,8 L-60,0",
            "rect -15,-5,60,10", "rect 40,-6, 17,12",
            "circle 42,-8,2", "circle 48,-8,2", "circle 54,-8,2",
            "circle 42, 8,2", "circle 48, 8,2", "circle 54, 8,2",
            "circle -20,0,8",
            ], c0, c1, lw);

        this.grp[10].attr({fill: '#000'});
        this.ofs(-15,0);
        //this.scale(0.75);
    }
}

class Shape_egtr extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        sz *= 0.75;
        super(x+15,y, r, sz, [
            "M0,0  Q0,-16,-16,-16  Q-26,-6,-36,-16  Q-58,-30,-60,0",
            "M0,0  L-10,0 Q10,30,-16,16  Q-26,6,-36,16  Q-58,30,-60,0",
            "rect -20,-5,65,10", "rect 40,-6, 17,12",
            "circle 42,-8,2", "circle 48,-8,2", "circle 54,-8,2",
            "circle 42, 8,2", "circle 48, 8,2", "circle 54, 8,2",
            "rect -27,-5,3,10", "rect -35,-5,3,10"
            ], c0, c1, lw);

        this.grp[10].attr({fill: '#000'});
        this.grp[11].attr({fill: '#000'});
        this.ofs(-15,0);
        //this.scale(0.75);
    }
}

class Shape_uke extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        sz *= 0.50;
        super(x+15,y, r, sz, [
            "M0,0  Q-3,-20,-16,-16  Q-26,-6,-32,-16  Q-46,-26,-54,-6, L-55,0",
            "M0,0  Q-3,20,-16,16  Q-26,6,-32,16  Q-46,26,-54,6, L-55,0",
            "rect -20,-5,50,10", "rect 30,-6, 17,12",
            "circle 34,-8,2", "circle 42,-8,2",
            "circle 34, 8,2", "circle 42, 8,2",
            "circle -20,0,8",
            ], c0, c1, lw);

        this.grp[8].attr({fill: '#000'});
        this.ofs(-15,0);
    }
}

class Shape_bj extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        sz *= 0.75;
        super(x+15,y, r, sz, [
            "circle -40,0, 20", "circle -40,0, 16",
            "rect -20,-4,60,8", "rect 40,-6, 17,12",
            "circle 44,-8,2", "circle 52,-8,2",
            "circle 44, 8,2", "circle 52, 8,2",
            "circle 20,-6,2",
            ], c0, c1, lw);

        this.ofs(-15,0);
    }
}

class Shape_mando extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        sz *= 0.50;
        super(x+15,y, r, sz, [
            "M5,0  s-3,-10,-12,-10  s-12,-17,-30,-15"
            +" q-3,0,-16,16  L-55,0",
            "M5,0  s-3,10,-12,10  s-12,17,-30,15"
            +" q-3,0,-16,-16  L-55,0",

            "rect -20,-5,50,10", "rect 30,-6, 20,12",
            "circle 30,-8,1.5", "circle 42,-8,1.5",
            "circle 36,-8,1.5", "circle 48,-8,1.5",

            "circle 30,8,1.5", "circle 42,8,1.5",
            "circle 36,8,1.5", "circle 48,8,1.5",
            "ellipse -20,0,5,8",
            ], c0, c1, lw);

        this.grp[12].attr({fill: '#000'});
        this.ofs(-15,0);
    }
}

class Shape_fid extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        var c3 = "#000";
        var c4 = "#fff";

        sz *= 0.50;
        super(x+15,y, r, sz, [
            "M0,0  c-3,-20,-14,-12,-16,-14 "
            + "l-2,-2  c4,8,-14,8,-12,0"
            + "l-2,2 c-3,1,-2,-6,-14,-2"
            + "c-3,0,-6,4,-8,8"
            + " L-55,0",
            "M0,0  c-3,20,-14,12,-16,14 "
            + "l-2,2  c4,-8,-14,-8,-12,0"
            + "l-2,-2 c-3,-1,-2,6,-14,2"
            + "c-3,0,-6,-4,-8,-8"
            + " L-55,0",

            "M-35,-3, l0,6 L -58,0",
            "M-15,-3 l45,1 l0,4 l-45,1",
            "M30,-4 l18,1 l1,3 l-1,3   l-18,1 z",
            "circle 34,-8,2", "circle 40,-8,2",
            "circle 36, 8,2", "circle 42, 8,2",

             "M-35,8  c0,-7,16,5,16,-5 ",
             "M-35,-8 c0, 7,16,-5,16,5 ",
            ], c0, c1, lw);

        this.grp[2].attr({fill: c3});
        this.grp[3].attr({fill: c3});
        this.ofs(-15,0);


        this.bow = new Shape( x,y-2, r*-1+10, sz, [
            "rect -2,-59,3,5",
            "M1,-54 l-5,0 l0,5  s5,50,0,80  l5,5 z",
            "circle -2,-50 1.5",
            ], c3, null, 0);

        this.bow.grp[2].attr({fill: c4});
    }
}



class Shape_dr extends Shape{
    constructor(x,y,r, sz, c0, c1, lw){
        super(x+15,y, r, sz, [
            //HH
                "line 40,30 50,25",
                "line 50,-4 50,30",
                "ellipse 50,-4 12,3",
                "ellipse 50,-8 12,3",
                "line 50,-8, 50,-15",

            //SN
            "M25,-2 l0,10  a12,2 0 1,0 20,0  l0,-10",
            "ellipse 35,0 12,2",
            //FT
            "M-40,0  l0,20  a15,2 0 1,0 30,0  l0,-20",
            "ellipse -25,0 15,2",
            //HT
                "M5,-10 l0,-6  a10,5 0 1,1 20,0  l0,6",
                "ellipse 15,-8 10,5",
            //KD
            "circle 0,10,25",

            //RC
                "line -27,-20 -27,35",
                "ellipse -27,-20 20,4",
                "line -27,-20, -27,-30",
            //CC
                "line 30,-30 30,35",
                "ellipse 30,-30 15,4",
                "line 30,-30, 30,-40",

            ], c0, c1, lw);
    }
}
 
Joined
Jul 4, 2023
Messages
366
Reaction score
41
Propose to write <!DOCTYPE> for the html5 standard, just
HTML:
<!DOCTYPE html>

<!DOCTYPE> is a declaration used in HTML (Hypertext Markup Language) documents to specify the document type and version. It stands for "Document Type Definition."

The <!DOCTYPE> declaration is an essential part of an HTML document as it helps the web browser understand how to render the content.
The <!DOCTYPE> declaration is typically placed at the very beginning of an HTML document, before the <html> tag. It serves two main purposes:

  • Document Type Declaration: It tells the web browser or HTML parser which version of HTML the document is written in. This information is crucial for rendering the content correctly because different HTML versions may have different rules and features.
  • Quirks Mode vs. Standards Mode: The <!DOCTYPE> declaration also determines whether the browser should render the page in "quirks mode" or "standards mode." Quirks mode is used when there is no <!DOCTYPE> declaration or when an outdated or incorrect declaration is used. Standards mode is used when a valid and up-to-date <!DOCTYPE> declaration is present, and it enforces strict compliance with HTML standards.

Using the correct <!DOCTYPE> declaration is important to ensure proper rendering and compatibility with web standards.

and ...

1694415537784.png
 
Joined
Sep 3, 2023
Messages
36
Reaction score
2
Yes I've changed <!DOCTYPE html> in my template file, that's what it was when I learned html, and all the browsers use just care if there's valid one.

"Snap is not defined" ??? The second file being stickman.js . I know I'm being messy here... should there be an on loaded function that ensures snap.svg-min.js is loaded and that it has <svg ...> element .... so to define global s variable. Or is there a better solution?
 
Joined
Sep 3, 2023
Messages
36
Reaction score
2
JavaScript:
            //... added line in shape class
            if(ty === 'shape'){ this.grp.add( gg.grp );    }
            else // if(ty === 'snapeshape') ...

              
//rewrote as classes
class Limb extends Shape{
    constructor(x,y, len, r){
        super(x,y,r, 1,
        [ s.line(0, 0, len, 0) ],
        null, null, null);
    }

    update(){
        this.move();
    }
}

class StickMan extends Shape{
    constructor(x,y,r){
        x = dval(x, 100);
        y = dval(y, 100);
        r = dval(r, 0);

        var head = new Shape(
            0,-15,0, 1,
            ["circle 0 0 15", ],
            "#ffc", "#330", null
            );

        var armr = new Limb(-5, 10, -24, 0);
        var farmr = new Limb(-24, 0, -22, 0);
        armr.grp.add( farmr.grp );

        var arml = new Limb(5, 10, 24, 0);
        var farml = new Limb(24, 0, 22, 0);
        arml.grp.add( farml.grp );

        var legr = new Limb(0, 45, -50, -60);
        var legl = new Limb(0, 45,  50, 60);

        var gtr = new Shape_acgtr(0,27,-20, 1, '#990', '#600', -1);

        var body = new Shape(
            0,0,0, 1,
            ["line 0 0 0 45", "line -5 10 5 10",
            head, legr,legl, arml, gtr, armr ],
            null,null,null
            );

      

        super(x,y,r, 1,
            [body],
            "#ffc", "#330", null);

        this.head = head;
        this.body = body;

        this.armr = armr;
        this.farmr = farmr;
        this.arml = arml;
        this.farml = farml;

        this.legr = legr;
        this.legl = legl;

        this.gtr = gtr;
    }

    update(){
        this.move();
    }
}

hum... doesn't let me edit my previous posts here.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top