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 | |