Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import json | |
| from pathlib import Path | |
| st.set_page_config(page_title="Shader + Comments JSON", layout="wide") | |
| st.title("🌀 Shader + Comments (Hugging Face Ready)") | |
| # ------------------------------- | |
| # Use /data folder for persistent storage | |
| # ------------------------------- | |
| DATA_DIR = Path("./data") | |
| DATA_DIR.mkdir(exist_ok=True) | |
| COMMENTS_FILE = DATA_DIR / "comments.json" | |
| # Load existing comments | |
| if COMMENTS_FILE.exists(): | |
| with open(COMMENTS_FILE, "r") as f: | |
| comments = json.load(f) | |
| else: | |
| comments = [] | |
| # ------------------------------- | |
| # Determine current shader | |
| # ------------------------------- | |
| shader_code_default = """ | |
| precision mediump float; | |
| uniform vec2 iResolution; | |
| uniform float iTime; | |
| void mainImage(out vec4 fragColor, in vec2 fragCoord) { | |
| vec2 uv = fragCoord / iResolution.xy; | |
| vec3 col = 0.5 + 0.5*cos(iTime + uv.xyx + vec3(0,2,4)); | |
| fragColor = vec4(col,1.0); | |
| } | |
| void main() { mainImage(gl_FragColor, gl_FragCoord.xy); } | |
| """ | |
| latest_shader = shader_code_default | |
| for c in reversed(comments): | |
| if c.get("type") == "shader": | |
| latest_shader = c["content"] | |
| break | |
| # ------------------------------- | |
| # Shader editor | |
| # ------------------------------- | |
| shader_code = st.text_area("Shader Code (GLSL Fragment Shader)", latest_shader, height=250) | |
| # ------------------------------- | |
| # WebGL Canvas | |
| # ------------------------------- | |
| html_code = f""" | |
| <canvas id="glcanvas" width="800" height="500"></canvas> | |
| <script> | |
| const canvas = document.getElementById('glcanvas'); | |
| const gl = canvas.getContext('webgl'); | |
| if (!gl) {{ | |
| alert('WebGL not supported'); | |
| }} | |
| const vertCode = ` | |
| attribute vec4 a_position; | |
| void main() {{ | |
| gl_Position = a_position; | |
| }} | |
| `; | |
| const fragCode = `{shader_code}`; | |
| function createShader(gl, type, source) {{ | |
| const shader = gl.createShader(type); | |
| gl.shaderSource(shader, source); | |
| gl.compileShader(shader); | |
| if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {{ | |
| alert(gl.getShaderInfoLog(shader)); | |
| }} | |
| return shader; | |
| }} | |
| const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertCode); | |
| const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragCode); | |
| const program = gl.createProgram(); | |
| gl.attachShader(program, vertexShader); | |
| gl.attachShader(program, fragmentShader); | |
| gl.linkProgram(program); | |
| gl.useProgram(program); | |
| const positionBuffer = gl.createBuffer(); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); | |
| gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ | |
| -1, -1, 1, -1, -1, 1, | |
| -1, 1, 1, -1, 1, 1 | |
| ]), gl.STATIC_DRAW); | |
| const positionLoc = gl.getAttribLocation(program, "a_position"); | |
| gl.enableVertexAttribArray(positionLoc); | |
| gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); | |
| const iResolution = gl.getUniformLocation(program, "iResolution"); | |
| const iTime = gl.getUniformLocation(program, "iTime"); | |
| function render(time) {{ | |
| gl.uniform2f(iResolution, canvas.width, canvas.height); | |
| gl.uniform1f(iTime, time * 0.001); | |
| gl.drawArrays(gl.TRIANGLES, 0, 6); | |
| requestAnimationFrame(render); | |
| }} | |
| requestAnimationFrame(render); | |
| </script> | |
| """ | |
| st.components.v1.html(html_code, height=520) | |
| # ------------------------------- | |
| # Comments Section | |
| # ------------------------------- | |
| st.markdown("---") | |
| st.subheader("💬 Comments / Add New Shader") | |
| ##comment_type = st.radio("Type", ["Normal Comment", "New Shader"]) | |
| with st.form("comment_form", clear_on_submit=True): | |
| user_name = st.text_input("Your name", "") | |
| user_content = st.text_area("Content", "", height=80) | |
| submitted = st.form_submit_button("Submit") | |
| if submitted and user_content.strip(): | |
| new_comment = { | |
| "name": user_name or "Anonymous", | |
| "content": user_content, | |
| } | |
| comments.append(new_comment) | |
| # Save to JSON in /data folder | |
| with open(COMMENTS_FILE, "w") as f: | |
| json.dump(comments, f, indent=2) | |
| st.success("Saved!") | |
| # Display all comments | |
| for c in reversed(comments): | |
| st.markdown(f"**{c['name']}**: {c['content']}") |