{
  "kind": "code",
  "model": "gemini-4-argon",
  "generatedAt": "2026-10-21T05:31:06.343Z",
  "prompt": "Using the attached blue ceramic cup image as a visual reference, create a rotatable 3D cup concept with dimension and material controls, zoom and reset. Use CSS 3D or canvas projected geometry with visible depth, responsive controls and no external resources. Do not claim CAD accuracy. Return JSON {title,content:\"complete self-contained HTML document\"}. Include only inline scripts, CSS and inline SVG or canvas, no external libraries, URLs, network access or imports. Make the example polished, responsive, keyboard and touch usable. Support prefers-reduced-motion and pause animation when document.hidden. Include meaningful accessible text. Never claim tests were run. Keep implementation concise under 10000 characters.",
  "sourceDocument": null,
  "sourceImage": "source-cup.png",
  "scope": "Direct real Vertex generation with production schema validation and JavaScript syntax checks. Not an account, billing or browser interaction test.",
  "usage": {
    "promptTokenCount": 1343,
    "candidatesTokenCount": 6308,
    "totalTokenCount": 7651,
    "trafficType": "ON_DEMAND",
    "promptTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 243
      },
      {
        "modality": "IMAGE",
        "tokenCount": 1100
      }
    ],
    "candidatesTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 6308
      }
    ]
  },
  "output": {
    "title": "Artisanal Blue Glaze Ceramic Cup 3D Concept",
    "content": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"><title>3D Ceramic Cup Concept</title><style>:root{--bg:#f2f3f5;--panel:rgba(255,255,255,0.88);--text:#1e242b;--muted:#5a6570;--accent:#235789;--border:#d8dde3}*{box-sizing:border-box;margin:0;padding:0}body{font-family:system-ui,-apple-system,sans-serif;background:linear-gradient(180deg,#dcdfe4 0%,#f5f6f8 45%,#eef0f3 100%);color:var(--text);min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden}header{padding:1rem 1.5rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--border);background:var(--panel);backdrop-filter:blur(8px)}h1{font-size:1.15rem;font-weight:600;letter-spacing:-0.01em}p.sub{font-size:0.8rem;color:var(--muted)}main{flex:1;display:grid;grid-template-columns:1fr 310px;gap:1rem;padding:1rem;max-width:1400px;width:100%;margin:0 auto;align-items:stretch}@media(max-width:820px){main{grid-template-columns:1fr;grid-template-rows:minmax(360px,52vh) auto}}.viewport{position:relative;background:radial-gradient(circle at 50% 42%,#ffffff 0%,#e6e9ef 100%);border-radius:14px;border:1px solid var(--border);box-shadow:inset 0 2px 12px rgba(0,0,0,0.04);overflow:hidden;display:flex;align-items:center;justify-content:center;touch-action:none;outline:none}.viewport:focus-visible{box-shadow:0 0 0 3px var(--accent)}canvas{width:100%;height:100%;display:block;cursor:grab}canvas:active{cursor:grabbing}.hud{position:absolute;bottom:12px;left:12px;right:12px;display:flex;justify-content:space-between;align-items:center;pointer-events:none;font-size:0.75rem;color:var(--muted);gap:8px;flex-wrap:wrap}.badge{background:var(--panel);padding:6px 10px;border-radius:8px;border:1px solid var(--border);backdrop-filter:blur(4px);pointer-events:auto}.controls{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:1.2rem;display:flex;flex-direction:column;gap:1rem;backdrop-filter:blur(8px);box-shadow:0 4px 20px rgba(0,0,0,0.04)}.group{display:flex;flex-direction:column;gap:0.45rem}.group-title{font-size:0.75rem;text-transform:uppercase;letter-spacing:0.06em;color:var(--muted);font-weight:700;margin-top:0.2rem}label{display:flex;justify-content:space-between;font-size:0.85rem;font-weight:500}label span.val{color:var(--muted);font-variant-numeric:tabular-nums}input[type=range]{width:100%;accent-color:var(--accent);cursor:pointer}select,button{font:inherit;font-size:0.85rem;padding:0.5rem 0.75rem;border-radius:8px;border:1px solid var(--border);background:#fff;color:var(--text);cursor:pointer;transition:all 0.15s}select:hover,button:hover{border-color:var(--accent)}button:active{transform:translateY(1px)}.btn-row{display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;margin-top:auto}.btn-primary{background:var(--accent);color:#fff;border-color:var(--accent)}.btn-primary:hover{background:#1b446b}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}</style></head><body><header><div><h1>Artisanal Reactive-Glaze Cup — 3D Concept Explorer</h1><p class=\"sub\">Interactive projected 3D geometry inspired by stoneware espresso cup reference (Visual concept only, non-CAD)</p></div></header><main><div class=\"viewport\" id=\"vp\" tabindex=\"0\" role=\"region\" aria-label=\"Interactive 3D cup viewport. Use arrow keys or drag to rotate, plus and minus keys or scroll to zoom.\"><canvas id=\"cv\"></canvas><div class=\"hud\"><span class=\"badge\">Drag / Arrows: Rotate &bull; Scroll / +-: Zoom</span><span class=\"badge\" id=\"stat\">Vol ~ 145 ml</span></div><p class=\"sr-only\" id=\"a11y-desc\">A rounded stoneware ceramic cup with a mottled cobalt and denim-blue glaze, toasted ochre-brown ceramic rim and foot, dark glossy interior, and a D-shaped side ear handle.</p></div><aside class=\"controls\" aria-label=\"Cup customization controls\"><div class=\"group\"><div class=\"group-title\">Dimensions</div><label for=\"rSlider\">Cup Width (Radius) <span class=\"val\" id=\"rVal\">48 mm</span></label><input id=\"rSlider\" type=\"range\" min=\"36\" max=\"64\" value=\"48\" step=\"1\"><label for=\"hSlider\">Cup Height <span class=\"val\" id=\"hVal\">66 mm</span></label><input id=\"hSlider\" type=\"range\" min=\"48\" max=\"92\" value=\"66\" step=\"1\"><label for=\"bSlider\">Belly Curvature <span class=\"val\" id=\"bVal\">65%</span></label><input id=\"bSlider\" type=\"range\" min=\"20\" max=\"100\" value=\"65\" step=\"1\"><label for=\"hdSlider\">Handle Projection <span class=\"val\" id=\"hdVal\">24 mm</span></label><input id=\"hdSlider\" type=\"range\" min=\"14\" max=\"36\" value=\"24\" step=\"1\"></div><div class=\"group\"><div class=\"group-title\">Surface &amp; Glaze</div><label for=\"glazeSel\">Glaze Palette</label><select id=\"glazeSel\"><option value=\"0\">Reactive Cobalt &amp; Ochre Rim (Reference)</option><option value=\"1\">Deep Midnight Indigo</option><option value=\"2\">Celadon Seafoam &amp; Iron</option><option value=\"3\">Raw Speckled Clay</option></select><label for=\"glossSlider\">Specular Gloss <span class=\"val\" id=\"glossVal\">78%</span></label><input id=\"glossSlider\" type=\"range\" min=\"10\" max=\"100\" value=\"78\" step=\"1\"><label for=\"rimSlider\">Toasted Rim Band <span class=\"val\" id=\"rimVal\">55%</span></label><input id=\"rimSlider\" type=\"range\" min=\"10\" max=\"100\" value=\"55\" step=\"1\"></div><div class=\"group\"><div class=\"group-title\">Camera &amp; Motion</div><label for=\"zoomSlider\">Zoom Scale <span class=\"val\" id=\"zoomVal\">100%</span></label><input id=\"zoomSlider\" type=\"range\" min=\"60\" max=\"160\" value=\"100\" step=\"2\"></div><div class=\"btn-row\"><button type=\"button\" id=\"spinBtn\" aria-pressed=\"false\">Auto-Spin: Off</button><button type=\"button\" id=\"resetBtn\" class=\"btn-primary\">Reset View</button></div></aside></main><script>(function(){const cv=document.getElementById('cv'),ctx=cv.getContext('2d'),vp=document.getElementById('vp');const reducedMotion=window.matchMedia('(prefers-reduced-motion: reduce)').matches;const defaults={r:48,h:66,belly:65,handle:24,glaze:0,gloss:78,rim:55,zoom:100,yaw:-0.25,pitch:0.28,spin:!reducedMotion};let st={...defaults};const palettes=[{name:'Cobalt',hBase:212,sBase:68,lBase:36,hRim:36,sRim:32,lRim:46,inL:14},{name:'Midnight',hBase:226,sBase:62,lBase:22,hRim:28,sRim:25,lRim:35,inL:10},{name:'Celadon',hBase:172,sBase:38,lBase:44,hRim:34,sRim:38,lRim:42,inL:20},{name:'RawClay',hBase:28,sBase:26,lBase:54,hRim:25,sRim:35,lRim:38,inL:26}];const ui={r:document.getElementById('rSlider'),h:document.getElementById('hSlider'),belly:document.getElementById('bSlider'),handle:document.getElementById('hdSlider'),glaze:document.getElementById('glazeSel'),gloss:document.getElementById('glossSlider'),rim:document.getElementById('rimSlider'),zoom:document.getElementById('zoomSlider'),spin:document.getElementById('spinBtn'),reset:document.getElementById('resetBtn')};function syncUI(){ui.r.value=st.r;document.getElementById('rVal').textContent=st.r+' mm';ui.h.value=st.h;document.getElementById('hVal').textContent=st.h+' mm';ui.belly.value=st.belly;document.getElementById('bVal').textContent=st.belly+'%';ui.handle.value=st.handle;document.getElementById('hdVal').textContent=st.handle+' mm';ui.glaze.value=st.glaze;ui.gloss.value=st.gloss;document.getElementById('glossVal').textContent=st.gloss+'%';ui.rim.value=st.rim;document.getElementById('rimVal').textContent=st.rim+'%';ui.zoom.value=Math.round(st.zoom);document.getElementById('zoomVal').textContent=Math.round(st.zoom)+'%';ui.spin.textContent='Auto-Spin: '+(st.spin?'On':'Off');ui.spin.setAttribute('aria-pressed',st.spin);const vol=Math.round(Math.PI*Math.pow(st.r*0.088,2)*(st.h*0.082)*(1+st.belly*0.002));document.getElementById('stat').textContent='Approx. Vol ~ '+vol+' ml';}['r','h','belly','handle','gloss','rim','zoom'].forEach(k=>{ui[k].addEventListener('input',e=>{st[k]=parseFloat(e.target.value);syncUI();requestRender();});});ui.glaze.addEventListener('change',e=>{st.glaze=parseInt(e.target.value,10);syncUI();requestRender();});ui.spin.addEventListener('click',()=>{st.spin=!st.spin;syncUI();requestRender();});ui.reset.addEventListener('click',()=>{st={...defaults,spin:false};syncUI();requestRender();});let dpr=1,W=600,H=500;function resize(){const rect=vp.getBoundingClientRect();dpr=Math.min(window.devicePixelRatio||1,2);W=rect.width;H=rect.height;cv.width=W*dpr;cv.height=H*dpr;requestRender();}window.addEventListener('resize',resize);let dragging=false,lx=0,ly=0;cv.addEventListener('pointerdown',e=>{dragging=true;lx=e.clientX;ly=e.clientY;st.spin=false;syncUI();cv.setPointerCapture(e.pointerId);vp.focus();});cv.addEventListener('pointermove',e=>{if(!dragging)return;const dx=e.clientX-lx,dy=e.clientY-ly;lx=e.clientX;ly=e.clientY;st.yaw+=dx*0.009;st.pitch=Math.max(-0.6,Math.min(1.15,st.pitch+dy*0.009));requestRender();});window.addEventListener('pointerup',()=>{dragging=false;});cv.addEventListener('wheel',e=>{e.preventDefault();st.zoom=Math.max(60,Math.min(160,st.zoom-e.deltaY*0.08));syncUI();requestRender();},{passive:false});vp.addEventListener('keydown',e=>{const step=0.08;if(e.key==='ArrowLeft'){st.yaw-=step;st.spin=false;}else if(e.key==='ArrowRight'){st.yaw+=step;st.spin=false;}else if(e.key==='ArrowUp'){st.pitch=Math.min(1.15,st.pitch+step);}else if(e.key==='ArrowDown'){st.pitch=Math.max(-0.6,st.pitch-step);}else if(e.key==='+'||e.key==='='){st.zoom=Math.min(160,st.zoom+6);}else if(e.key==='-'){st.zoom=Math.max(60,st.zoom-6);}else return;e.preventDefault();syncUI();requestRender();});function rotProj(x,y,z,cy,sy,cp,sp,scale){const x1=x*cy-z*sy,z1=x*sy+z*cy;const y2=y*cp-z1*sp,z2=y*sp+z1*cp;const fov=620/(620+z2);return{x:W*0.5+x1*scale*fov,y:H*0.54-y2*scale*fov,z:z2,nx:x1,ny:y2,nz:z2};}function buildAndDraw(){ctx.save();ctx.scale(dpr,dpr);ctx.clearRect(0,0,W,H);const scale=(Math.min(W,H)/210)*(st.zoom/100);const cy=Math.cos(st.yaw),sy=Math.sin(st.yaw),cp=Math.cos(st.pitch),sp=Math.sin(st.pitch);const R=st.r,Hc=st.h,B=st.belly/100,Hd=st.handle;const shY=-Hc*0.5;const shCenter=rotProj(-R*0.35,shY,R*0.15,cy,sy,cp,sp,scale);const shRx=R*scale*1.55,shRy=R*scale*Math.max(0.28,0.65*Math.sin( Math.max(0.2,st.pitch+0.35) ));const grad=ctx.createRadialGradient(shCenter.x,shCenter.y,shRx*0.1,shCenter.x,shCenter.y,shRx);grad.addColorStop(0,'rgba(22,30,40,0.28)');grad.addColorStop(0.55,'rgba(22,30,40,0.11)');grad.addColorStop(1,'rgba(22,30,40,0)');ctx.fillStyle=grad;ctx.beginPath();ctx.ellipse(shCenter.x,shCenter.y,shRx,shRy,0,0,Math.PI*2);ctx.fill();const U=24,V=38;const ring=[];for(let i=0;i<=U;i++){const t=i/U;let y,r,isIn=false,vCoord=t;if(t<=0.72){const u=t/0.72;y=(u-0.5)*Hc;const foot=u<0.09?0.58+0.42*(u/0.09):0.64+0.36*Math.sin(Math.pow(u,0.62)*Math.PI*0.78);const bulge=Math.sin(u*Math.PI)*0.24*B;const lip=u>0.92?Math.sin((u-0.92)/0.08*Math.PI)*0.035:0;r=R*(foot+bulge+lip);}else{isIn=true;const u=(t-0.72)/0.28;y=(0.5-u*0.86)*Hc;const innerCurve=Math.cos(u*Math.PI*0.48);r=R*0.89*innerCurve;vCoord=1-u*0.85;}const row=[];for(let j=0;j<V;j++){const a=(j/V)*Math.PI*2;const px=r*Math.cos(a),pz=r*Math.sin(a);const p=rotProj(px,y,pz,cy,sy,cp,sp,scale);p.u=vCoord;p.a=a;p.isIn=isIn;p.rawT=t;row.push(p);}ring.push(row);}const faces=[];const pal=palettes[st.glaze];const rimBand=0.04+(st.rim/100)*0.09;const glossF=st.gloss/100;for(let i=0;i<U;i++){for(let j=0;j<V;j++){const jn=(j+1)%V;const p0=ring[i][j],p1=ring[i][jn],p2=ring[i+1][jn],p3=ring[i+1][j];const zAvg=(p0.z+p1.z+p2.z+p3.z)*0.25;const ux=p1.x-p0.x,uy=p1.y-p0.y,vx=p3.x-p0.x,vy=p3.y-p0.y;const cross=ux*vy-uy*vx;let nx=Math.cos(p0.a+Math.PI/V),nz=Math.sin(p0.a+Math.PI/V),ny=(i<3)?-0.45:(i===17?0.85:0.12*(0.5-p0.u));if(p0.isIn){nx=-nx*0.7;nz=-nz*0.7;ny=0.45;}const rx=nx*cy-nz*sy,rz=nx*sy+nz*cy;const rny=ny*cp-rz*sp,rnz=ny*sp+rz*cp;const lDirX=-0.38,lDirY=0.62,lDirZ=-0.68;const diff=Math.max(0,rx*lDirX+rny*lDirY+rnz*lDirZ);const spec=Math.pow(Math.max(0,rx*-0.22+rny*0.52+rnz*-0.82),14+glossF*28)*glossF;const mottle=Math.sin(j*3.1+i*0.9)*4+Math.cos(j*5.0-i*1.7)*3;const drip=Math.sin(j*4)*0.035;const distRim=Math.abs(p0.rawT-0.70)+drip*0.4;const distFoot=p0.rawT;let h=pal.hBase+mottle*0.7,s=pal.sBase,l=pal.lBase+mottle*0.9;if(p0.isIn){l=pal.inL+diff*18+spec*38;s=pal.sBase*0.85;}else if(distRim<rimBand){const blend=1-(distRim/rimBand);h=pal.hBase*(1-blend)+pal.hRim*blend;s=pal.sBase*(1-blend)+pal.sRim*blend;l=(pal.lBase*(1-blend)+pal.lRim*blend)+diff*24+spec*45;}else if(distFoot<0.08){const blend=1-(distFoot/0.08);h=pal.hBase*(1-blend)+pal.hRim*blend;s=pal.sBase*(1-blend)+pal.sRim*blend;l=(pal.lBase*0.55*(1-blend)+pal.lRim*0.7*blend)+diff*16;}else{const bellyLight=Math.sin(p0.u*Math.PI)*8;l+=bellyLight+diff*26+spec*52-Math.max(0,(0.28-p0.u)*45);}l=Math.max(6,Math.min(95,l));faces.push({p0,p1,p2,p3,z:zAvg,col:`hsl(${Math.round(h)},${Math.round(s)}%,${Math.round(l)}%)`,cross});}}const HU=18,HV=10;const hAttachR=R*(0.66+0.18*B);const hRing=[];for(let i=0;i<=HU;i++){const t=i/HU;const ang=(t-0.5)*Math.PI*1.08;const cx=hAttachR-2+Hd*Math.cos(ang);const cyPos=Hc*(0.06+0.31*Math.sin(ang));const tubeR=R*0.095*(1-0.18*Math.cos(ang));const tx=-Hd*Math.sin(ang),ty=Hc*0.31*Math.cos(ang);const len=Math.hypot(tx,ty)||1;const nx=ty/len,ny=-tx/len;const row=[];for(let j=0;j<HV;j++){const a=(j/HV)*Math.PI*2;const ca=Math.cos(a),sa=Math.sin(a);const px=cx+tubeR*ca*nx;const py=cyPos+tubeR*ca*ny;const pz=tubeR*sa*1.25;const p=rotProj(px,py,pz,cy,sy,cp,sp,scale);p.t=t;p.a=a;row.push(p);}hRing.push(row);}for(let i=0;i<HU;i++){for(let j=0;j<HV;j++){const jn=(j+1)%HV;const p0=hRing[i][j],p1=hRing[i][jn],p2=hRing[i+1][jn],p3=hRing[i+1][j];const zAvg=(p0.z+p1.z+p2.z+p3.z)*0.25;const a=p0.a;const nx=Math.cos(a),nz=Math.sin(a),ny=Math.sin((p0.t-0.5)*Math.PI);const rx=nx*cy-nz*sy,rz=nx*sy+nz*cy;const rny=ny*cp-rz*sp,rnz=ny*sp+rz*cp;const diff=Math.max(0,rx*-0.35+rny*0.65+rnz*-0.65);const spec=Math.pow(Math.max(0,rx*-0.2+rny*0.5+rnz*-0.8),18)*glossF;const outerEdge=Math.cos(a)>0.35;const h=outerEdge?pal.hRim:pal.hBase;const s=outerEdge?pal.sRim:pal.sBase;const l=Math.max(10,Math.min(92,(outerEdge?pal.lRim*0.85:pal.lBase*0.8)+diff*28+spec*48));faces.push({p0,p1,p2,p3,z:zAvg,col:`hsl(${Math.round(h)},${Math.round(s)}%,${Math.round(l)}%)`});}}faces.sort((a,b)=>b.z-a.z);ctx.lineJoin='round';for(let k=0;k<faces.length;k++){const f=faces[k];ctx.fillStyle=f.col;ctx.strokeStyle=f.col;ctx.lineWidth=0.65;ctx.beginPath();ctx.moveTo(f.p0.x,f.p0.y);ctx.lineTo(f.p1.x,f.p1.y);ctx.lineTo(f.p2.x,f.p2.y);ctx.lineTo(f.p3.x,f.p3.y);ctx.closePath();ctx.fill();ctx.stroke();}ctx.restore();}let rafId=null;function tick(){rafId=null;if(document.hidden)return;if(st.spin){st.yaw+=0.0065;buildAndDraw();rafId=requestAnimationFrame(tick);}else{buildAndDraw();}}function requestRender(){if(!rafId)rafId=requestAnimationFrame(tick);}document.addEventListener('visibilitychange',()=>{if(!document.hidden&&st.spin)requestRender();});syncUI();resize();})();</script></body></html>"
  }
}