{"id":1346,"date":"2026-08-22T04:26:16","date_gmt":"2026-08-22T04:26:16","guid":{"rendered":"https:\/\/burstingrainbow.com\/index.php\/experiment\/orbit-choir\/"},"modified":"2026-08-22T04:26:16","modified_gmt":"2026-08-22T04:26:16","slug":"orbit-choir","status":"publish","type":"experiment","link":"https:\/\/burstingrainbow.com\/index.php\/experiment\/orbit-choir\/","title":{"rendered":"Orbit Choir"},"content":{"rendered":"<p>This is a small motion experiment for the Motion shelf.<\/p>\n<p>The piece is a browser-made orbit loop: little color cards circle a warm paper stage, drift out of time, then find the center again. Use the controls to shuffle the path, change the speed, thicken the crowd, or pause the whole thing mid-spin.<\/p>\n    <div id=\"broc-8e769bef-d319-412b-bba8-006d21e871a4\" class=\"broc\" data-broc>\n      <div class=\"broc__stage-wrap\">\n        <canvas class=\"broc__canvas\" width=\"1200\" height=\"720\" aria-label=\"Animated orbiting rainbow cards\"><\/canvas>\n        <div class=\"broc__hud\">\n          <span>orbit choir<\/span>\n          <b data-state>listening<\/b>\n        <\/div>\n      <\/div>\n      <div class=\"broc__controls\">\n        <button type=\"button\" data-action=\"shuffle\">Shuffle path<\/button>\n        <button type=\"button\" data-action=\"pause\">Pause<\/button>\n        <label>Speed <input type=\"range\" min=\"20\" max=\"180\" value=\"74\" data-speed><\/label>\n        <label>Density <input type=\"range\" min=\"5\" max=\"16\" value=\"10\" data-density><\/label>\n      <\/div>\n    <\/div>\n    <style>\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4{--bg:#f2efe8;--paper:#faf7f0;--ink:#0d0d0d;--body:#2a2925;--muted:#5a5751;--hair:#dcd7ca;--accent:#ff5a1f;--violet:#3a2a95;margin:28px 0 10px;font-family:Inter,system-ui,sans-serif;color:var(--ink)}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__stage-wrap{position:relative;overflow:hidden;border:1px solid var(--hair);border-radius:14px;background:var(--paper);box-shadow:0 22px 54px -34px rgba(0,0,0,.36)}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__canvas{display:block;width:100%;height:auto;aspect-ratio:5\/3;background:#f2efe8}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__hud{position:absolute;left:18px;right:18px;top:16px;display:flex;justify-content:space-between;gap:12px;align-items:center;pointer-events:none;font:700 11px\/1 JetBrains Mono,ui-monospace,monospace;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__hud b{color:var(--accent);font-weight:700}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__controls{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:14px}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 button{border:1px solid var(--ink);background:var(--ink);color:#fff;border-radius:999px;padding:12px 16px;font:700 12px\/1 Inter,system-ui,sans-serif;letter-spacing:.13em;text-transform:uppercase;cursor:pointer;transition:transform .2s ease,background .2s ease,color .2s ease}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 button:hover{transform:translateY(-1px)}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 label{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--hair);border-radius:999px;background:#fff;padding:9px 12px;color:var(--muted);font:700 11px\/1 Inter,system-ui,sans-serif;letter-spacing:.12em;text-transform:uppercase}\n      #broc-8e769bef-d319-412b-bba8-006d21e871a4 input[type=range]{accent-color:var(--accent);width:116px}\n      @media(max-width:680px){#broc-8e769bef-d319-412b-bba8-006d21e871a4 .broc__controls{align-items:stretch}#broc-8e769bef-d319-412b-bba8-006d21e871a4 button,#broc-8e769bef-d319-412b-bba8-006d21e871a4 label{width:100%;justify-content:center}#broc-8e769bef-d319-412b-bba8-006d21e871a4 input[type=range]{width:100%}}\n    <\/style>\n    <script>\n      (function(){\n        const root = document.getElementById(\"broc-8e769bef-d319-412b-bba8-006d21e871a4\");\n        if (!root) return;\n        const canvas = root.querySelector('canvas');\n        const ctx = canvas.getContext('2d');\n        const stateEl = root.querySelector('[data-state]');\n        const speed = root.querySelector('[data-speed]');\n        const density = root.querySelector('[data-density]');\n        const colors = ['#ff5a1f','#ffcf3a','#2fb3a4','#4a7dff','#5a3aa8','#ff6aa8','#ffb42a'];\n        let paused = false;\n        let seed = 11;\n        let items = [];\n        let last = performance.now();\n        let t = 0;\n        function rand(){seed=(seed*1664525+1013904223)>>>0; return seed\/4294967296;}\n        function rebuild(){\n          items = [];\n          const n = parseInt(density.value,10);\n          for(let i=0;i<n;i++){\n            items.push({\n              r: 74 + rand()*242,\n              phase: rand()*Math.PI*2,\n              drift: .52 + rand()*1.8,\n              size: 34 + rand()*68,\n              color: colors[i % colors.length],\n              wobble: rand()*Math.PI*2,\n              square: rand() > .38\n            });\n          }\n        }\n        function paper(){\n          ctx.fillStyle = '#f2efe8'; ctx.fillRect(0,0,canvas.width,canvas.height);\n          ctx.globalAlpha = .26; ctx.fillStyle = '#0d0d0d';\n          for(let x=22;x<canvas.width;x+=28){for(let y=20;y<canvas.height;y+=28){ctx.fillRect(x,y,1,1);}}\n          ctx.globalAlpha = 1;\n        }\n        function roundedRect(x,y,w,h,r){\n          ctx.beginPath(); ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r); ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath();\n        }\n        function draw(now){\n          const dt = Math.min(40, now-last); last = now;\n          if(!paused) t += dt * (parseInt(speed.value,10)\/74000);\n          paper();\n          const cx = canvas.width*.5, cy = canvas.height*.54;\n          ctx.save();\n          ctx.translate(cx, cy);\n          ctx.strokeStyle = 'rgba(90,87,81,.22)'; ctx.lineWidth = 1;\n          [90,170,250,330].forEach(r=>{ctx.beginPath();ctx.ellipse(0,0,r,r*.58,Math.sin(t*.4)*.08,0,Math.PI*2);ctx.stroke();});\n          items.forEach((it,i)=>{\n            const a = t*it.drift + it.phase;\n            const x = Math.cos(a)*it.r + Math.sin(a*2+it.wobble)*28;\n            const y = Math.sin(a)*it.r*.58 + Math.cos(a*1.7)*18;\n            const pulse = 1 + Math.sin(a*3)*.08;\n            ctx.save(); ctx.translate(x,y); ctx.rotate(a*.7);\n            ctx.globalAlpha = .2; ctx.fillStyle = '#0d0d0d'; roundedRect(-it.size*.47+8,-it.size*.34+10,it.size,it.size*.72,12); ctx.fill();\n            ctx.globalAlpha = .94; ctx.fillStyle = it.color;\n            if(it.square){roundedRect(-it.size*.47,-it.size*.34,it.size*pulse,it.size*.72*pulse,12); ctx.fill();}\n            else{ctx.beginPath();ctx.arc(0,0,it.size*.42*pulse,0,Math.PI*2);ctx.fill();}\n            ctx.globalAlpha = .36; ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(-it.size*.28,0); ctx.lineTo(it.size*.28,0); ctx.stroke();\n            ctx.restore();\n          });\n          ctx.globalAlpha = .92;\n          ctx.fillStyle = '#0d0d0d'; ctx.beginPath(); ctx.arc(0,0,46,0,Math.PI*2); ctx.fill();\n          ctx.fillStyle = '#f2efe8'; ctx.beginPath(); ctx.arc(0,0,28,0,Math.PI*2); ctx.fill();\n          ctx.fillStyle = '#ff5a1f'; ctx.beginPath(); ctx.arc(0,0,11,0,Math.PI*2); ctx.fill();\n          ctx.restore();\n          requestAnimationFrame(draw);\n        }\n        function shuffle(){seed = Math.floor(Math.random()*999999)+1; rebuild(); stateEl.textContent = 'new path'; setTimeout(()=>{stateEl.textContent = paused ? 'paused' : 'listening';}, 900);}\n        root.addEventListener('click', e=>{\n          const action = e.target && e.target.dataset ? e.target.dataset.action : '';\n          if(action === 'shuffle') shuffle();\n          if(action === 'pause'){paused = !paused; e.target.textContent = paused ? 'Resume' : 'Pause'; stateEl.textContent = paused ? 'paused' : 'listening';}\n        });\n        density.addEventListener('input', rebuild);\n        rebuild(); requestAnimationFrame(draw);\n      })();\n    <\/script>\n    \n<p>It is not a video file. It is a live motion system, which feels right for the Wall: a thing that keeps happening while you look at it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A browser-made motion loop where little rainbow cards orbit, stutter, pause and find a rhythm again.<\/p>\n","protected":false},"featured_media":1345,"template":"","experiment_tool":[31,32,33],"experiment_type":[26,27,29,22],"class_list":["post-1346","experiment","type-experiment","status-publish","has-post-thumbnail","hentry","experiment_tool-codex","experiment_tool-novamira","experiment_tool-wordpress","experiment_type-code","experiment_type-design","experiment_type-oddity","experiment_type-video"],"acpt":{"meta":[{"meta_box":"details","meta_fields":[{"name":"short_description","type":"Text","options":[],"value":"A browser-made motion loop where little rainbow cards orbit, stutter, pause and find a rhythm again.","default":"","required":false,"showInAdmin":false,"advancedOptions":[]},{"name":"external_url","type":"Url","options":[],"value":null,"default":"","required":false,"showInAdmin":false,"advancedOptions":[]},{"name":"featured_experiment","type":"Toggle","options":[],"value":"1","default":"","required":false,"showInAdmin":false,"advancedOptions":[]},{"name":"display_style","type":"Select","options":[{"label":"Standard","value":"standard"},{"label":"Wide","value":"wide"},{"label":"Tall","value":"tall"},{"label":"Featured","value":"featured"}],"value":"wide","default":"standard","required":false,"showInAdmin":false,"advancedOptions":[]}]}]},"_links":{"self":[{"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/experiment\/1346","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/experiment"}],"about":[{"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/types\/experiment"}],"version-history":[{"count":0,"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/experiment\/1346\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/media\/1345"}],"wp:attachment":[{"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/media?parent=1346"}],"wp:term":[{"taxonomy":"experiment_tool","embeddable":true,"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/experiment_tool?post=1346"},{"taxonomy":"experiment_type","embeddable":true,"href":"https:\/\/burstingrainbow.com\/index.php\/wp-json\/wp\/v2\/experiment_type?post=1346"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}