react-holographic-cube 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,6 @@
3
3
  A high-performance, cyberpunk-styled 3D spinning cube for React. Features physics-based friction, holographic visuals, and a floating drift animation when idle.
4
4
 
5
5
  ![Holographic Cube Preview](https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExZTVyamF6bjlsYjB5ZmdmbnlrY2RpNGtsYm9oZW0zNGN4eDZ1YmZmNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/IWt8NLETm6OLAnHE8C/giphy.gif)
6
- _(Note: You can replace this link with a screenshot of your actual cube later)_
7
6
 
8
7
  ## Features
9
8
 
@@ -16,6 +15,7 @@ _(Note: You can replace this link with a screenshot of your actual cube later)_
16
15
  ## Installation
17
16
 
18
17
  ```bash
18
+ npm create vite@latest . -- --template react
19
19
  npm install react-holographic-cube
20
20
  ```
21
21
 
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=require("react"),t=["1","2","3","4","5","6"];module.exports=function(r){var n=r.items,a=void 0===n?t:n,c=r.onWinner,i=r.perspective,u=void 0===i?"1000px":i,s=e.useState("idle"),o=s[0],l=s[1],f=e.useState(null)[1],d=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),m=d[0],p=d[1],v=e.useRef(null),g=e.useRef([]),N=e.useRef(null),b=e.useRef(0),y=e.useRef(0),x=e.useRef(0),R=e.useRef("idle");e.useEffect(function(){return function(){return cancelAnimationFrame(N.current)}},[]),e.useEffect(function(){S(0)},[a]),e.useEffect(function(){var e,t=function(){if("idle"===R.current){var r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;p({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+r+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var i=4e3+1e3*Math.random();e=setTimeout(t,i)}};return"idle"===o?t():(clearTimeout(e),p({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[o]);var M=function(){b.current+=y.current,b.current>=90&&(b.current%=90,x.current=(x.current+1)%a.length,S(x.current)),v.current&&(v.current.style.transform="rotateX("+b.current+"deg)"),"stopping"===R.current&&(y.current*=.98,y.current<.5&&(y.current=.5),y.current<=.5&&b.current<1)?T():N.current=requestAnimationFrame(M)},S=function(e){for(var t=0;t<4;t++){var r=g.current[t];r&&(r.innerText=a[(e+t)%a.length])}},T=function(){v.current&&(v.current.style.transform="rotateX(0deg)");var e=a[x.current%a.length];l("idle"),R.current="idle",f(e),c&&c(e)};return h("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},h("div",{className:"scene",style:{perspective:u}},h("div",{className:"light-pillar"}),h("div",{className:"cube-wrapper "+("idle"!==o?"locked":""),style:"idle"===o?m:{}},h("div",{ref:v,className:"cube "+("idle"!==o?"is-spinning":""),style:{transition:"none"}},h("div",{className:"face front",ref:function(e){return g.current[0]=e}}),h("div",{className:"face bottom",ref:function(e){return g.current[1]=e}}),h("div",{className:"face back",ref:function(e){return g.current[2]=e}}),h("div",{className:"face top",ref:function(e){return g.current[3]=e}}),h("div",{className:"face left"}),h("div",{className:"face right"}))),h("div",{className:"cube-shadow"}),h("div",{className:"hi-tech-floor"})),h("div",{className:"controls",style:{marginTop:40}},h("button",{className:"cyber-button",onClick:function(){"idle"===R.current&&(f(null),l("spinning"),R.current="spinning",y.current=30,x.current=0,b.current=0,S(0),M())},disabled:"idle"!==o},"Spin"),h("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===R.current&&(l("stopping"),R.current="stopping")},disabled:"spinning"!==o},"Stop")))};
1
+ var e=require("react");function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/t(e),n=["1","2","3","4","5","6"];module.exports=function(t){var a=t.items,c=void 0===a?n:a,u=t.onWinner,l=t.perspective,i=void 0===l?"1000px":l,s=e.useState("idle"),o=s[0],f=s[1],d=e.useState(null)[1],m=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),p=m[0],v=m[1],g=e.useRef(null),E=e.useRef([]),b=e.useRef(null),N=e.useRef(0),h=e.useRef(0),y=e.useRef(0),x=e.useRef("idle");e.useEffect(function(){return function(){return cancelAnimationFrame(b.current)}},[]),e.useEffect(function(){M(0)},[c]),e.useEffect(function(){var e,t=function(){if("idle"===x.current){var r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;v({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+r+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var u=4e3+1e3*Math.random();e=setTimeout(t,u)}};return"idle"===o?t():(clearTimeout(e),v({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[o]);var R=function(){N.current+=h.current,N.current>=90&&(N.current%=90,y.current=(y.current+1)%c.length,M(y.current)),g.current&&(g.current.style.transform="rotateX("+N.current+"deg)"),"stopping"===x.current&&(h.current*=.98,h.current<.5&&(h.current=.5),h.current<=.5&&N.current<1)?S():b.current=requestAnimationFrame(R)},M=function(e){for(var t=0;t<4;t++){var r=E.current[t];r&&(r.innerText=c[(e+t)%c.length])}},S=function(){g.current&&(g.current.style.transform="rotateX(0deg)");var e=c[y.current%c.length];f("idle"),x.current="idle",d(e),u&&u(e)};/*#__PURE__*/return r.default.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/r.default.createElement("div",{className:"scene",style:{perspective:i}},/*#__PURE__*/r.default.createElement("div",{className:"light-pillar"}),/*#__PURE__*/r.default.createElement("div",{className:"cube-wrapper "+("idle"!==o?"locked":""),style:"idle"===o?p:{}},/*#__PURE__*/r.default.createElement("div",{ref:g,className:"cube "+("idle"!==o?"is-spinning":""),style:{transition:"none"}},/*#__PURE__*/r.default.createElement("div",{className:"face front",ref:function(e){return E.current[0]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face bottom",ref:function(e){return E.current[1]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face back",ref:function(e){return E.current[2]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face top",ref:function(e){return E.current[3]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face left"}),/*#__PURE__*/r.default.createElement("div",{className:"face right"}))),/*#__PURE__*/r.default.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/r.default.createElement("div",{className:"hi-tech-floor"})),/*#__PURE__*/r.default.createElement("div",{className:"controls",style:{marginTop:40}},/*#__PURE__*/r.default.createElement("button",{className:"cyber-button",onClick:function(){"idle"===x.current&&(d(null),f("spinning"),x.current="spinning",h.current=30,y.current=0,N.current=0,M(0),R())},disabled:"idle"!==o},"Spin"),/*#__PURE__*/r.default.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===x.current&&(f("stopping"),x.current="stopping")},disabled:"spinning"!==o},"Stop")))};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","h","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"uBAIMA,EAAa,CAAC,IAAK,IAAK,IAAK,IAAK,IAAK,oBAExB,SAAHC,GAIZ,IAAAC,EAAAD,EAHJE,MAAAA,OAAQH,IAAHE,EAAGF,EAAUE,EAClBE,EAAQH,EAARG,SAAQC,EAAAJ,EACRK,YAAAA,OAAW,IAAAD,EAAG,SAAQA,EAEtBE,EAA4BC,EAAAA,SAAS,QAA9BC,EAAMF,EAAA,GAAEG,EAASH,EAAA,GACTI,EAAaH,EAAQA,SAAC,MAGrC,GAIAI,EAAoCJ,EAAAA,SAAS,CAC3CK,UAAW,wDADNC,EAAUF,EAAEG,GAAAA,EAAaH,EAIhC,GAAMI,EAAUC,EAAMA,OAAC,MACjBC,EAAWD,EAAAA,OAAO,IAClBE,EAAeF,EAAAA,OAAO,MAEtBG,EAAcH,EAAMA,OAAC,GACrBI,EAAWJ,EAAMA,OAAC,GAClBK,EAAiBL,EAAAA,OAAO,GACxBM,EAAYN,EAAAA,OAAO,QAEzBO,YAAU,WACR,OAAa,WAAA,OAAAC,qBAAqBN,EAAaO,QAAQ,CACzD,EAAG,IAEHF,EAASA,UAAC,WACRG,EAAkB,EACpB,EAAG,CAACxB,IAGJqB,EAASA,UAAC,WACR,IAAII,EACEC,EAAgB,WACpB,GAA0B,SAAtBN,EAAUG,QAAd,CAEA,IAAMI,EAA6B,IAAvBC,KAAKC,SAAW,IACtBC,EAA6B,IAAvBF,KAAKC,SAAW,IACtBE,EAA6B,IAAvBH,KAAKC,SAAW,IACtBG,EAA6B,IAAvBJ,KAAKC,SAAW,IAAY,EAExCjB,EAAc,CACZF,UAAS,oBAAsBsB,EAAE,oBAAoBL,EAAE,gBAAgBG,EAAE,gBAAgBC,EAAE,SAG7F,IAAME,EAAe,IAAuB,IAAhBL,KAAKC,SACjCJ,EAAYS,WAAWR,EAAeO,EAVtC,CAWF,EAUA,MARe,SAAX3B,EACFoB,KAEAS,aAAaV,GACbb,EAAc,CACZF,UAAW,yDAGR,WAAA,OAAMyB,aAAaV,EAAU,CACtC,EAAG,CAACnB,IAEJ,IAmBM8B,EAAO,WACXnB,EAAYM,SAAWL,EAASK,QAG5BN,EAAYM,SAAW,KACzBN,EAAYM,SAAW,GACvBJ,EAAeI,SAAWJ,EAAeI,QAAU,GAAKvB,EAAMqC,OAC9Db,EAAkBL,EAAeI,UAG/BV,EAAQU,UACVV,EAAQU,QAAQe,MAAM5B,UAAuBO,WAAAA,EAAYM,QAC3D,QAG0B,aAAtBH,EAAUG,UACZL,EAASK,SAzFI,IA0FTL,EAASK,QAzFO,KA0FlBL,EAASK,QA1FS,IA4FhBL,EAASK,SA5FO,IA4FuBN,EAAYM,QAAU,GAC/DgB,IAIJvB,EAAaO,QAAUiB,sBAAsBJ,EAC/C,EAEMZ,EAAoB,SAACiB,GACzB,IAAK,IAAIC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IACMC,EAAK5B,EAASQ,QAAQmB,GACxBC,IAAIA,EAAGC,UAAY5C,GAFJyC,EAAaC,GAAK1C,EAAMqC,QAG7C,CACF,EAEME,EAAa,WACb1B,EAAQU,UAASV,EAAQU,QAAQe,MAAM5B,UAAS,iBAEpD,IAAMmC,EAAc7C,EAAMmB,EAAeI,QAAUvB,EAAMqC,QAEzD9B,EAAU,QACVa,EAAUG,QAAU,OACpBf,EAAUqC,GAGN5C,GAAUA,EAAS4C,EACzB,EAEA,OACEC,EACER,MAAAA,CAAAA,MAAO,CACLS,SAAU,WACVC,OAAQ,GACRC,MAAO,OACPC,QAAS,OACTC,cAAe,SACfC,WAAY,WAGdN,EAAA,MAAA,CAAKO,UAAU,QAAQf,MAAO,CAAEnC,YAAAA,IAC9B2C,EAAKO,MAAAA,CAAAA,UAAU,iBAEfP,EACEO,MAAAA,CAAAA,UAA2B/C,iBAAW,SAAXA,EAAoB,SAAW,IAC1DgC,MAAkB,SAAXhC,EAAoBK,EAAa,CAAA,GAExCmC,EAAA,MAAA,CACEQ,IAAKzC,EACLwC,UAAmB/C,SAAW,SAAXA,EAAoB,cAAgB,IACvDgC,MAAO,CAAEiB,WAAY,SAErBT,EACEO,MAAAA,CAAAA,UAAU,aACVC,IAAK,SAACX,GAAQ,OAAA5B,EAASQ,QAAQ,GAAKoB,CAAE,IAExCG,EAAA,MAAA,CACEO,UAAU,cACVC,IAAK,SAACX,GAAQ,OAAA5B,EAASQ,QAAQ,GAAKoB,CAAE,IAExCG,EACEO,MAAAA,CAAAA,UAAU,YACVC,IAAK,SAACX,GAAE,OAAM5B,EAASQ,QAAQ,GAAKoB,CAAE,IAExCG,EACEO,MAAAA,CAAAA,UAAU,WACVC,IAAK,SAACX,GAAQ,OAAA5B,EAASQ,QAAQ,GAAKoB,CAAE,IAExCG,EAAKO,MAAAA,CAAAA,UAAU,cACfP,EAAA,MAAA,CAAKO,UAAU,iBAInBP,EAAA,MAAA,CAAKO,UAAU,gBACfP,EAAKO,MAAAA,CAAAA,UAAU,mBAIjBP,EAAA,MAAA,CAAKO,UAAU,WAAWf,MAAO,CAAEkB,UAAW,KAC5CV,EAAA,SAAA,CACEO,UAAU,eACVI,QAxHY,WACQ,SAAtBrC,EAAUG,UACdf,EAAU,MACVD,EAAU,YACVa,EAAUG,QAAU,WACpBL,EAASK,QA5DS,GA6DlBJ,EAAeI,QAAU,EACzBN,EAAYM,QAAU,EACtBC,EAAkB,GAClBY,IACF,EA+GQsB,SAAqB,SAAXpD,GACX,QAGDwC,EAAA,SAAA,CACEO,UAAU,wBACVI,QAnHW,WACS,aAAtBrC,EAAUG,UACZhB,EAAU,YACVa,EAAUG,QAAU,WAExB,EA+GQmC,SAAqB,aAAXpD,GACX,SAMT"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useState as e,useRef as t,useEffect as r}from"react";const n=["1","2","3","4","5","6"],a=({items:a=n,onWinner:c,perspective:s="1000px"})=>{const[i,l]=e("idle"),[o,u]=e(null),[d,m]=e({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),p=t(null),f=t([]),g=t(null),v=t(0),N=t(0),b=t(0),y=t("idle");r(()=>()=>cancelAnimationFrame(g.current),[]),r(()=>{M(0)},[a]),r(()=>{let e;const t=()=>{if("idle"!==y.current)return;const r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;m({transform:`translate3d(0px, ${c}px, 0px) rotateX(${r}deg) rotateY(${n}deg) rotateZ(${a}deg)`});const s=4e3+1e3*Math.random();e=setTimeout(t,s)};return"idle"===i?t():(clearTimeout(e),m({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),()=>clearTimeout(e)},[i]);const x=()=>{v.current+=N.current,v.current>=90&&(v.current%=90,b.current=(b.current+1)%a.length,M(b.current)),p.current&&(p.current.style.transform=`rotateX(${v.current}deg)`),"stopping"===y.current&&(N.current*=.98,N.current<.5&&(N.current=.5),N.current<=.5&&v.current<1)?T():g.current=requestAnimationFrame(x)},M=e=>{for(let t=0;t<4;t++){const r=f.current[t];r&&(r.innerText=a[(e+t)%a.length])}},T=()=>{p.current&&(p.current.style.transform="rotateX(0deg)");const e=a[b.current%a.length];l("idle"),y.current="idle",u(e),c&&c(e)};return h("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},h("div",{className:"scene",style:{perspective:s}},h("div",{className:"light-pillar"}),h("div",{className:"cube-wrapper "+("idle"!==i?"locked":""),style:"idle"===i?d:{}},h("div",{ref:p,className:"cube "+("idle"!==i?"is-spinning":""),style:{transition:"none"}},h("div",{className:"face front",ref:e=>f.current[0]=e}),h("div",{className:"face bottom",ref:e=>f.current[1]=e}),h("div",{className:"face back",ref:e=>f.current[2]=e}),h("div",{className:"face top",ref:e=>f.current[3]=e}),h("div",{className:"face left"}),h("div",{className:"face right"}))),h("div",{className:"cube-shadow"}),h("div",{className:"hi-tech-floor"})),h("div",{className:"controls",style:{marginTop:40}},h("button",{className:"cyber-button",onClick:()=>{"idle"===y.current&&(u(null),l("spinning"),y.current="spinning",N.current=30,b.current=0,v.current=0,M(0),x())},disabled:"idle"!==i},"Spin"),h("button",{className:"cyber-button stop-btn",onClick:()=>{"spinning"===y.current&&(l("stopping"),y.current="stopping")},disabled:"spinning"!==i},"Stop")))};export{a as default};
1
+ import e,{useState as t,useRef as r,useEffect as n}from"react";const a=["1","2","3","4","5","6"],c=({items:c=a,onWinner:l,perspective:s="1000px"})=>{const[i,o]=t("idle"),[m,u]=t(null),[d,p]=t({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),f=r(null),g=r([]),v=r(null),E=r(0),N=r(0),b=r(0),h=r("idle");n(()=>()=>cancelAnimationFrame(v.current),[]),n(()=>{x(0)},[c]),n(()=>{let e;const t=()=>{if("idle"!==h.current)return;const r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;p({transform:`translate3d(0px, ${c}px, 0px) rotateX(${r}deg) rotateY(${n}deg) rotateZ(${a}deg)`});const l=4e3+1e3*Math.random();e=setTimeout(t,l)};return"idle"===i?t():(clearTimeout(e),p({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),()=>clearTimeout(e)},[i]);const y=()=>{E.current+=N.current,E.current>=90&&(E.current%=90,b.current=(b.current+1)%c.length,x(b.current)),f.current&&(f.current.style.transform=`rotateX(${E.current}deg)`),"stopping"===h.current&&(N.current*=.98,N.current<.5&&(N.current=.5),N.current<=.5&&E.current<1)?M():v.current=requestAnimationFrame(y)},x=e=>{for(let t=0;t<4;t++){const r=g.current[t];r&&(r.innerText=c[(e+t)%c.length])}},M=()=>{f.current&&(f.current.style.transform="rotateX(0deg)");const e=c[b.current%c.length];o("idle"),h.current="idle",u(e),l&&l(e)};/*#__PURE__*/return e.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/e.createElement("div",{className:"scene",style:{perspective:s}},/*#__PURE__*/e.createElement("div",{className:"light-pillar"}),/*#__PURE__*/e.createElement("div",{className:"cube-wrapper "+("idle"!==i?"locked":""),style:"idle"===i?d:{}},/*#__PURE__*/e.createElement("div",{ref:f,className:"cube "+("idle"!==i?"is-spinning":""),style:{transition:"none"}},/*#__PURE__*/e.createElement("div",{className:"face front",ref:e=>g.current[0]=e}),/*#__PURE__*/e.createElement("div",{className:"face bottom",ref:e=>g.current[1]=e}),/*#__PURE__*/e.createElement("div",{className:"face back",ref:e=>g.current[2]=e}),/*#__PURE__*/e.createElement("div",{className:"face top",ref:e=>g.current[3]=e}),/*#__PURE__*/e.createElement("div",{className:"face left"}),/*#__PURE__*/e.createElement("div",{className:"face right"}))),/*#__PURE__*/e.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/e.createElement("div",{className:"hi-tech-floor"})),/*#__PURE__*/e.createElement("div",{className:"controls",style:{marginTop:40}},/*#__PURE__*/e.createElement("button",{className:"cyber-button",onClick:()=>{"idle"===h.current&&(u(null),o("spinning"),h.current="spinning",N.current=30,b.current=0,E.current=0,x(0),y())},disabled:"idle"!==i},"Spin"),/*#__PURE__*/e.createElement("button",{className:"cyber-button stop-btn",onClick:()=>{"spinning"===h.current&&(o("stopping"),h.current="stopping")},disabled:"spinning"!==i},"Stop")))};export{c as default};
2
2
  //# sourceMappingURL=index.modern.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.modern.mjs","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","InfiniteCube","items","onWinner","perspective","status","setStatus","useState","winner","setWinner","driftStyle","setDriftStyle","transform","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","h","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","handleStart","disabled","handleStop"],"mappings":"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"}
1
+ {"version":3,"file":"index.modern.mjs","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","InfiniteCube","items","onWinner","perspective","status","setStatus","useState","winner","setWinner","driftStyle","setDriftStyle","transform","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","handleStart","disabled","handleStop"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useState as e,useRef as r,useEffect as t}from"react";var n=["1","2","3","4","5","6"],a=function(a){var c=a.items,i=void 0===c?n:c,o=a.onWinner,u=a.perspective,s=void 0===u?"1000px":u,l=e("idle"),d=l[0],f=l[1],m=e(null)[1],p=e({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),v=p[0],g=p[1],N=r(null),b=r([]),y=r(null),x=r(0),M=r(0),T=r(0),X=r("idle");t(function(){return function(){return cancelAnimationFrame(y.current)}},[]),t(function(){w(0)},[i]),t(function(){var e,r=function(){if("idle"===X.current){var t=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;g({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+t+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var i=4e3+1e3*Math.random();e=setTimeout(r,i)}};return"idle"===d?r():(clearTimeout(e),g({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[d]);var k=function(){x.current+=M.current,x.current>=90&&(x.current%=90,T.current=(T.current+1)%i.length,w(T.current)),N.current&&(N.current.style.transform="rotateX("+x.current+"deg)"),"stopping"===X.current&&(M.current*=.98,M.current<.5&&(M.current=.5),M.current<=.5&&x.current<1)?Y():y.current=requestAnimationFrame(k)},w=function(e){for(var r=0;r<4;r++){var t=b.current[r];t&&(t.innerText=i[(e+r)%i.length])}},Y=function(){N.current&&(N.current.style.transform="rotateX(0deg)");var e=i[T.current%i.length];f("idle"),X.current="idle",m(e),o&&o(e)};return h("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},h("div",{className:"scene",style:{perspective:s}},h("div",{className:"light-pillar"}),h("div",{className:"cube-wrapper "+("idle"!==d?"locked":""),style:"idle"===d?v:{}},h("div",{ref:N,className:"cube "+("idle"!==d?"is-spinning":""),style:{transition:"none"}},h("div",{className:"face front",ref:function(e){return b.current[0]=e}}),h("div",{className:"face bottom",ref:function(e){return b.current[1]=e}}),h("div",{className:"face back",ref:function(e){return b.current[2]=e}}),h("div",{className:"face top",ref:function(e){return b.current[3]=e}}),h("div",{className:"face left"}),h("div",{className:"face right"}))),h("div",{className:"cube-shadow"}),h("div",{className:"hi-tech-floor"})),h("div",{className:"controls",style:{marginTop:40}},h("button",{className:"cyber-button",onClick:function(){"idle"===X.current&&(m(null),f("spinning"),X.current="spinning",M.current=30,T.current=0,x.current=0,w(0),k())},disabled:"idle"!==d},"Spin"),h("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===X.current&&(f("stopping"),X.current="stopping")},disabled:"spinning"!==d},"Stop")))};export{a as default};
1
+ import e,{useState as t,useRef as r,useEffect as n}from"react";var a=["1","2","3","4","5","6"],c=function(c){var i=c.items,l=void 0===i?a:i,o=c.onWinner,u=c.perspective,s=void 0===u?"1000px":u,m=t("idle"),d=m[0],f=m[1],p=t(null)[1],v=t({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),g=v[0],E=v[1],N=r(null),b=r([]),h=r(null),y=r(0),x=r(0),M=r(0),T=r("idle");n(function(){return function(){return cancelAnimationFrame(h.current)}},[]),n(function(){k(0)},[l]),n(function(){var e,t=function(){if("idle"===T.current){var r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;E({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+r+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var i=4e3+1e3*Math.random();e=setTimeout(t,i)}};return"idle"===d?t():(clearTimeout(e),E({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[d]);var X=function(){y.current+=x.current,y.current>=90&&(y.current%=90,M.current=(M.current+1)%l.length,k(M.current)),N.current&&(N.current.style.transform="rotateX("+y.current+"deg)"),"stopping"===T.current&&(x.current*=.98,x.current<.5&&(x.current=.5),x.current<=.5&&y.current<1)?w():h.current=requestAnimationFrame(X)},k=function(e){for(var t=0;t<4;t++){var r=b.current[t];r&&(r.innerText=l[(e+t)%l.length])}},w=function(){N.current&&(N.current.style.transform="rotateX(0deg)");var e=l[M.current%l.length];f("idle"),T.current="idle",p(e),o&&o(e)};/*#__PURE__*/return e.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/e.createElement("div",{className:"scene",style:{perspective:s}},/*#__PURE__*/e.createElement("div",{className:"light-pillar"}),/*#__PURE__*/e.createElement("div",{className:"cube-wrapper "+("idle"!==d?"locked":""),style:"idle"===d?g:{}},/*#__PURE__*/e.createElement("div",{ref:N,className:"cube "+("idle"!==d?"is-spinning":""),style:{transition:"none"}},/*#__PURE__*/e.createElement("div",{className:"face front",ref:function(e){return b.current[0]=e}}),/*#__PURE__*/e.createElement("div",{className:"face bottom",ref:function(e){return b.current[1]=e}}),/*#__PURE__*/e.createElement("div",{className:"face back",ref:function(e){return b.current[2]=e}}),/*#__PURE__*/e.createElement("div",{className:"face top",ref:function(e){return b.current[3]=e}}),/*#__PURE__*/e.createElement("div",{className:"face left"}),/*#__PURE__*/e.createElement("div",{className:"face right"}))),/*#__PURE__*/e.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/e.createElement("div",{className:"hi-tech-floor"})),/*#__PURE__*/e.createElement("div",{className:"controls",style:{marginTop:40}},/*#__PURE__*/e.createElement("button",{className:"cyber-button",onClick:function(){"idle"===T.current&&(p(null),f("spinning"),T.current="spinning",x.current=30,M.current=0,y.current=0,k(0),X())},disabled:"idle"!==d},"Spin"),/*#__PURE__*/e.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===T.current&&(f("stopping"),T.current="stopping")},disabled:"spinning"!==d},"Stop")))};export{c as default};
2
2
  //# sourceMappingURL=index.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.module.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","InfiniteCube","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","h","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
1
+ {"version":3,"file":"index.module.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","InfiniteCube","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):(e||self).reactHolographicCube=t(e.react)}(this,function(e){var t=["1","2","3","4","5","6"];return function(r){var n=r.items,a=void 0===n?t:n,c=r.onWinner,i=r.perspective,u=void 0===i?"1000px":i,o=e.useState("idle"),s=o[0],l=o[1],f=e.useState(null)[1],d=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),m=d[0],p=d[1],v=e.useRef(null),g=e.useRef([]),b=e.useRef(null),N=e.useRef(0),y=e.useRef(0),x=e.useRef(0),R=e.useRef("idle");e.useEffect(function(){return function(){return cancelAnimationFrame(b.current)}},[]),e.useEffect(function(){M(0)},[a]),e.useEffect(function(){var e,t=function(){if("idle"===R.current){var r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;p({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+r+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var i=4e3+1e3*Math.random();e=setTimeout(t,i)}};return"idle"===s?t():(clearTimeout(e),p({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[s]);var T=function(){N.current+=y.current,N.current>=90&&(N.current%=90,x.current=(x.current+1)%a.length,M(x.current)),v.current&&(v.current.style.transform="rotateX("+N.current+"deg)"),"stopping"===R.current&&(y.current*=.98,y.current<.5&&(y.current=.5),y.current<=.5&&N.current<1)?S():b.current=requestAnimationFrame(T)},M=function(e){for(var t=0;t<4;t++){var r=g.current[t];r&&(r.innerText=a[(e+t)%a.length])}},S=function(){v.current&&(v.current.style.transform="rotateX(0deg)");var e=a[x.current%a.length];l("idle"),R.current="idle",f(e),c&&c(e)};return h("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},h("div",{className:"scene",style:{perspective:u}},h("div",{className:"light-pillar"}),h("div",{className:"cube-wrapper "+("idle"!==s?"locked":""),style:"idle"===s?m:{}},h("div",{ref:v,className:"cube "+("idle"!==s?"is-spinning":""),style:{transition:"none"}},h("div",{className:"face front",ref:function(e){return g.current[0]=e}}),h("div",{className:"face bottom",ref:function(e){return g.current[1]=e}}),h("div",{className:"face back",ref:function(e){return g.current[2]=e}}),h("div",{className:"face top",ref:function(e){return g.current[3]=e}}),h("div",{className:"face left"}),h("div",{className:"face right"}))),h("div",{className:"cube-shadow"}),h("div",{className:"hi-tech-floor"})),h("div",{className:"controls",style:{marginTop:40}},h("button",{className:"cyber-button",onClick:function(){"idle"===R.current&&(f(null),l("spinning"),R.current="spinning",y.current=30,x.current=0,N.current=0,M(0),T())},disabled:"idle"!==s},"Spin"),h("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===R.current&&(l("stopping"),R.current="stopping")},disabled:"spinning"!==s},"Stop")))}});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):(e||self).reactHolographicCube=t(e.react)}(this,function(e){function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=/*#__PURE__*/t(e),n=["1","2","3","4","5","6"];return function(t){var a=t.items,c=void 0===a?n:a,u=t.onWinner,l=t.perspective,i=void 0===l?"1000px":l,o=e.useState("idle"),s=o[0],f=o[1],d=e.useState(null)[1],m=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),p=m[0],v=m[1],g=e.useRef(null),b=e.useRef([]),E=e.useRef(null),h=e.useRef(0),y=e.useRef(0),N=e.useRef(0),x=e.useRef("idle");e.useEffect(function(){return function(){return cancelAnimationFrame(E.current)}},[]),e.useEffect(function(){T(0)},[c]),e.useEffect(function(){var e,t=function(){if("idle"===x.current){var r=30*(Math.random()-.5),n=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;v({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+r+"deg) rotateY("+n+"deg) rotateZ("+a+"deg)"});var u=4e3+1e3*Math.random();e=setTimeout(t,u)}};return"idle"===s?t():(clearTimeout(e),v({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[s]);var R=function(){h.current+=y.current,h.current>=90&&(h.current%=90,N.current=(N.current+1)%c.length,T(N.current)),g.current&&(g.current.style.transform="rotateX("+h.current+"deg)"),"stopping"===x.current&&(y.current*=.98,y.current<.5&&(y.current=.5),y.current<=.5&&h.current<1)?M():E.current=requestAnimationFrame(R)},T=function(e){for(var t=0;t<4;t++){var r=b.current[t];r&&(r.innerText=c[(e+t)%c.length])}},M=function(){g.current&&(g.current.style.transform="rotateX(0deg)");var e=c[N.current%c.length];f("idle"),x.current="idle",d(e),u&&u(e)};/*#__PURE__*/return r.default.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/r.default.createElement("div",{className:"scene",style:{perspective:i}},/*#__PURE__*/r.default.createElement("div",{className:"light-pillar"}),/*#__PURE__*/r.default.createElement("div",{className:"cube-wrapper "+("idle"!==s?"locked":""),style:"idle"===s?p:{}},/*#__PURE__*/r.default.createElement("div",{ref:g,className:"cube "+("idle"!==s?"is-spinning":""),style:{transition:"none"}},/*#__PURE__*/r.default.createElement("div",{className:"face front",ref:function(e){return b.current[0]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face bottom",ref:function(e){return b.current[1]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face back",ref:function(e){return b.current[2]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face top",ref:function(e){return b.current[3]=e}}),/*#__PURE__*/r.default.createElement("div",{className:"face left"}),/*#__PURE__*/r.default.createElement("div",{className:"face right"}))),/*#__PURE__*/r.default.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/r.default.createElement("div",{className:"hi-tech-floor"})),/*#__PURE__*/r.default.createElement("div",{className:"controls",style:{marginTop:40}},/*#__PURE__*/r.default.createElement("button",{className:"cyber-button",onClick:function(){"idle"===x.current&&(d(null),f("spinning"),x.current="spinning",y.current=30,N.current=0,h.current=0,T(0),R())},disabled:"idle"!==s},"Spin"),/*#__PURE__*/r.default.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===x.current&&(f("stopping"),x.current="stopping")},disabled:"spinning"!==s},"Stop")))}});
2
2
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","h","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/index.js"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport \"./styles.css\";\n\n// Default items if user provides none\nconst DEMO_ITEMS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\n\n // Constants\n const START_SPEED = 30;\n const FRICTION = 0.98;\n const MIN_CRAWL_SPEED = 0.5;\n\n const [driftStyle, setDriftStyle] = useState({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n\n const cubeRef = useRef(null);\n const faceRefs = useRef([]);\n const animationRef = useRef(null);\n\n const rotationRef = useRef(0);\n const speedRef = useRef(0);\n const listPointerRef = useRef(0);\n const statusRef = useRef(\"idle\");\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]); // Re-run if items change\n\n // --- Random Float Logic ---\n useEffect(() => {\n let timeoutId;\n const floatRandomly = () => {\n if (statusRef.current !== \"idle\") return;\n\n const rX = (Math.random() - 0.5) * 30;\n const rY = (Math.random() - 0.5) * 30;\n const rZ = (Math.random() - 0.5) * 10;\n const tY = (Math.random() - 0.5) * 30 - 5;\n\n setDriftStyle({\n transform: `translate3d(0px, ${tY}px, 0px) rotateX(${rX}deg) rotateY(${rY}deg) rotateZ(${rZ}deg)`,\n });\n\n const nextMoveTime = 4000 + Math.random() * 1000;\n timeoutId = setTimeout(floatRandomly, nextMoveTime);\n };\n\n if (status === \"idle\") {\n floatRandomly();\n } else {\n clearTimeout(timeoutId);\n setDriftStyle({\n transform: \"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)\",\n });\n }\n return () => clearTimeout(timeoutId);\n }, [status]);\n\n const handleStart = () => {\n if (statusRef.current !== \"idle\") return;\n setWinner(null);\n setStatus(\"spinning\");\n statusRef.current = \"spinning\";\n speedRef.current = START_SPEED;\n listPointerRef.current = 0;\n rotationRef.current = 0;\n updateFaceContent(0);\n loop();\n };\n\n const handleStop = () => {\n if (statusRef.current === \"spinning\") {\n setStatus(\"stopping\");\n statusRef.current = \"stopping\";\n }\n };\n\n const loop = () => {\n rotationRef.current += speedRef.current;\n\n // Treadmill Logic\n if (rotationRef.current >= 90) {\n rotationRef.current %= 90;\n listPointerRef.current = (listPointerRef.current + 1) % items.length;\n updateFaceContent(listPointerRef.current);\n }\n\n if (cubeRef.current) {\n cubeRef.current.style.transform = `rotateX(${rotationRef.current}deg)`;\n }\n\n // Physics\n if (statusRef.current === \"stopping\") {\n speedRef.current *= FRICTION;\n if (speedRef.current < MIN_CRAWL_SPEED)\n speedRef.current = MIN_CRAWL_SPEED;\n\n if (speedRef.current <= MIN_CRAWL_SPEED && rotationRef.current < 1.0) {\n finishGame();\n return;\n }\n }\n animationRef.current = requestAnimationFrame(loop);\n };\n\n const updateFaceContent = (startIndex) => {\n for (let i = 0; i < 4; i++) {\n const itemIndex = (startIndex + i) % items.length;\n const el = faceRefs.current[i];\n if (el) el.innerText = items[itemIndex];\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningItem = items[listPointerRef.current % items.length];\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningItem);\n\n // Call the user's callback function\n if (onWinner) onWinner(winningItem);\n };\n\n return (\n <div\n style={{\n position: \"relative\",\n zIndex: 10,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n }}\n >\n <div className=\"scene\" style={{ perspective }}>\n <div className=\"light-pillar\"></div>\n\n <div\n className={`cube-wrapper ${status !== \"idle\" ? \"locked\" : \"\"}`}\n style={status === \"idle\" ? driftStyle : {}}\n >\n <div\n ref={cubeRef}\n className={`cube ${status !== \"idle\" ? \"is-spinning\" : \"\"}`}\n style={{ transition: \"none\" }}\n >\n <div\n className=\"face front\"\n ref={(el) => (faceRefs.current[0] = el)}\n ></div>\n <div\n className=\"face bottom\"\n ref={(el) => (faceRefs.current[1] = el)}\n ></div>\n <div\n className=\"face back\"\n ref={(el) => (faceRefs.current[2] = el)}\n ></div>\n <div\n className=\"face top\"\n ref={(el) => (faceRefs.current[3] = el)}\n ></div>\n <div className=\"face left\"></div>\n <div className=\"face right\"></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {/* Exposed Controls for the parent to style as they wish */}\n <div className=\"controls\" style={{ marginTop: 40 }}>\n <button\n className=\"cyber-button\"\n onClick={handleStart}\n disabled={status !== \"idle\"}\n >\n Spin\n </button>\n <button\n className=\"cyber-button stop-btn\"\n onClick={handleStop}\n disabled={status !== \"spinning\"}\n >\n Stop\n </button>\n </div>\n </div>\n );\n};\n\nexport default InfiniteCube;\n"],"names":["DEMO_ITEMS","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_useState","useState","status","setStatus","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","length","style","finishGame","requestAnimationFrame","startIndex","i","el","innerText","winningItem","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "react-holographic-cube",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A 3D holographic spinning cube component for React",
5
5
  "source": "src/index.js",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.module.js",
8
8
  "style": "dist/index.css",
9
9
  "scripts": {
10
- "build": "microbundle",
11
- "watch": "microbundle watch"
10
+ "build": "microbundle --jsx React.createElement --jsxFragment React.Fragment",
11
+ "watch": "microbundle watch --jsx React.createElement --jsxFragment React.Fragment"
12
12
  },
13
13
  "peerDependencies": {
14
14
  "react": ">=16",