|
|
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)") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DATA_DIR = Path("./data") |
|
|
DATA_DIR.mkdir(exist_ok=True) |
|
|
COMMENTS_FILE = DATA_DIR / "comments.json" |
|
|
|
|
|
|
|
|
if COMMENTS_FILE.exists(): |
|
|
with open(COMMENTS_FILE, "r") as f: |
|
|
comments = json.load(f) |
|
|
else: |
|
|
comments = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_code = st.text_area("Shader Code (GLSL Fragment Shader)", latest_shader, height=250) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.markdown("---") |
|
|
st.subheader("💬 Comments / Add 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) |
|
|
|
|
|
|
|
|
with open(COMMENTS_FILE, "w") as f: |
|
|
json.dump(comments, f, indent=2) |
|
|
|
|
|
st.success("Saved!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for c in reversed(comments): |
|
|
st.markdown(f"**{c['name']}**: {c['content']}") |