Creative Visual Effects

Aurora Field Kaleidoscope Pattern

Complete a kaleidoscope pattern in an aurora field scenario: includes real content, actionable controls, clear status feedback, and responsive layout across sizes.

Creative Visual EffectsKaleidoscope PatternHTMLCanvasJavaScript
With JavaScript enabled, you can edit, run, and save this example. The fixed source is as follows:
<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Aurora Field Kaleidoscope Pattern</title>
  <style>
    :root { --ink:#3a2419; --paper:#fbf3df; --accent:#c66a2d; --secondary:#b5c88d; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:Didot,"Songti SC",serif; background:linear-gradient(30deg,transparent 48%,color-mix(in srgb,var(--accent) 9%,transparent) 49% 51%,transparent 52%),var(--paper);background-size:52px 90px; }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(1040px,calc(100% - 36px));margin:auto;padding:64px 0}.mast{display:grid;justify-items:center;text-align:center;border-block:3px double var(--accent);padding:26px;gap:20px;margin-bottom:32px}.mast h1{font-family:Didot,"Songti SC",serif;font-weight:700;font-size:clamp(38px,8vw,86px);letter-spacing:.035em;margin:0;line-height:1}.eyebrow{display:block;color:var(--accent);font:800 11px/1 ui-monospace,monospace;letter-spacing:.3em}.intro{max-width:600px;margin-inline:auto;line-height:1.8}.scenario{padding:8px 26px;border-inline:1px solid var(--accent);letter-spacing:.16em}.demo{border:4px double var(--accent);border-radius:0;clip-path:polygon(24px 0,calc(100% - 24px) 0,100% 24px,100% calc(100% - 24px),calc(100% - 24px) 100%,24px 100%,0 calc(100% - 24px),0 24px);position:relative;min-height:440px;overflow:hidden;padding:clamp(28px,5vw,60px);background:var(--paper)}@media(max-width:700px){.page{width:calc(100% - 20px);padding:24px 0}.mast{padding:18px}.demo{padding:18px}}
    .panel{padding:20px;border:1px solid color-mix(in srgb,var(--accent) 50%,transparent);border-radius:18px;background:color-mix(in srgb,var(--paper) 88%,transparent);box-shadow:inset 0 0 24px color-mix(in srgb,var(--accent) 7%,transparent)}.stack{display:grid;gap:16px}.row{display:flex;flex-wrap:wrap;gap:9px}.action{padding:11px 16px;border:1px solid var(--accent);border-radius:6px;color:var(--accent);background:transparent;box-shadow:0 0 14px color-mix(in srgb,var(--accent) 10%,transparent)}.action.primary,.action.is-active{color:var(--paper);background:var(--accent)}.status{min-height:24px;color:var(--secondary);text-shadow:0 0 10px currentColor}.metric{font-size:clamp(30px,7vw,64px);font-weight:900;text-shadow:0 0 18px color-mix(in srgb,var(--accent) 40%,transparent)}.muted{opacity:.7}.chip{padding:6px 9px;border:1px solid var(--secondary);border-radius:4px}.meter{height:7px;background:color-mix(in srgb,var(--accent) 15%,transparent)}.meter>i{display:block;height:100%;box-shadow:0 0 12px var(--accent);background:var(--accent)}
    .composition-gallery{margin:0;padding:clamp(8px,2vw,18px);border:1px solid var(--ink);background:color-mix(in srgb,var(--paper) 78%,transparent)}.gallery-caption{display:grid;grid-template-columns:auto 1fr auto;gap:16px;align-items:center;padding:15px 4px 2px;font-size:12px}.gallery-caption::before,.gallery-caption::after{content:"";height:1px;background:var(--line)}.gallery-caption strong{font:800 11px/1.2 ui-monospace,monospace;letter-spacing:.16em;text-transform:uppercase}.composition-gallery .demo{box-shadow:none}.composition-gallery .demo::before{content:"";position:absolute;inset:10px;border:1px dashed color-mix(in srgb,var(--accent) 36%,transparent);pointer-events:none}
    .kaleidoscope-lab{display:grid;grid-template-columns:minmax(300px,1fr) minmax(220px,.55fr);gap:16px;align-items:stretch}.kaleidoscope-lab canvas{width:100%;max-height:520px;aspect-ratio:1;border:1px solid var(--line);border-radius:50%;background:#100b24;touch-action:none}.kaleidoscope-controls{display:grid;align-content:center;gap:17px}.kaleidoscope-controls label{display:grid;grid-template-columns:1fr auto;gap:8px;font-weight:800}.kaleidoscope-controls input{grid-column:1/-1}@media(max-width:740px){.kaleidoscope-lab{grid-template-columns:1fr}.kaleidoscope-lab canvas{max-height:none}}.workflow-compare{display:grid;grid-template-columns:minmax(230px,.55fr) minmax(0,1.45fr);gap:18px}.compare-stage{display:grid;gap:12px;min-width:0}.compare-stage>header{display:flex;justify-content:space-between;gap:16px;align-items:end}.compare-stage h2{margin:.2em 0}.compare-core{--compare-split:50%;min-width:0;padding:14px;clip-path:inset(0 calc(100% - var(--compare-split)) 0 0);outline:1px dashed var(--accent);outline-offset:-8px;transition:clip-path .25s,filter .25s}.compare-core[data-compare-channel="B"]{filter:hue-rotate(32deg) saturate(1.15)}.compare-controls{display:grid;align-content:start;gap:16px;padding:20px;border:1px solid var(--line);border-radius:24px 4px 24px 4px;background:var(--paper)}.compare-controls fieldset,.compare-controls>label{display:grid;gap:8px}.compare-controls input[type="range"]{width:100%}#workflowCompareShelf{display:grid;gap:6px;padding:0;margin:0;list-style:none}#workflowCompareShelf li{display:grid;grid-template-columns:auto 1fr auto;gap:8px;padding:9px;border-top:1px solid var(--line);font-size:12px}@media(max-width:900px){.workflow-compare{grid-template-columns:1fr}.compare-stage{order:-1}.compare-core{clip-path:none;border-left:8px solid var(--accent)}}
  </style>
</head>
<body data-aesthetic="art-deco" data-composition="gallery-frame">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">art-deco / kaleidoscope pattern / INTERMEDIATE</span><h1>Aurora Field Kaleidoscope Pattern</h1><p class="intro">Complete a kaleidoscope pattern in an aurora field scenario: includes real content, actionable controls, clear status feedback, and responsive layout across sizes.</p></div><span class="scenario">Aurora Field</span></header>
    <figure class="composition-gallery"><section class="demo" aria-label="Aurora Field Kaleidoscope Pattern Interaction Area"><div class="workflow-compare"><form id="workflowCompareControls" class="compare-controls"><fieldset><legend>Reference Channel</legend><label><input type="radio" name="workflowChannel" value="A" checked>A · Green Light Curtain</label><label><input type="radio" name="workflowChannel" value="B">B · magenta light band</label></fieldset><label>Exposure Time Weight<input id="workflowCompareWeight" type="range" min="10" max="90" value="50"><output id="workflowCompareWeightValue">50 seconds</output></label><label><input id="workflowCompareFreeze" type="checkbox">Freeze current version</label><button id="workflowCompareCapture" class="action primary" type="button">Sample and save exposure</button><ol id="workflowCompareShelf" aria-label="Version Sampling Record"></ol></form><section class="compare-stage"><header><span class="eyebrow">Aurora Field COMPARE</span><h2>Aurora A/B Comparison</h2><output id="workflowCompareLive">Version A waiting for sampling</output></header><section id="workflowCore" class="workflow-core compare-core" data-compare-channel="A" style="--compare-split:50%"><!-- 11DZ_CORE_START:creative-effects-kaleidoscope --><div class="kaleidoscope-lab"><canvas id="kaleidoscopeCanvas" width="720" height="720" tabindex="0" aria-label="Interactive Kaleidoscope of the Aurora Field; move the pointer or use the left and right arrow keys to rotate the pattern" aria-describedby="kaleidoscopeHelp">Your browser does not support Canvas.</canvas><aside class="kaleidoscope-controls panel"><span class="eyebrow">KALEIDOSCOPE</span><h2>Kaleidoscope Pattern</h2><p id="kaleidoscopeHelp" class="muted">Multiple mirrored sectors share the same set of shapes, forming strict symmetry. Move the pointer to change the rotation angle.</p><label>Mirror sector <input id="kaleidoscopeSegments" type="range" min="4" max="16" step="2" value="10" data-core-bridge="creative-effects-kaleidoscope"><output id="kaleidoscopeSegmentsValue">10</output></label><label>Graphic Density <input id="kaleidoscopeDensity" type="range" min="3" max="12" value="7"><output id="kaleidoscopeDensityValue">7</output></label><button id="kaleidoscopeSpin" class="action" type="button" aria-pressed="false">Auto rotate</button></aside></div><!-- 11DZ_CORE_END --></section></section></div><p id="status" class="status" role="status" aria-live="polite"></p></section><figcaption class="gallery-caption"><strong>Aurora Field / GALLERY 03</strong></figcaption></figure>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:creative-effects-kaleidoscope */
const kaleidoscopeCanvas=document.querySelector('#kaleidoscopeCanvas');const kaleidoscopeContext=kaleidoscopeCanvas.getContext('2d');const kaleidoscopeSegments=document.querySelector('#kaleidoscopeSegments');const kaleidoscopeDensity=document.querySelector('#kaleidoscopeDensity');const kaleidoscopeReduced=matchMedia('(prefers-reduced-motion: reduce)').matches;let kaleidoscopeAngle=0;let kaleidoscopeSpinning=false;let kaleidoscopeFrame=0;function sizeKaleidoscope(){const rect=kaleidoscopeCanvas.getBoundingClientRect();const side=Math.max(300,Math.min(rect.width,rect.height||rect.width));const ratio=Math.min(2,devicePixelRatio||1);kaleidoscopeCanvas.width=Math.round(side*ratio);kaleidoscopeCanvas.height=Math.round(side*ratio);kaleidoscopeContext.setTransform(ratio,0,0,ratio,0,0);drawKaleidoscope();}function drawKaleidoscope(){const side=kaleidoscopeCanvas.width/Math.min(2,devicePixelRatio||1);const center=side/2;const segments=Number(kaleidoscopeSegments.value);const density=Number(kaleidoscopeDensity.value);kaleidoscopeContext.fillStyle='#100b24';kaleidoscopeContext.fillRect(0,0,side,side);for(let segment=0;segment<segments;segment+=1){for(let mirror=0;mirror<2;mirror+=1){kaleidoscopeContext.save();kaleidoscopeContext.translate(center,center);kaleidoscopeContext.rotate(kaleidoscopeAngle+segment*Math.PI*2/segments);kaleidoscopeContext.scale(1,mirror?-1:1);for(let index=0;index<density;index+=1){const radius=36+index*(center-54)/density;const size=8+(index*7)%24;kaleidoscopeContext.beginPath();kaleidoscopeContext.fillStyle=['#22d3ee','#f472b6','#fde047','#a78bfa'][index%4]+'bb';kaleidoscopeContext.arc(radius,Math.sin(index*1.7)*radius*.18,size,0,Math.PI*2);kaleidoscopeContext.fill();kaleidoscopeContext.rotate(.045);}kaleidoscopeContext.restore();}}if(kaleidoscopeSpinning&&!kaleidoscopeReduced){kaleidoscopeAngle+=.004;cancelAnimationFrame(kaleidoscopeFrame);kaleidoscopeFrame=requestAnimationFrame(drawKaleidoscope);}}kaleidoscopeCanvas.addEventListener('pointermove',event=>{const rect=kaleidoscopeCanvas.getBoundingClientRect();kaleidoscopeAngle=(event.clientX-rect.left)/rect.width*Math.PI*2;drawKaleidoscope();});kaleidoscopeCanvas.addEventListener('keydown',event=>{if(!['ArrowLeft','ArrowRight'].includes(event.key))return;event.preventDefault();kaleidoscopeAngle+=event.key==='ArrowRight'?.12:-.12;drawKaleidoscope();announce('The kaleidoscope rotation angle has been adjusted');});[kaleidoscopeSegments,kaleidoscopeDensity].forEach(input=>input.addEventListener('input',()=>{document.querySelector('#kaleidoscopeSegmentsValue').textContent=kaleidoscopeSegments.value;document.querySelector('#kaleidoscopeDensityValue').textContent=kaleidoscopeDensity.value;drawKaleidoscope();announce('Kaleidoscope '+kaleidoscopeSegments.value+' sector, density '+kaleidoscopeDensity.value);}));document.querySelector('#kaleidoscopeSpin').addEventListener('click',event=>{kaleidoscopeSpinning=!kaleidoscopeSpinning;event.currentTarget.textContent=kaleidoscopeSpinning?'Stop rotating':'Auto rotate';event.currentTarget.setAttribute('aria-pressed',String(kaleidoscopeSpinning));cancelAnimationFrame(kaleidoscopeFrame);drawKaleidoscope();announce(kaleidoscopeSpinning?'The kaleidoscope starts rotating automatically':'The kaleidoscope has stopped rotating');});addEventListener('resize',sizeKaleidoscope,{passive:true});sizeKaleidoscope();
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"creative-effects-kaleidoscope","selector":"[data-core-bridge=\"creative-effects-kaleidoscope\"]","mode":"range","key":"ArrowRight"};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Core Version '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.addEventListener("input",workflowBridgeScheduleCommit);workflowBridgeControl.addEventListener('change',workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();const step=Number(workflowBridgeControl.step)||1;const min=workflowBridgeControl.min===''?-Infinity:Number(workflowBridgeControl.min);const max=workflowBridgeControl.max===''?Infinity:Number(workflowBridgeControl.max);let next=Math.min(max,Math.max(min,(Number(workflowBridgeControl.value)||0)+step));if(next===Number(workflowBridgeControl.value))next=Math.max(min,Number(workflowBridgeControl.value)-step);workflowBridgeControl.value=String(next);workflowBridgeControl.dispatchEvent(new Event('input',{bubbles:true}));workflowBridgeControl.dispatchEvent(new Event('change',{bubbles:true}));const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowCompareCore=document.querySelector('#workflowCore');const workflowCompareWeight=document.querySelector('#workflowCompareWeight');const workflowCompareState={channel:'A',weight:50,frozen:false,snapshots:[]};function workflowCompareFingerprint(){const controls=[...workflowCompareCore.querySelectorAll('input,select,textarea')];const outputs=[...workflowCompareCore.querySelectorAll('output,[role="status"],strong')].map(node=>node.textContent.trim()).filter(Boolean);return {controlValues:controls.map(control=>control.type==='checkbox'||control.type==='radio'?control.checked:control.value),summary:outputs.slice(0,4).join(' / '),nodes:workflowCompareCore.querySelectorAll('*').length};}function workflowCompareDrive(){workflowCompareCore.dataset.compareChannel=workflowCompareState.channel;workflowCompareCore.style.setProperty('--compare-split',workflowCompareState.weight+'%');document.querySelector('#workflowCompareWeightValue').textContent=workflowCompareState.weight+' sec';document.querySelector('#workflowCompareLive').textContent=workflowCompareState.channel+' Version · '+workflowCompareState.weight+' sec'+(workflowCompareState.frozen?' · Frozen':'');announce('Aurora comparison in progress '+workflowCompareState.channel+' Version');}function workflowCompareCapture(source){const bridge=workflowBridgeActivate();const snapshot={...workflowCompareFingerprint(),channel:workflowCompareState.channel,weight:workflowCompareState.weight,source,bridge:bridge.summary};workflowCompareState.snapshots.push(snapshot);const item=document.createElement('li');item.innerHTML='<b>'+snapshot.channel+'</b><span>'+(snapshot.summary||snapshot.bridge)+'</span><small>'+snapshot.weight+' seconds · '+snapshot.bridge+'</small>';document.querySelector('#workflowCompareShelf').prepend(item);announce('sampled '+snapshot.channel+' Save exposure version · '+bridge.summary);}document.querySelectorAll('[name="workflowChannel"]').forEach(input=>input.addEventListener('change',()=>{workflowCompareState.channel=input.value;workflowCompareDrive();}));workflowCompareWeight.addEventListener('input',()=>{workflowCompareState.weight=Number(workflowCompareWeight.value);workflowCompareDrive();});document.querySelector('#workflowCompareFreeze').addEventListener('change',event=>{workflowCompareState.frozen=event.currentTarget.checked;workflowCompareDrive();});document.querySelector('#workflowCompareCapture').addEventListener('click',()=>workflowCompareCapture('Button Sampling'));workflowCompareCore.addEventListener('dblclick',()=>workflowCompareCapture('Main view double-click'));workflowCompareDrive();
workflowBridgeReset();
  </script>
</body>
</html>
Page feedbackFound an issue or have suggestions for improvement?
Feedback features need to be used in the online version

Please enable JavaScript in the online version before submitting; local features of the current tool or example are not affected.

Go to the online version for feedback