shader-playground-0 / index.html
Mooooonk's picture
Add 2 files
8f23c64 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ShaderPlayground</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
#editor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: rgba(30, 41, 59, 0.9);
transition: background-color 0.3s ease;
}
#preview {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.control-panel {
position: absolute;
bottom: 20px;
right: 20px;
z-index: 20;
background: rgba(15, 23, 42, 0.8);
border-radius: 8px;
padding: 10px;
backdrop-filter: blur(5px);
}
.gradient-border {
border: 2px solid transparent;
background-clip: padding-box;
position: relative;
}
.gradient-border::after {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #6366f1, #8b5cf6, #ec4899);
z-index: -1;
border-radius: inherit;
}
</style>
</head>
<body class="bg-slate-900 text-slate-200 overflow-hidden h-screen">
<div id="preview"></div>
<div id="editor"></div>
<div class="control-panel gradient-border">
<div class="flex items-center space-x-4">
<div class="flex items-center">
<span class="text-sm mr-2">Editor Opacity:</span>
<input type="range" id="opacitySlider" min="0.1" max="1" step="0.1" value="0.9" class="w-24">
</div>
<button id="toggleEditor" class="px-3 py-1 bg-indigo-600 hover:bg-indigo-700 rounded-md text-sm font-medium transition-colors">
Toggle Editor
</button>
<button id="runShader" class="px-3 py-1 bg-emerald-600 hover:bg-emerald-700 rounded-md text-sm font-medium transition-colors">
Run Shader
</button>
</div>
</div>
<script>
// Initialize ACE Editor
const editor = ace.edit("editor");
editor.setTheme("ace/theme/twilight");
editor.session.setMode("ace/mode/glsl");
editor.setFontSize(14);
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true
});
// Default shader code
const defaultShader = `
// Based on https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
// background color
vec3 col = vec3(0.3 + 0.05*p.y);
// animate
float tt = mod(iTime,2.0)/2.0;
float ss = pow(tt,.2)*0.5 + 0.5;
ss = 1.0 + ss*0.5*sin(tt*6.2831*3.0 + p.y*0.5)*exp(-tt*4.0);
p *= vec2(0.5,1.5) + ss*vec2(0.5,-0.5);
// shape
float a = atan(p.x,p.y);
float r = length(p);
float h = abs(a);
float d = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h);
// color
float s = 1.0-0.5*clamp(r/d,0.0,1.0);
s = 0.75 + 0.75*p.x;
s *= 1.0-0.25*r;
s = 0.5 + 0.6*s;
s *= 0.5+0.5*pow( 1.0-clamp(r/d, 0.0, 1.0 ), 0.1 );
vec3 hcol = vec3(1.0,0.5*r,0.3)*s;
col = mix( col, hcol, smoothstep( -0.06, 0.06, d-r) );
fragColor = vec4(col,1.0);
}`;
editor.setValue(defaultShader.trim(), -1);
// Three.js setup for shader preview
let scene, camera, renderer, shaderMaterial;
const preview = document.getElementById('preview');
function initThreeJS() {
scene = new THREE.Scene();
camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
preview.appendChild(renderer.domElement);
const geometry = new THREE.PlaneGeometry(2, 2);
shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
iTime: { value: 0 },
iResolution: { value: new THREE.Vector3() }
},
vertexShader: `
void main() {
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: defaultShader
});
const mesh = new THREE.Mesh(geometry, shaderMaterial);
scene.add(mesh);
window.addEventListener('resize', onWindowResize);
onWindowResize();
animate();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
shaderMaterial.uniforms.iResolution.value.set(
window.innerWidth * window.devicePixelRatio,
window.innerHeight * window.devicePixelRatio,
1
);
}
function animate() {
requestAnimationFrame(animate);
shaderMaterial.uniforms.iTime.value = performance.now() / 1000;
renderer.render(scene, camera);
}
// Control panel functionality
const opacitySlider = document.getElementById('opacitySlider');
const toggleEditor = document.getElementById('toggleEditor');
const runShader = document.getElementById('runShader');
let editorVisible = true;
opacitySlider.addEventListener('input', () => {
const opacity = opacitySlider.value;
document.getElementById('editor').style.backgroundColor = `rgba(30, 41, 59, ${opacity})`;
});
toggleEditor.addEventListener('click', () => {
editorVisible = !editorVisible;
document.getElementById('editor').style.display = editorVisible ? 'block' : 'none';
toggleEditor.textContent = editorVisible ? 'Hide Editor' : 'Show Editor';
});
runShader.addEventListener('click', () => {
const shaderCode = editor.getValue();
try {
shaderMaterial.fragmentShader = `
uniform vec3 iResolution;
uniform float iTime;
void mainImage(out vec4 fragColor, in vec2 fragCoord);
void main() {
vec2 fragCoord = gl_FragCoord.xy;
vec4 fragColor;
mainImage(fragColor, fragCoord);
gl_FragColor = fragColor;
}
${shaderCode}
`;
shaderMaterial.needsUpdate = true;
// Show success message
const notification = document.createElement('div');
notification.className = 'fixed top-4 right-4 bg-emerald-600 text-white px-4 py-2 rounded-md shadow-lg z-50 animate-fade-in-out';
notification.textContent = 'Shader compiled successfully!';
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => notification.remove(), 300);
}, 2000);
} catch (e) {
// Show error message
const notification = document.createElement('div');
notification.className = 'fixed top-4 right-4 bg-rose-600 text-white px-4 py-2 rounded-md shadow-lg z-50';
notification.textContent = 'Shader error: ' + e.message;
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => notification.remove(), 300);
}, 3000);
}
});
// Initialize everything
window.addEventListener('load', () => {
initThreeJS();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Mooooonk/shader-playground-0" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>