{"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-83c8edbf-f6de-42d2-83ca-d73a41e505f9\" 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-83c8edbf-f6de-42d2-83ca-d73a41e505f9{--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-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .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-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .broc__canvas{display:block;width:100%;height:auto;aspect-ratio:5\/3;background:#f2efe8}\n      #broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .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-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .broc__hud b{color:var(--accent);font-weight:700}\n      #broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .broc__controls{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:14px}\n      #broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 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-83c8edbf-f6de-42d2-83ca-d73a41e505f9 button:hover{transform:translateY(-1px)}\n      #broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 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-83c8edbf-f6de-42d2-83ca-d73a41e505f9 input[type=range]{accent-color:var(--accent);width:116px}\n      @media(max-width:680px){#broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 .broc__controls{align-items:stretch}#broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 button,#broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 label{width:100%;justify-content:center}#broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9 input[type=range]{width:100%}}\n    <\/style>\n    <script>\n      (function(){\n        const root = document.getElementById(\"broc-83c8edbf-f6de-42d2-83ca-d73a41e505f9\");\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}]}}