Download index.html from TheWheke/Sentinel: direct link, hf CLI and curl.
- Browser
- Download file 7.29 kB
-
https://huggingface.co/spaces/TheWheke/Sentinel/resolve/main/index.html
- Command line
-
hf download hf://spaces/TheWheke/Sentinel/index.html
-
curl -L -o index.html https://huggingface.co/spaces/TheWheke/Sentinel/resolve/main/index.html
7.29 kB
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>Sentinel Demo — Single Timeline Color Cycle</title> | |
| <style> | |
| html,body{ | |
| margin:0; | |
| height:100%; | |
| background:#000; | |
| overflow:hidden; | |
| } | |
| canvas{ | |
| width:100%; | |
| height:100%; | |
| display:block; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="gl"></canvas> | |
| <script> | |
| (() => { | |
| const canvas=document.getElementById("gl"); | |
| const gl=canvas.getContext("webgl",{antialias:true}); | |
| if(!gl){ | |
| document.body.innerHTML="WebGL not supported"; | |
| return; | |
| } | |
| function resize(){ | |
| canvas.width=window.innerWidth; | |
| canvas.height=window.innerHeight; | |
| gl.viewport(0,0,canvas.width,canvas.height); | |
| } | |
| resize(); | |
| window.addEventListener("resize",resize); | |
| function compile(type,src){ | |
| const s=gl.createShader(type); | |
| gl.shaderSource(s,src); | |
| gl.compileShader(s); | |
| if(!gl.getShaderParameter(s, gl.COMPILE_STATUS)){ | |
| throw new Error(gl.getShaderInfoLog(s) || "shader compile failed"); | |
| } | |
| return s; | |
| } | |
| function program(v,f){ | |
| const p=gl.createProgram(); | |
| gl.attachShader(p,compile(gl.VERTEX_SHADER,v)); | |
| gl.attachShader(p,compile(gl.FRAGMENT_SHADER,f)); | |
| gl.linkProgram(p); | |
| if(!gl.getProgramParameter(p, gl.LINK_STATUS)){ | |
| throw new Error(gl.getProgramInfoLog(p) || "program link failed"); | |
| } | |
| return p; | |
| } | |
| const quad=gl.createBuffer(); | |
| gl.bindBuffer(gl.ARRAY_BUFFER,quad); | |
| gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([ | |
| -1,-1, 1,-1, -1, 1, | |
| -1, 1, 1,-1, 1, 1 | |
| ]),gl.STATIC_DRAW); | |
| const VS=` | |
| attribute vec2 a; | |
| varying vec2 v; | |
| void main(){ | |
| v=a*0.5+0.5; | |
| gl_Position=vec4(a,0.0,1.0); | |
| } | |
| `; | |
| /* ================================ | |
| APPROVED HALO SHADER (ADD-ONLY) | |
| - Added uniform vec3 uCol | |
| - Replaced hard-coded red with uCol | |
| ================================= */ | |
| const FS=` | |
| precision highp float; | |
| varying vec2 v; | |
| uniform vec2 r; | |
| uniform float t; | |
| /* ADD ONLY */ | |
| uniform vec3 uCol; | |
| float ring(vec2 p,float rad){ | |
| float d=length(p); | |
| return smoothstep(0.02,0.0,abs(d-rad)); | |
| } | |
| void main(){ | |
| vec2 uv=v*2.0-1.0; | |
| uv.x*=r.x/r.y; | |
| float time=t*0.8; | |
| float R=0.35+sin(time)*0.01; | |
| float phase=mod(floor(t/5.0),5.0); | |
| if(phase==1.0){ | |
| R+=sin(atan(uv.y,uv.x)*6.0+time)*0.005; | |
| } | |
| if(phase==2.0){ | |
| R+=sin(length(uv)*40.0-time*2.0)*0.002; | |
| } | |
| if(phase==3.0){ | |
| R+=sin(time*6.0)*0.015; | |
| } | |
| if(phase==4.0){ | |
| R+=sin(atan(uv.y,uv.x)*80.0+time*4.0)*0.008; | |
| } | |
| float base=ring(uv,R); | |
| float glow=exp(-8.0*abs(length(uv)-R)); | |
| /* CHANGED: from vec3 red to uCol */ | |
| vec3 color = | |
| uCol*(base*1.4) + | |
| uCol*(glow*0.8); | |
| gl_FragColor=vec4(color,1.0); | |
| } | |
| `; | |
| const prog=program(VS,FS); | |
| const uRes=gl.getUniformLocation(prog,"r"); | |
| const uTime=gl.getUniformLocation(prog,"t"); | |
| /* ADD ONLY */ | |
| const uCol = gl.getUniformLocation(prog,"uCol"); | |
| /* ========= ADD ONLY: overlay line program (color capable) ========= */ | |
| const LINE_VS=` | |
| attribute vec2 a; | |
| void main(){ | |
| gl_Position=vec4(a,0.0,1.0); | |
| } | |
| `; | |
| const LINE_FS=` | |
| precision highp float; | |
| uniform vec3 uColor; | |
| uniform float alpha; | |
| void main(){ | |
| gl_FragColor=vec4(uColor,alpha); | |
| } | |
| `; | |
| const lineProg=program(LINE_VS,LINE_FS); | |
| const lineA=gl.getAttribLocation(lineProg,"a"); | |
| const lineColor=gl.getUniformLocation(lineProg,"uColor"); | |
| const lineAlpha=gl.getUniformLocation(lineProg,"alpha"); | |
| const lineBuf=gl.createBuffer(); | |
| /* ========= timeline color cycle (single color active per full demo) ========= */ | |
| const TIMELINE_COLORS = [ | |
| { name:"red", rgb:[1.00,0.00,0.00] }, | |
| { name:"blue", rgb:[0.10,0.55,1.00] }, | |
| { name:"green",rgb:[0.00,1.00,0.35] }, | |
| { name:"gold", rgb:[1.00,0.78,0.12] } | |
| ]; | |
| const PHASE_SECONDS = 5; | |
| const PHASE_COUNT = 5; | |
| const DEMO_CYCLE_SECONDS = PHASE_SECONDS * PHASE_COUNT; // 25s | |
| function activeTimelineColor(time){ | |
| const completedCycles = Math.floor(time / DEMO_CYCLE_SECONDS); | |
| const idx = completedCycles % TIMELINE_COLORS.length; | |
| return TIMELINE_COLORS[idx].rgb; | |
| } | |
| /* ========= helpers ========= */ | |
| function pxToClip(x,y){ | |
| return [ | |
| (x/canvas.width)*2-1, | |
| 1-(y/canvas.height)*2 | |
| ]; | |
| } | |
| function useLine(color, alpha){ | |
| gl.useProgram(lineProg); | |
| gl.bindBuffer(gl.ARRAY_BUFFER, lineBuf); | |
| gl.enableVertexAttribArray(lineA); | |
| gl.vertexAttribPointer(lineA,2,gl.FLOAT,false,0,0); | |
| gl.uniform3f(lineColor, color[0], color[1], color[2]); | |
| gl.uniform1f(lineAlpha, alpha); | |
| } | |
| function drawLine(x1,y1,x2,y2,color,alpha){ | |
| const p1=pxToClip(x1,y1); | |
| const p2=pxToClip(x2,y2); | |
| useLine(color, alpha); | |
| gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([p1[0],p1[1], p2[0],p2[1]]), gl.STATIC_DRAW); | |
| gl.drawArrays(gl.LINES, 0, 2); | |
| } | |
| /* ========= scan arm (single color; phase 4 only) ========= */ | |
| function drawScanArm(time, color){ | |
| const phase = Math.floor(time/PHASE_SECONDS) % PHASE_COUNT; | |
| if(phase !== 4) return; | |
| const angle=time*0.7; | |
| const cx=canvas.width/2; | |
| const cy=canvas.height/2; | |
| const len=Math.max(canvas.width,canvas.height)*1.6; | |
| gl.enable(gl.BLEND); | |
| gl.blendFunc(gl.SRC_ALPHA, gl.ONE); | |
| const tailSteps=18; | |
| for(let i=0;i<tailSteps;i++){ | |
| const k=i/(tailSteps-1); | |
| const a=1.0-k; | |
| const tailAngle=angle - k*0.35; | |
| const tx=cx+Math.cos(tailAngle)*len; | |
| const ty=cy+Math.sin(tailAngle)*len; | |
| drawLine(cx,cy,tx,ty,color, 0.02 + a*0.08); | |
| } | |
| const x=cx+Math.cos(angle)*len; | |
| const y=cy+Math.sin(angle)*len; | |
| drawLine(cx,cy,x,y,color,0.36); | |
| gl.disable(gl.BLEND); | |
| } | |
| /* ========= bottom timeline (single color) ========= */ | |
| function drawTimeline(time, color){ | |
| const padX = Math.max(24, canvas.width*0.08); | |
| const xL = padX; | |
| const xR = canvas.width - padX; | |
| const w = xR - xL; | |
| const y = canvas.height - Math.max(110, canvas.height*0.16); | |
| gl.enable(gl.BLEND); | |
| gl.blendFunc(gl.SRC_ALPHA, gl.ONE); | |
| // base line | |
| drawLine(xL,y,xR,y,color,0.10); | |
| // ticks | |
| const ticks=18; | |
| for(let i=0;i<=ticks;i++){ | |
| const x=xL+(i/ticks)*w; | |
| const h=(i%3===0)?8:4; | |
| drawLine(x,y-h,x,y+h,color,0.08); | |
| } | |
| // pulse progresses over the FULL demo cycle (0..1) | |
| const cycleT = (time % DEMO_CYCLE_SECONDS) / DEMO_CYCLE_SECONDS; | |
| const eased = 0.5 - 0.5*Math.cos(cycleT * Math.PI * 2.0); | |
| const px = xL + eased*w; | |
| drawLine(px-14,y,px+14,y,color,0.55); | |
| drawLine(px,y-10,px,y+10,color,0.35); | |
| // trail | |
| for(let i=1;i<=10;i++){ | |
| const tx = px - i*10; | |
| if(tx < xL) break; | |
| drawLine(tx-4,y,tx+4,y,color,0.14*(1-i/11)); | |
| } | |
| gl.disable(gl.BLEND); | |
| } | |
| /* ========= bind halo ========= */ | |
| let aLoc=-1; | |
| function bindHalo(){ | |
| gl.useProgram(prog); | |
| gl.bindBuffer(gl.ARRAY_BUFFER,quad); | |
| aLoc = gl.getAttribLocation(prog,"a"); | |
| gl.enableVertexAttribArray(aLoc); | |
| gl.vertexAttribPointer(aLoc,2,gl.FLOAT,false,0,0); | |
| } | |
| const start=performance.now(); | |
| function draw(){ | |
| const time=(performance.now()-start)/1000; | |
| // active single color for entire display (halo + overlays) | |
| const color = activeTimelineColor(time); | |
| gl.clearColor(0,0,0,1); | |
| gl.clear(gl.COLOR_BUFFER_BIT); | |
| bindHalo(); | |
| gl.uniform2f(uRes, canvas.width, canvas.height); | |
| gl.uniform1f(uTime, time); | |
| // halo color (ADD ONLY) | |
| gl.uniform3f(uCol, color[0], color[1], color[2]); | |
| gl.drawArrays(gl.TRIANGLES,0,6); | |
| // overlays (same single color) | |
| drawScanArm(time, color); | |
| drawTimeline(time, color); | |
| requestAnimationFrame(draw); | |
| } | |
| draw(); | |
| })(); | |
| </script> | |
| </body> | |
| </html> |