Spaces:
Runtime error
Runtime error
def construct_embed(source_url): | |
shader_id = source_url.split("/")[-1] | |
return f'<iframe width="640" height="360" frameborder="0" src="https://www.shadertoy.com/embed/{shader_id}?gui=true&t=0&paused=true&muted=true" allowfullscreen></iframe>' | |
def make_iframe(shader_code): #keep a single function? | |
script = make_script(shader_code) | |
return f"""<iframe width="640" height="420" srcdoc=\'{script}\' allowfullscreen></iframe>""" | |
def make_script(shader_code): | |
# code copied and fixed(escaping single quotes to double quotes!!!) from https://webglfundamentals.org/webgl/webgl-shadertoy.html | |
script = (""" | |
<!-- Licensed under a BSD license. See license.html for license --> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> | |
<title>WebGL - Shadertoy</title> | |
<link type="text/css" href="https://webglfundamentals.org/webgl/resources/webgl-tutorials.css" rel="stylesheet" /> | |
<style> | |
.divcanvas { | |
position: relative; | |
display: inline-block; | |
} | |
canvas { | |
display: block; | |
} | |
.playpause { | |
position: absolute; | |
left: 10px; | |
top: 10px; | |
width: 100%; | |
height: 100%; | |
font-size: 60px; | |
justify-content: center; | |
align-items: center; | |
color: rgba(255, 255, 255, 0.3); | |
transition: opacity 0.2s ease-in-out; | |
} | |
.playpausehide, | |
.playpause:hover { | |
opacity: 0; | |
} | |
.iframe .divcanvas { | |
display: block; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="divcanvas"> | |
<canvas id="canvas"></canvas> | |
<div class="playpause">▶</div> | |
</div> | |
\nblank canvas here indicates that some of the shadertoy specific functions are not yet supported with this implementation (like #define I believe). you can always copy and paste the code into a shadertoy.com window to try. | |
</body> | |
<!-- | |
for most samples webgl-utils only provides shader compiling/linking and | |
canvas resizing because why clutter the examples with code thats the same in every sample. | |
See https://webglfundamentals.org/webgl/lessons/webgl-boilerplate.html | |
and https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html | |
for webgl-utils, m3, m4, and webgl-lessons-ui. | |
--> | |
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script> | |
<script> | |
"use strict"; | |
function main() { | |
// Get A WebGL context | |
/** @type {HTMLCanvasElement} */ | |
const canvas = document.querySelector("#canvas"); | |
const gl = canvas.getContext("webgl"); | |
if (!gl) { | |
return; | |
} | |
const vs = ` | |
// an attribute will receive data from a buffer | |
attribute vec4 a_position; | |
// all shaders have a main function | |
void main() { | |
// gl_Position is a special variable a vertex shader | |
// is responsible for setting | |
gl_Position = a_position; | |
} | |
`; | |
const fs = ` | |
precision highp float; | |
uniform vec2 iResolution; | |
uniform vec2 iMouse; | |
uniform float iTime; | |
""" + shader_code + """ | |
void main() { | |
mainImage(gl_FragColor, gl_FragCoord.xy); | |
} | |
`; | |
// setup GLSL program | |
const program = webglUtils.createProgramFromSources(gl, [vs, fs]); | |
// look up where the vertex data needs to go. | |
const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); | |
// look up uniform locations | |
const resolutionLocation = gl.getUniformLocation(program, "iResolution"); | |
const mouseLocation = gl.getUniformLocation(program, "iMouse"); | |
const timeLocation = gl.getUniformLocation(program, "iTime"); | |
// Create a buffer to put three 2d clip space points in | |
const positionBuffer = gl.createBuffer(); | |
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// fill it with a 2 triangles that cover clipspace | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
-1, -1, // first triangle | |
1, -1, | |
-1, 1, | |
-1, 1, // second triangle | |
1, -1, | |
1, 1, | |
]), gl.STATIC_DRAW); | |
const playpauseElem = document.querySelector(".playpause"); | |
const inputElem = document.querySelector(".divcanvas"); | |
inputElem.addEventListener("mouseover", requestFrame); | |
inputElem.addEventListener("mouseout", cancelFrame); | |
let mouseX = 0; | |
let mouseY = 0; | |
function setMousePosition(e) { | |
const rect = inputElem.getBoundingClientRect(); | |
mouseX = e.clientX - rect.left; | |
mouseY = rect.height - (e.clientY - rect.top) - 1; // bottom is 0 in WebGL | |
} | |
inputElem.addEventListener("mousemove", setMousePosition); | |
inputElem.addEventListener("touchstart", (e) => { | |
e.preventDefault(); | |
playpauseElem.classList.add("playpausehide"); | |
requestFrame(); | |
}, {passive: false}); | |
inputElem.addEventListener("touchmove", (e) => { | |
e.preventDefault(); | |
setMousePosition(e.touches[0]); | |
}, {passive: false}); | |
inputElem.addEventListener("touchend", (e) => { | |
e.preventDefault(); | |
playpauseElem.classList.remove("playpausehide"); | |
cancelFrame(); | |
}, {passive: false}); | |
let requestId; | |
function requestFrame() { | |
if (!requestId) { | |
requestId = requestAnimationFrame(render); | |
} | |
} | |
function cancelFrame() { | |
if (requestId) { | |
cancelAnimationFrame(requestId); | |
requestId = undefined; | |
} | |
} | |
let then = 0; | |
let time = 0; | |
function render(now) { | |
requestId = undefined; | |
now *= 0.001; // convert to seconds | |
const elapsedTime = Math.min(now - then, 0.1); | |
time += elapsedTime; | |
then = now; | |
webglUtils.resizeCanvasToDisplaySize(gl.canvas); | |
// Tell WebGL how to convert from clip space to pixels | |
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); | |
// Tell it to use our program (pair of shaders) | |
gl.useProgram(program); | |
// Turn on the attribute | |
gl.enableVertexAttribArray(positionAttributeLocation); | |
// Bind the position buffer. | |
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) | |
gl.vertexAttribPointer( | |
positionAttributeLocation, | |
2, // 2 components per iteration | |
gl.FLOAT, // the data is 32bit floats | |
false, // dont normalize the data | |
0, // 0 = move forward size * sizeof(type) each iteration to get the next position | |
0, // start at the beginning of the buffer | |
); | |
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height); | |
gl.uniform2f(mouseLocation, mouseX, mouseY); | |
gl.uniform1f(timeLocation, time); | |
gl.drawArrays( | |
gl.TRIANGLES, | |
0, // offset | |
6, // num vertices to process | |
); | |
requestFrame(); | |
} | |
requestFrame(); | |
requestAnimationFrame(cancelFrame); | |
} | |
main(); | |
</script> | |
</html> | |
""") | |
return script | |