JSFiddle - React, Tailwind, and code Playground

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<div class="main">
    <div id="canvas"></div>
    <span>tempo: </span><input id="tempo" value='200' />
    <span>ticks: </span><input id="ticks" value='20' />
    <input type="button" id="startstop" value="start" />
</div>

<audio id="tick" src="http://experimentsinform.com/media/audio/tick.wav"></audio>

CSS

.main {
    width: 400px;
    margin: 5px;
    padding: 10px;
}

#canvas {
    width: 900px;
    height: 240px;
    margin-bottom: 5px;
}

#tempo {
    width: 50px;
    text-align: center;
}

#ticks {
    width: 50px;
    text-align: center;
}

body {
    font-size: 12px;
}

JavaScript

var paper = Raphael("canvas", 300, 240);

var metronome = function(l, r) {
    l = typeof l !== "undefined" ? l : 200; // length of metronome arm
    r = typeof r !== "undefined" ? r : 20; //max angle from upright 
    var y0 = l * Math.cos(Math.PI * r / 180),
        x0 = l * Math.sin(Math.PI * r / 180),    
        y = l + 10,
        x = x0 + 10,    
        tick_count = 0,
        width,
        bars = paper.set();
    
    var outline = paper.path("M"+x+","+y+"l-"+x0+",-"+y0+"a"+l+","+l+" "+2*r+" 0,1 "+2*x0+",0L"+x+","+y).attr({
        fill: "#EEF",
        'stroke-width': 0    
    });
    
    var arm = paper.path("M" + x + "," + y + "v-" + l).attr({
        'stroke-width': 5,
        stroke: "#999"
    }).data("id", "arm");
        
    var weight = paper.path("M" + x + "," + (y-100) + "h12l-3,18h-18l-3-18h12").attr({
        'stroke-width': 0,
        fill: '#666'
    }).data("id", "weight");

    var vertex = paper.circle(x, y, 7).attr({
        'stroke-width': 0,
        fill: '#CCC'
    }).data("id", "vertex");

    var label = paper.text(x, y + 20, "").attr({
        "text-anchor": "center",
        "font-size": 14
    });

    var mn = paper.set(arm, weight);
    
	Raphael.easing_formulas.sinoid = function(n) { return Math.sin(Math.PI * n / 2) };

    function done() {
        mn.attr("transform", "R0 " + x + "," + y);
        $(this).val("start");
        
    }
    
    function tick(obj, repeats, callback) {    
        console.log(arguments);
        //Raphael summons the callback on each of the three objects in the set, so we
        //have to only call the sound once per iteration by associating it with one of the objects.
        //doesn't matter which one
        if (obj.data("id") === "arm") {
            document.getElementById("tick").play();
            tick_count += 1;
            label.attr("text", tick_count);    
            if (callback && tick_count >= repeats) {
                callback();
            }    
        }
    }  
   ...