const API_BASE = "/api/shaders"; const nameInput = document.getElementById("name-input"); const authorInput = document.getElementById("author-input"); const codeInput = document.getElementById("code-input"); const saveBtn = document.getElementById("save-btn"); const exampleBtn = document.getElementById("example-btn"); const listEl = document.getElementById("list"); const listCountEl = document.getElementById("list-count"); function esc(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } const EXAMPLE = `void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float t = iTime; float v = sin(uv.x * 9.0 + t * 2.0) + cos(uv.y * 8.0 - t * 1.4); vec3 col = 0.5 + 0.5 * cos(vec3(0.2, 1.2, 2.2) + v + t); fragColor = vec4(col, 1.0); }`; function validateClientCode(code) { const hasMainImage = code.includes("mainImage"); const hasAngleMain = code.includes("_umainImage"); if (!hasMainImage && !hasAngleMain) return "代码需包含 mainImage 或 _umainImage。"; return ""; } async function fetchList() { const res = await fetch(API_BASE); if (!res.ok) throw new Error("加载失败"); return res.json(); } function renderList(items) { listEl.innerHTML = ""; if (listCountEl) { listCountEl.textContent = items.length ? `${items.length} 项` : ""; } if (!items.length) { listEl.innerHTML = '