twgl.js/examples/dynamic-buffers.html
Gregg Tavares 67551111b4 Fix CSS
There was a time when 100vh was correct but mobile browsers changed.
2025-10-13 14:54:12 -07:00

224 lines
6.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<!--
@license twgl.js Copyright (c) 2015, Gregg Tavares All Rights Reserved.
Available via the MIT license.
see: http://github.com/greggman/twgl.js for details
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta property="og:title" content="TWGL.js - dynamic-buffers" />
<meta property="og:type" content="website" />
<meta property="og:image" content="http://twgljs.org/examples/screenshots/dynamic-buffers.png" />
<meta property="og:description" content="TWGL.js - dynamic-buffers" />
<meta property="og:url" content="http://twgljs.org" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@greggman">
<meta name="twitter:creator" content="@greggman">
<meta name="twitter:domain" content="twgljs.org">
<meta name="twitter:title" content="TWGL.js - dynamic-buffers">
<meta name="twitter:url" content="http://twgljs.org/examples/dynamic-buffers.html">
<meta name="twitter:description" content="TWGL.js - dynamic-buffers">
<meta name="twitter:image:src" content="http://twgljs.org/examples/screenshots/dynamic-buffers.png">
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
<title>twgl.js - dynamic-buffers</title>
<style>
html, body {
margin: 0;
font-family: monospace;
height: 100%;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
#b {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 2;
color: white;
}
a:visited, a:link, a:active {
color: white;
}
audio {
display: none;
}
#click, #load {
font-family: sans-serif;
position: absolute;
left: 0;
top: 0;
z-index: 2;
background-color: rgba(0,0,0,0.8);
width: 100%;
height: 100%;
display: flex;
display: -webkit-flex;
flex-flow: column;
-webkit-flex-flow: column;
justify-content: center;
align-content: center;
align-items: center;
-webkit-justify-content: center;
-webkit-align-content: center;
-webkit-align-items: center;
min-height: auto;
}
#click>div, #load>div {
font-size: 24pt;
color: white;
background-color: blue;
border-radius: 1em;
padding: 1em;
}
#load {
z-index: 3;
}
#load>div {
color: black;
background-color: red;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="b">
<div><a href="http://twgljs.org">twgl.js - dynamic-buffers</a></div>
<div>music: <a href="http://youtu.be/eUX39M_0MJ8">DOCTOR VOX - Level Up</a></div>
</div>
<div id="click">
<div>tap to play</div>
</div>
<div id="load">
<div>loading...</div>
</div>
</body>
<script src="../3rdparty/audiostreamsource.min.js"></script>
<script type="module">
import * as twgl from '../dist/7.x/twgl-full.module.js';
/* global audioStreamSource */
// There's really no good way to tell which browsers fail.
// Right now Safari doesn't expose AudioContext (it's still webkitAudioContext)
// so my hope is whenever they get around to actually supporting the 3+ year old
// standard that things will actually work.
const shittyBrowser = window.AudioContext === undefined && /iPhone|iPad|iPod/.test(navigator.userAgent);
const context = new (window.AudioContext || window.webkitAudioContext)();
const analyser = context.createAnalyser();
twgl.setDefaults({attribPrefix: "a_"});
const gl = document.querySelector("#c").getContext("webgl");
const vs = `
attribute float a_spread;
attribute float a_height;
varying vec4 v_color;
vec3 hsv2rgb(vec3 c) {
c = vec3(c.x, clamp(c.yz, 0.0, 1.0));
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
gl_Position = vec4(a_spread, a_height * 2.0 - 1.0, 0, 1);
v_color = vec4(hsv2rgb(vec3(a_spread * 0.5 + 0.5, a_height, 1)), 1);
}
`;
const fs = `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// If it's a shitty browser (like Safari) then we can't stream so we load
// a very lo-fi version of the song that has no frequencies above 11.5k
const numPoints = analyser.frequencyBinCount * (shittyBrowser ? 0.25 : 1) | 0;
const spreadArray = new Float32Array(numPoints);
const heightArray = new Uint8Array(numPoints);
for (let ii = 0; ii < numPoints; ++ii) {
spreadArray[ii] = ii / numPoints * 2 - 1; // make clip space positions
}
const arrays = {
spread: { data: spreadArray, numComponents: 1 },
height: { data: heightArray, numComponents: 1, drawType: gl.DYNAMIC_DRAW },
};
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
function render() {
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.lineWidth(2);
gl.useProgram(programInfo.program);
analyser.getByteFrequencyData(heightArray);
twgl.setAttribInfoBufferFromArray(gl, bufferInfo.attribs.a_height, heightArray);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo, gl.LINE_STRIP);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
const clickElem = document.querySelector("#click");
const loadElem = document.querySelector("#load");
const streamSource = audioStreamSource.create({
context: context,
loop: true,
});
function startMusic() {
clickElem.style.display = "none";
streamSource.play();
context.resume().then(() => {
streamSource.play();
streamSource.getSource().connect(analyser);
analyser.connect(context.destination);
});
}
streamSource.on('error', function(e) {
console.error("audio error:", e); // eslint-disable-line
});
streamSource.on('newSource', function(/* source */) {
loadElem.style.display = "none";
clickElem.addEventListener('click', startMusic);
});
streamSource.setSource(
'sounds/DOCTOR VOX - Level Up.mp3',
'sounds/DOCTOR VOX - Level Up - for shitty browsers.mp3' // for shitty browsers like Safari on iOS
);
</script>
</html>