react-holographic-cube 1.0.4 → 1.0.5

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
@@ -2,14 +2,16 @@
2
2
 
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
+ Now supports **dynamic colors per item**, custom physics, and full style overrides!
6
+
5
7
  ![Holographic Cube Preview](https://media4.giphy.com/media/v1.Y2lkPTc5MGI3NjExZTVyamF6bjlsYjB5ZmdmbnlrY2RpNGtsYm9oZW0zNGN4eDZ1YmZmNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/IWt8NLETm6OLAnHE8C/giphy.gif)
6
8
 
7
9
  ## Features
8
10
 
9
- - **đŸ•šī¸ Physics-Based:** Real momentum and friction (no pre-baked animations).
11
+ - **🎨 Dynamic Item Colors:** Assign specific neon colors to individual items (e.g., Red for Fire, Blue for Water).
12
+ - **đŸ•šī¸ Physics Control:** Adjust `friction` and `initialSpeed` to control how long the spin lasts.
10
13
  - **🔮 Holographic Styling:** Glassy textures, neon borders, and "light pillar" effects.
11
14
  - **💨 Anti-Stutter:** Uses a "treadmill" logic to spin infinitely without visual glitches.
12
- - **🧊 Closed Geometry:** Fully 3D closed cube (including side caps).
13
15
  - **📱 Responsive:** Scales nicely within its container.
14
16
 
15
17
  ## Installation
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
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")))};
1
+ var e=require("react");function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=/*#__PURE__*/t(e);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(null,arguments)}var a=[{content:"1",color:"#00f7ff"},{content:"2",color:"#00db46"},{content:"3",color:"#ff00e6"},{content:"4",color:"#ffbd00"}];module.exports=function(t){var c=t.items,o=void 0===c?a:c,l=t.onWinner,u=t.perspective,i=void 0===u?"1000px":u,s=t.initialSpeed,d=void 0===s?30:s,f=t.friction,m=void 0===f?.98:f,p=t.showResult,v=void 0===p||p,g=t.resultStyle,b=void 0===g?{}:g,y=t.cubeStyle,h=void 0===y?{}:y,E=e.useState("idle"),x=E[0],N=E[1],S=e.useState(null),R=S[0],w=S[1],T=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),k=T[0],M=T[1],X=e.useRef(null),j=e.useRef([]),C=e.useRef(null),O=e.useRef(0),Y=e.useRef(0),Z=e.useRef(0),q=e.useRef("idle"),A=function(e){var t=o[e%o.length];return"string"==typeof t?{content:t,color:"#00db46"}:{content:t.content,color:t.color||"#00db46"}};e.useEffect(function(){return function(){return cancelAnimationFrame(C.current)}},[]),e.useEffect(function(){I(0)},[o]),e.useEffect(function(){var e,t=function(){if("idle"===q.current){var n=30*(Math.random()-.5),r=30*(Math.random()-.5),a=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;M({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+n+"deg) rotateY("+r+"deg) rotateZ("+a+"deg)"});var o=4e3+1e3*Math.random();e=setTimeout(t,o)}};return"idle"===x?t():(clearTimeout(e),M({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[x]);var F=function(){O.current+=Y.current,O.current>=90&&(O.current%=90,Z.current=(Z.current+1)%o.length,I(Z.current)),X.current&&(X.current.style.transform="rotateX("+O.current+"deg)"),"stopping"===q.current&&(Y.current*=m,Y.current<.5&&(Y.current=.5),Y.current<=.5&&O.current<1)?z():C.current=requestAnimationFrame(F)},I=function(e){for(var t=0;t<4;t++){var n=A((e+t)%o.length),r=j.current[t];r&&(r.innerText=n.content,r.style.borderColor=n.color,r.style.boxShadow="0 0 15px "+n.color+"4d, inset 0 0 30px "+n.color+"1a",r.style.textShadow="0 0 20px "+n.color)}},z=function(){X.current&&(X.current.style.transform="rotateX(0deg)");var e=A(Z.current);N("idle"),q.current="idle",w(e.content),l&&l(e.content)};/*#__PURE__*/return n.default.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/n.default.createElement("div",{className:"scene",style:{perspective:i}},/*#__PURE__*/n.default.createElement("div",{className:"light-pillar"}),/*#__PURE__*/n.default.createElement("div",{className:"cube-wrapper "+("idle"!==x?"locked":""),style:"idle"===x?k:{}},/*#__PURE__*/n.default.createElement("div",{ref:X,className:"cube "+("idle"!==x?"is-spinning":""),style:{transition:"none"}},[0,1,2,3].map(function(e){/*#__PURE__*/return n.default.createElement("div",{key:e,className:"face "+["front","bottom","back","top"][e],ref:function(t){return j.current[e]=t},style:h})}),/*#__PURE__*/n.default.createElement("div",{className:"face left",style:h}),/*#__PURE__*/n.default.createElement("div",{className:"face right",style:h}))),/*#__PURE__*/n.default.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/n.default.createElement("div",{className:"hi-tech-floor"})),v&&/*#__PURE__*/n.default.createElement("div",{className:"winner-text",style:r({marginTop:"4rem",minHeight:"50px"},b)},R?"Result: "+R:"..."),/*#__PURE__*/n.default.createElement("div",{className:"controls",style:{marginTop:20}},/*#__PURE__*/n.default.createElement("button",{className:"cyber-button",onClick:function(){"idle"===q.current&&(w(null),N("spinning"),q.current="spinning",Y.current=d,Z.current=0,O.current=0,I(0),F())},disabled:"idle"!==x},"Spin"),/*#__PURE__*/n.default.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===q.current&&(N("stopping"),q.current="stopping")},disabled:"spinning"!==x},"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","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","marginTop","onClick","disabled"],"mappings":"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"}
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 = [\n { content: \"1\", color: \"#00f7ff\" },\n { content: \"2\", color: \"#00db46\" },\n { content: \"3\", color: \"#ff00e6\" },\n { content: \"4\", color: \"#ffbd00\" },\n];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n initialSpeed = 30, // How fast it starts spinning\n friction = 0.98, // 0.99 = long spin, 0.90 = short spin\n showResult = true, // Show/Hide the text below\n resultStyle = {}, // Custom styles for the result text\n cubeStyle = {}, // Override the generic cube face style\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\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 const MIN_CRAWL_SPEED = 0.5;\n\n // --- Helper: Normalize Item Data ---\n // Ensures we handle both [\"A\", \"B\"] and [{content:\"A\"}, {content:\"B\"}]\n const getItemData = (index) => {\n const rawItem = items[index % items.length];\n if (typeof rawItem === \"string\") {\n return { content: rawItem, color: \"#00db46\" }; // Default neon green\n }\n return {\n content: rawItem.content,\n color: rawItem.color || \"#00db46\", // Fallback color\n };\n };\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]);\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\n // Use the prop for speed\n speedRef.current = initialSpeed;\n\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 // Use the prop for friction\n speedRef.current *= friction;\n\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 data = getItemData(itemIndex);\n const el = faceRefs.current[i];\n\n if (el) {\n el.innerText = data.content;\n\n // DYNAMIC STYLING\n // We inject the color directly into the CSS variables or styles\n el.style.borderColor = data.color;\n el.style.boxShadow = `0 0 15px ${data.color}4d, inset 0 0 30px ${data.color}1a`; // Hex alpha hacks\n el.style.textShadow = `0 0 20px ${data.color}`;\n }\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningData = getItemData(listPointerRef.current);\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningData.content);\n\n if (onWinner) onWinner(winningData.content);\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 {/* Optional: You can pass a prop to hide this pillar too if desired */}\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 {/* The 4 active faces */}\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className={`face ${[\"front\", \"bottom\", \"back\", \"top\"][i]}`}\n ref={(el) => (faceRefs.current[i] = el)}\n style={cubeStyle} // Apply user overrides\n ></div>\n ))}\n\n {/* Caps */}\n <div className=\"face left\" style={cubeStyle}></div>\n <div className=\"face right\" style={cubeStyle}></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {showResult && (\n <div\n className=\"winner-text\"\n style={{ marginTop: \"4rem\", minHeight: \"50px\", ...resultStyle }}\n >\n {winner ? `Result: ${winner}` : \"...\"}\n </div>\n )}\n\n <div className=\"controls\" style={{ marginTop: 20 }}>\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","content","color","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_ref$initialSpeed","initialSpeed","_ref$friction","friction","_ref$showResult","showResult","_ref$resultStyle","resultStyle","_ref$cubeStyle","cubeStyle","_useState","useState","status","setStatus","_useState2","winner","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","getItemData","index","rawItem","length","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","style","finishGame","requestAnimationFrame","startIndex","i","data","el","innerText","borderColor","boxShadow","textShadow","winningData","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","map","key","_extends","marginTop","minHeight","onClick","disabled"],"mappings":"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"}
@@ -1,2 +1,2 @@
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};
1
+ import e,{useState as t,useRef as r,useEffect as n}from"react";function c(){return c=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)({}).hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},c.apply(null,arguments)}const o=[{content:"1",color:"#00f7ff"},{content:"2",color:"#00db46"},{content:"3",color:"#ff00e6"},{content:"4",color:"#ffbd00"}],l=({items:l=o,onWinner:a,perspective:s="1000px",initialSpeed:i=30,friction:u=.98,showResult:d=!0,resultStyle:m={},cubeStyle:p={}})=>{const[f,g]=t("idle"),[b,y]=t(null),[h,v]=t({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),x=r(null),E=r([]),N=r(null),$=r(0),w=r(0),S=r(0),T=r("idle"),k=e=>{const t=l[e%l.length];return"string"==typeof t?{content:t,color:"#00db46"}:{content:t.content,color:t.color||"#00db46"}};n(()=>()=>cancelAnimationFrame(N.current),[]),n(()=>{X(0)},[l]),n(()=>{let e;const t=()=>{if("idle"!==T.current)return;const r=30*(Math.random()-.5),n=30*(Math.random()-.5),c=10*(Math.random()-.5),o=30*(Math.random()-.5)-5;v({transform:`translate3d(0px, ${o}px, 0px) rotateX(${r}deg) rotateY(${n}deg) rotateZ(${c}deg)`});const l=4e3+1e3*Math.random();e=setTimeout(t,l)};return"idle"===f?t():(clearTimeout(e),v({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),()=>clearTimeout(e)},[f]);const M=()=>{$.current+=w.current,$.current>=90&&($.current%=90,S.current=(S.current+1)%l.length,X(S.current)),x.current&&(x.current.style.transform=`rotateX(${$.current}deg)`),"stopping"===T.current&&(w.current*=u,w.current<.5&&(w.current=.5),w.current<=.5&&$.current<1)?C():N.current=requestAnimationFrame(M)},X=e=>{for(let t=0;t<4;t++){const r=k((e+t)%l.length),n=E.current[t];n&&(n.innerText=r.content,n.style.borderColor=r.color,n.style.boxShadow=`0 0 15px ${r.color}4d, inset 0 0 30px ${r.color}1a`,n.style.textShadow=`0 0 20px ${r.color}`)}},C=()=>{x.current&&(x.current.style.transform="rotateX(0deg)");const e=k(S.current);g("idle"),T.current="idle",y(e.content),a&&a(e.content)};/*#__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"!==f?"locked":""),style:"idle"===f?h:{}},/*#__PURE__*/e.createElement("div",{ref:x,className:"cube "+("idle"!==f?"is-spinning":""),style:{transition:"none"}},[0,1,2,3].map(t=>/*#__PURE__*/e.createElement("div",{key:t,className:`face ${["front","bottom","back","top"][t]}`,ref:e=>E.current[t]=e,style:p})),/*#__PURE__*/e.createElement("div",{className:"face left",style:p}),/*#__PURE__*/e.createElement("div",{className:"face right",style:p}))),/*#__PURE__*/e.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/e.createElement("div",{className:"hi-tech-floor"})),d&&/*#__PURE__*/e.createElement("div",{className:"winner-text",style:c({marginTop:"4rem",minHeight:"50px"},m)},b?`Result: ${b}`:"..."),/*#__PURE__*/e.createElement("div",{className:"controls",style:{marginTop:20}},/*#__PURE__*/e.createElement("button",{className:"cyber-button",onClick:()=>{"idle"===T.current&&(y(null),g("spinning"),T.current="spinning",w.current=i,S.current=0,$.current=0,X(0),M())},disabled:"idle"!==f},"Spin"),/*#__PURE__*/e.createElement("button",{className:"cyber-button stop-btn",onClick:()=>{"spinning"===T.current&&(g("stopping"),T.current="stopping")},disabled:"spinning"!==f},"Stop")))};export{l 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","React","createElement","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 = [\n { content: \"1\", color: \"#00f7ff\" },\n { content: \"2\", color: \"#00db46\" },\n { content: \"3\", color: \"#ff00e6\" },\n { content: \"4\", color: \"#ffbd00\" },\n];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n initialSpeed = 30, // How fast it starts spinning\n friction = 0.98, // 0.99 = long spin, 0.90 = short spin\n showResult = true, // Show/Hide the text below\n resultStyle = {}, // Custom styles for the result text\n cubeStyle = {}, // Override the generic cube face style\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\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 const MIN_CRAWL_SPEED = 0.5;\n\n // --- Helper: Normalize Item Data ---\n // Ensures we handle both [\"A\", \"B\"] and [{content:\"A\"}, {content:\"B\"}]\n const getItemData = (index) => {\n const rawItem = items[index % items.length];\n if (typeof rawItem === \"string\") {\n return { content: rawItem, color: \"#00db46\" }; // Default neon green\n }\n return {\n content: rawItem.content,\n color: rawItem.color || \"#00db46\", // Fallback color\n };\n };\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]);\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\n // Use the prop for speed\n speedRef.current = initialSpeed;\n\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 // Use the prop for friction\n speedRef.current *= friction;\n\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 data = getItemData(itemIndex);\n const el = faceRefs.current[i];\n\n if (el) {\n el.innerText = data.content;\n\n // DYNAMIC STYLING\n // We inject the color directly into the CSS variables or styles\n el.style.borderColor = data.color;\n el.style.boxShadow = `0 0 15px ${data.color}4d, inset 0 0 30px ${data.color}1a`; // Hex alpha hacks\n el.style.textShadow = `0 0 20px ${data.color}`;\n }\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningData = getItemData(listPointerRef.current);\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningData.content);\n\n if (onWinner) onWinner(winningData.content);\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 {/* Optional: You can pass a prop to hide this pillar too if desired */}\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 {/* The 4 active faces */}\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className={`face ${[\"front\", \"bottom\", \"back\", \"top\"][i]}`}\n ref={(el) => (faceRefs.current[i] = el)}\n style={cubeStyle} // Apply user overrides\n ></div>\n ))}\n\n {/* Caps */}\n <div className=\"face left\" style={cubeStyle}></div>\n <div className=\"face right\" style={cubeStyle}></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {showResult && (\n <div\n className=\"winner-text\"\n style={{ marginTop: \"4rem\", minHeight: \"50px\", ...resultStyle }}\n >\n {winner ? `Result: ${winner}` : \"...\"}\n </div>\n )}\n\n <div className=\"controls\" style={{ marginTop: 20 }}>\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","content","color","InfiniteCube","items","onWinner","perspective","initialSpeed","friction","showResult","resultStyle","cubeStyle","status","setStatus","useState","winner","setWinner","driftStyle","setDriftStyle","transform","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","getItemData","index","rawItem","length","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","style","finishGame","requestAnimationFrame","startIndex","i","data","el","innerText","borderColor","boxShadow","textShadow","winningData","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","map","key","_extends","marginTop","minHeight","onClick","handleStart","disabled","handleStop"],"mappings":"uRAIA,MAAMA,EAAa,CACjB,CAAEC,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,YAGnBC,EAAeA,EACnBC,MAAAA,EAAQJ,EACRK,WACAC,YAAAA,EAAc,SACdC,aAAAA,EAAe,GACfC,SAAAA,EAAW,IACXC,WAAAA,GAAa,EACbC,YAAAA,EAAc,CAAE,EAChBC,UAAAA,EAAY,CAAA,MAEZ,MAAOC,EAAQC,GAAaC,EAAS,SAC9BC,EAAQC,GAAaF,EAAS,OAE9BG,EAAYC,GAAiBJ,EAAS,CAC3CK,UAAW,wDAGPC,EAAUC,EAAO,MACjBC,EAAWD,EAAO,IAClBE,EAAeF,EAAO,MAEtBG,EAAcH,EAAO,GACrBI,EAAWJ,EAAO,GAClBK,EAAiBL,EAAO,GACxBM,EAAYN,EAAO,QAMnBO,EAAeC,IACnB,MAAMC,EAAU1B,EAAMyB,EAAQzB,EAAM2B,QACpC,MAAuB,iBAAZD,EACF,CAAE7B,QAAS6B,EAAS5B,MAAO,WAE7B,CACLD,QAAS6B,EAAQ7B,QACjBC,MAAO4B,EAAQ5B,OAAS,YAI5B8B,EAAU,IACD,IAAMC,qBAAqBV,EAAaW,SAC9C,IAEHF,EAAU,KACRG,EAAkB,IACjB,CAAC/B,IAGJ4B,EAAU,KACR,IAAII,EACJ,MAAMC,EAAgBA,KACpB,GAA0B,SAAtBV,EAAUO,QAAoB,OAElC,MAAMI,EAA6B,IAAvBC,KAAKC,SAAW,IACtBC,EAA6B,IAAvBF,KAAKC,SAAW,IACtBE,EAA6B,IAAvBH,KAAKC,SAAW,IACtBG,EAA6B,IAAvBJ,KAAKC,SAAW,IAAY,EAExCtB,EAAc,CACZC,UAAW,oBAAoBwB,qBAAsBL,iBAAkBG,iBAAkBC,UAG3F,MAAME,EAAe,IAAuB,IAAhBL,KAAKC,SACjCJ,EAAYS,WAAWR,EAAeO,IAWxC,MARe,SAAXhC,EACFyB,KAEAS,aAAaV,GACblB,EAAc,CACZC,UAAW,yDAGR,IAAM2B,aAAaV,IACzB,CAACxB,IAEJ,MAsBMmC,EAAOA,KACXvB,EAAYU,SAAWT,EAASS,QAG5BV,EAAYU,SAAW,KACzBV,EAAYU,SAAW,GACvBR,EAAeQ,SAAWR,EAAeQ,QAAU,GAAK9B,EAAM2B,OAC9DI,EAAkBT,EAAeQ,UAG/Bd,EAAQc,UACVd,EAAQc,QAAQc,MAAM7B,UAAY,WAAWK,EAAYU,eAIjC,aAAtBP,EAAUO,UAEZT,EAASS,SAAW1B,EAEhBiB,EAASS,QA9FO,KA+FlBT,EAASS,QA/FS,IAiGhBT,EAASS,SAjGO,IAiGuBV,EAAYU,QAAU,GAC/De,IAIJ1B,EAAaW,QAAUgB,sBAAsBH,IAGzCZ,EAAqBgB,IACzB,IAAK,IAAIC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,MACMC,EAAOzB,GADMuB,EAAaC,GAAKhD,EAAM2B,QAErCuB,EAAKhC,EAASY,QAAQkB,GAExBE,IACFA,EAAGC,UAAYF,EAAKpD,QAIpBqD,EAAGN,MAAMQ,YAAcH,EAAKnD,MAC5BoD,EAAGN,MAAMS,UAAY,YAAYJ,EAAKnD,2BAA2BmD,EAAKnD,UACtEoD,EAAGN,MAAMU,WAAa,YAAYL,EAAKnD,QAE3C,GAGI+C,EAAaA,KACb7B,EAAQc,UAASd,EAAQc,QAAQc,MAAM7B,UAAY,iBAEvD,MAAMwC,EAAc/B,EAAYF,EAAeQ,SAE/CrB,EAAU,QACVc,EAAUO,QAAU,OACpBlB,EAAU2C,EAAY1D,SAElBI,GAAUA,EAASsD,EAAY1D,uBAGrC,OACE2D,EAAAC,qBACEb,MAAO,CACLc,SAAU,WACVC,OAAQ,GACRC,MAAO,OACPC,QAAS,OACTC,cAAe,SACfC,WAAY,wBAGdP,EAAAC,cAAA,MAAA,CAAKO,UAAU,QAAQpB,MAAO,CAAE1C,YAAAA,iBAE9BsD,EAAAC,cAAA,MAAA,CAAKO,UAAU,8BAEfR,EAAAC,cAAA,MAAA,CACEO,UAAW,iBAA2B,SAAXxD,EAAoB,SAAW,IAC1DoC,MAAkB,SAAXpC,EAAoBK,EAAa,CAAG,gBAE3C2C,EAAAC,cAAA,MAAA,CACEQ,IAAKjD,EACLgD,UAAW,SAAmB,SAAXxD,EAAoB,cAAgB,IACvDoC,MAAO,CAAEsB,WAAY,SAGpB,CAAC,EAAG,EAAG,EAAG,GAAGC,IAAKnB,gBACjBQ,EAAAC,cAAA,MAAA,CACEW,IAAKpB,EACLgB,UAAW,QAAQ,CAAC,QAAS,SAAU,OAAQ,OAAOhB,KACtDiB,IAAMf,GAAQhC,EAASY,QAAQkB,GAAKE,EACpCN,MAAOrC,kBAKXiD,EAAAC,cAAKO,MAAAA,CAAAA,UAAU,YAAYpB,MAAOrC,iBAClCiD,EAAAC,cAAKO,MAAAA,CAAAA,UAAU,aAAapB,MAAOrC,mBAIvCiD,EAAAC,cAAKO,MAAAA,CAAAA,UAAU,6BACfR,EAAAC,cAAA,MAAA,CAAKO,UAAU,mBAGhB3D,gBACCmD,EAAAC,cACEO,MAAAA,CAAAA,UAAU,cACVpB,MAAKyB,EAAA,CAAIC,UAAW,OAAQC,UAAW,QAAWjE,IAEjDK,EAAS,WAAWA,IAAW,oBAIpC6C,EAAAC,cAAKO,MAAAA,CAAAA,UAAU,WAAWpB,MAAO,CAAE0B,UAAW,kBAC5Cd,EAAAC,wBACEO,UAAU,eACVQ,QA1IYC,KACQ,SAAtBlD,EAAUO,UACdlB,EAAU,MACVH,EAAU,YACVc,EAAUO,QAAU,WAGpBT,EAASS,QAAU3B,EAEnBmB,EAAeQ,QAAU,EACzBV,EAAYU,QAAU,EACtBC,EAAkB,GAClBY,MA+HM+B,SAAqB,SAAXlE,GACX,qBAGDgD,EAAAC,cAAA,SAAA,CACEO,UAAU,wBACVQ,QAlIWG,KACS,aAAtBpD,EAAUO,UACZrB,EAAU,YACVc,EAAUO,QAAU,aAgIhB4C,SAAqB,aAAXlE,GACX"}
@@ -1,2 +1,2 @@
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};
1
+ import e,{useState as t,useRef as n,useEffect as r}from"react";function o(){return o=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},o.apply(null,arguments)}var c=[{content:"1",color:"#00f7ff"},{content:"2",color:"#00db46"},{content:"3",color:"#ff00e6"},{content:"4",color:"#ffbd00"}],a=function(a){var l=a.items,i=void 0===l?c:l,s=a.onWinner,u=a.perspective,d=void 0===u?"1000px":u,m=a.initialSpeed,f=void 0===m?30:m,p=a.friction,v=void 0===p?.98:p,g=a.showResult,b=void 0===g||g,y=a.resultStyle,h=void 0===y?{}:y,x=a.cubeStyle,E=void 0===x?{}:x,N=t("idle"),w=N[0],S=N[1],T=t(null),k=T[0],M=T[1],X=t({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),C=X[0],O=X[1],Y=n(null),Z=n([]),j=n(null),A=n(0),F=n(0),I=n(0),R=n("idle"),q=function(e){var t=i[e%i.length];return"string"==typeof t?{content:t,color:"#00db46"}:{content:t.content,color:t.color||"#00db46"}};r(function(){return function(){return cancelAnimationFrame(j.current)}},[]),r(function(){D(0)},[i]),r(function(){var e,t=function(){if("idle"===R.current){var n=30*(Math.random()-.5),r=30*(Math.random()-.5),o=10*(Math.random()-.5),c=30*(Math.random()-.5)-5;O({transform:"translate3d(0px, "+c+"px, 0px) rotateX("+n+"deg) rotateY("+r+"deg) rotateZ("+o+"deg)"});var a=4e3+1e3*Math.random();e=setTimeout(t,a)}};return"idle"===w?t():(clearTimeout(e),O({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[w]);var z=function(){A.current+=F.current,A.current>=90&&(A.current%=90,I.current=(I.current+1)%i.length,D(I.current)),Y.current&&(Y.current.style.transform="rotateX("+A.current+"deg)"),"stopping"===R.current&&(F.current*=v,F.current<.5&&(F.current=.5),F.current<=.5&&A.current<1)?H():j.current=requestAnimationFrame(z)},D=function(e){for(var t=0;t<4;t++){var n=q((e+t)%i.length),r=Z.current[t];r&&(r.innerText=n.content,r.style.borderColor=n.color,r.style.boxShadow="0 0 15px "+n.color+"4d, inset 0 0 30px "+n.color+"1a",r.style.textShadow="0 0 20px "+n.color)}},H=function(){Y.current&&(Y.current.style.transform="rotateX(0deg)");var e=q(I.current);S("idle"),R.current="idle",M(e.content),s&&s(e.content)};/*#__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:d}},/*#__PURE__*/e.createElement("div",{className:"light-pillar"}),/*#__PURE__*/e.createElement("div",{className:"cube-wrapper "+("idle"!==w?"locked":""),style:"idle"===w?C:{}},/*#__PURE__*/e.createElement("div",{ref:Y,className:"cube "+("idle"!==w?"is-spinning":""),style:{transition:"none"}},[0,1,2,3].map(function(t){/*#__PURE__*/return e.createElement("div",{key:t,className:"face "+["front","bottom","back","top"][t],ref:function(e){return Z.current[t]=e},style:E})}),/*#__PURE__*/e.createElement("div",{className:"face left",style:E}),/*#__PURE__*/e.createElement("div",{className:"face right",style:E}))),/*#__PURE__*/e.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/e.createElement("div",{className:"hi-tech-floor"})),b&&/*#__PURE__*/e.createElement("div",{className:"winner-text",style:o({marginTop:"4rem",minHeight:"50px"},h)},k?"Result: "+k:"..."),/*#__PURE__*/e.createElement("div",{className:"controls",style:{marginTop:20}},/*#__PURE__*/e.createElement("button",{className:"cyber-button",onClick:function(){"idle"===R.current&&(M(null),S("spinning"),R.current="spinning",F.current=f,I.current=0,A.current=0,D(0),z())},disabled:"idle"!==w},"Spin"),/*#__PURE__*/e.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===R.current&&(S("stopping"),R.current="stopping")},disabled:"spinning"!==w},"Stop")))};export{a 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","React","createElement","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 = [\n { content: \"1\", color: \"#00f7ff\" },\n { content: \"2\", color: \"#00db46\" },\n { content: \"3\", color: \"#ff00e6\" },\n { content: \"4\", color: \"#ffbd00\" },\n];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n initialSpeed = 30, // How fast it starts spinning\n friction = 0.98, // 0.99 = long spin, 0.90 = short spin\n showResult = true, // Show/Hide the text below\n resultStyle = {}, // Custom styles for the result text\n cubeStyle = {}, // Override the generic cube face style\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\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 const MIN_CRAWL_SPEED = 0.5;\n\n // --- Helper: Normalize Item Data ---\n // Ensures we handle both [\"A\", \"B\"] and [{content:\"A\"}, {content:\"B\"}]\n const getItemData = (index) => {\n const rawItem = items[index % items.length];\n if (typeof rawItem === \"string\") {\n return { content: rawItem, color: \"#00db46\" }; // Default neon green\n }\n return {\n content: rawItem.content,\n color: rawItem.color || \"#00db46\", // Fallback color\n };\n };\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]);\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\n // Use the prop for speed\n speedRef.current = initialSpeed;\n\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 // Use the prop for friction\n speedRef.current *= friction;\n\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 data = getItemData(itemIndex);\n const el = faceRefs.current[i];\n\n if (el) {\n el.innerText = data.content;\n\n // DYNAMIC STYLING\n // We inject the color directly into the CSS variables or styles\n el.style.borderColor = data.color;\n el.style.boxShadow = `0 0 15px ${data.color}4d, inset 0 0 30px ${data.color}1a`; // Hex alpha hacks\n el.style.textShadow = `0 0 20px ${data.color}`;\n }\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningData = getItemData(listPointerRef.current);\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningData.content);\n\n if (onWinner) onWinner(winningData.content);\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 {/* Optional: You can pass a prop to hide this pillar too if desired */}\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 {/* The 4 active faces */}\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className={`face ${[\"front\", \"bottom\", \"back\", \"top\"][i]}`}\n ref={(el) => (faceRefs.current[i] = el)}\n style={cubeStyle} // Apply user overrides\n ></div>\n ))}\n\n {/* Caps */}\n <div className=\"face left\" style={cubeStyle}></div>\n <div className=\"face right\" style={cubeStyle}></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {showResult && (\n <div\n className=\"winner-text\"\n style={{ marginTop: \"4rem\", minHeight: \"50px\", ...resultStyle }}\n >\n {winner ? `Result: ${winner}` : \"...\"}\n </div>\n )}\n\n <div className=\"controls\" style={{ marginTop: 20 }}>\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","content","color","InfiniteCube","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_ref$initialSpeed","initialSpeed","_ref$friction","friction","_ref$showResult","showResult","_ref$resultStyle","resultStyle","_ref$cubeStyle","cubeStyle","_useState","useState","status","setStatus","_useState2","winner","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","getItemData","index","rawItem","length","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","style","finishGame","requestAnimationFrame","startIndex","i","data","el","innerText","borderColor","boxShadow","textShadow","winningData","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","map","key","_extends","marginTop","minHeight","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){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")))}});
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 n=/*#__PURE__*/t(e);function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(null,arguments)}var a=[{content:"1",color:"#00f7ff"},{content:"2",color:"#00db46"},{content:"3",color:"#ff00e6"},{content:"4",color:"#ffbd00"}];return function(t){var o=t.items,c=void 0===o?a:o,l=t.onWinner,i=t.perspective,u=void 0===i?"1000px":i,s=t.initialSpeed,f=void 0===s?30:s,d=t.friction,m=void 0===d?.98:d,p=t.showResult,v=void 0===p||p,b=t.resultStyle,g=void 0===b?{}:b,y=t.cubeStyle,h=void 0===y?{}:y,x=e.useState("idle"),E=x[0],N=x[1],S=e.useState(null),R=S[0],w=S[1],T=e.useState({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"}),k=T[0],M=T[1],X=e.useRef(null),j=e.useRef([]),C=e.useRef(null),O=e.useRef(0),Y=e.useRef(0),Z=e.useRef(0),q=e.useRef("idle"),A=function(e){var t=c[e%c.length];return"string"==typeof t?{content:t,color:"#00db46"}:{content:t.content,color:t.color||"#00db46"}};e.useEffect(function(){return function(){return cancelAnimationFrame(C.current)}},[]),e.useEffect(function(){H(0)},[c]),e.useEffect(function(){var e,t=function(){if("idle"===q.current){var n=30*(Math.random()-.5),r=30*(Math.random()-.5),a=10*(Math.random()-.5),o=30*(Math.random()-.5)-5;M({transform:"translate3d(0px, "+o+"px, 0px) rotateX("+n+"deg) rotateY("+r+"deg) rotateZ("+a+"deg)"});var c=4e3+1e3*Math.random();e=setTimeout(t,c)}};return"idle"===E?t():(clearTimeout(e),M({transform:"translate3d(0,0,0) rotateX(0) rotateY(0) rotateZ(0)"})),function(){return clearTimeout(e)}},[E]);var F=function(){O.current+=Y.current,O.current>=90&&(O.current%=90,Z.current=(Z.current+1)%c.length,H(Z.current)),X.current&&(X.current.style.transform="rotateX("+O.current+"deg)"),"stopping"===q.current&&(Y.current*=m,Y.current<.5&&(Y.current=.5),Y.current<=.5&&O.current<1)?I():C.current=requestAnimationFrame(F)},H=function(e){for(var t=0;t<4;t++){var n=A((e+t)%c.length),r=j.current[t];r&&(r.innerText=n.content,r.style.borderColor=n.color,r.style.boxShadow="0 0 15px "+n.color+"4d, inset 0 0 30px "+n.color+"1a",r.style.textShadow="0 0 20px "+n.color)}},I=function(){X.current&&(X.current.style.transform="rotateX(0deg)");var e=A(Z.current);N("idle"),q.current="idle",w(e.content),l&&l(e.content)};/*#__PURE__*/return n.default.createElement("div",{style:{position:"relative",zIndex:10,width:"100%",display:"flex",flexDirection:"column",alignItems:"center"}},/*#__PURE__*/n.default.createElement("div",{className:"scene",style:{perspective:u}},/*#__PURE__*/n.default.createElement("div",{className:"light-pillar"}),/*#__PURE__*/n.default.createElement("div",{className:"cube-wrapper "+("idle"!==E?"locked":""),style:"idle"===E?k:{}},/*#__PURE__*/n.default.createElement("div",{ref:X,className:"cube "+("idle"!==E?"is-spinning":""),style:{transition:"none"}},[0,1,2,3].map(function(e){/*#__PURE__*/return n.default.createElement("div",{key:e,className:"face "+["front","bottom","back","top"][e],ref:function(t){return j.current[e]=t},style:h})}),/*#__PURE__*/n.default.createElement("div",{className:"face left",style:h}),/*#__PURE__*/n.default.createElement("div",{className:"face right",style:h}))),/*#__PURE__*/n.default.createElement("div",{className:"cube-shadow"}),/*#__PURE__*/n.default.createElement("div",{className:"hi-tech-floor"})),v&&/*#__PURE__*/n.default.createElement("div",{className:"winner-text",style:r({marginTop:"4rem",minHeight:"50px"},g)},R?"Result: "+R:"..."),/*#__PURE__*/n.default.createElement("div",{className:"controls",style:{marginTop:20}},/*#__PURE__*/n.default.createElement("button",{className:"cyber-button",onClick:function(){"idle"===q.current&&(w(null),N("spinning"),q.current="spinning",Y.current=f,Z.current=0,O.current=0,H(0),F())},disabled:"idle"!==E},"Spin"),/*#__PURE__*/n.default.createElement("button",{className:"cyber-button stop-btn",onClick:function(){"spinning"===q.current&&(N("stopping"),q.current="stopping")},disabled:"spinning"!==E},"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","React","createElement","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 = [\n { content: \"1\", color: \"#00f7ff\" },\n { content: \"2\", color: \"#00db46\" },\n { content: \"3\", color: \"#ff00e6\" },\n { content: \"4\", color: \"#ffbd00\" },\n];\n\nconst InfiniteCube = ({\n items = DEMO_ITEMS,\n onWinner,\n perspective = \"1000px\",\n initialSpeed = 30, // How fast it starts spinning\n friction = 0.98, // 0.99 = long spin, 0.90 = short spin\n showResult = true, // Show/Hide the text below\n resultStyle = {}, // Custom styles for the result text\n cubeStyle = {}, // Override the generic cube face style\n}) => {\n const [status, setStatus] = useState(\"idle\");\n const [winner, setWinner] = useState(null);\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 const MIN_CRAWL_SPEED = 0.5;\n\n // --- Helper: Normalize Item Data ---\n // Ensures we handle both [\"A\", \"B\"] and [{content:\"A\"}, {content:\"B\"}]\n const getItemData = (index) => {\n const rawItem = items[index % items.length];\n if (typeof rawItem === \"string\") {\n return { content: rawItem, color: \"#00db46\" }; // Default neon green\n }\n return {\n content: rawItem.content,\n color: rawItem.color || \"#00db46\", // Fallback color\n };\n };\n\n useEffect(() => {\n return () => cancelAnimationFrame(animationRef.current);\n }, []);\n\n useEffect(() => {\n updateFaceContent(0);\n }, [items]);\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\n // Use the prop for speed\n speedRef.current = initialSpeed;\n\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 // Use the prop for friction\n speedRef.current *= friction;\n\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 data = getItemData(itemIndex);\n const el = faceRefs.current[i];\n\n if (el) {\n el.innerText = data.content;\n\n // DYNAMIC STYLING\n // We inject the color directly into the CSS variables or styles\n el.style.borderColor = data.color;\n el.style.boxShadow = `0 0 15px ${data.color}4d, inset 0 0 30px ${data.color}1a`; // Hex alpha hacks\n el.style.textShadow = `0 0 20px ${data.color}`;\n }\n }\n };\n\n const finishGame = () => {\n if (cubeRef.current) cubeRef.current.style.transform = `rotateX(0deg)`;\n\n const winningData = getItemData(listPointerRef.current);\n\n setStatus(\"idle\");\n statusRef.current = \"idle\";\n setWinner(winningData.content);\n\n if (onWinner) onWinner(winningData.content);\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 {/* Optional: You can pass a prop to hide this pillar too if desired */}\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 {/* The 4 active faces */}\n {[0, 1, 2, 3].map((i) => (\n <div\n key={i}\n className={`face ${[\"front\", \"bottom\", \"back\", \"top\"][i]}`}\n ref={(el) => (faceRefs.current[i] = el)}\n style={cubeStyle} // Apply user overrides\n ></div>\n ))}\n\n {/* Caps */}\n <div className=\"face left\" style={cubeStyle}></div>\n <div className=\"face right\" style={cubeStyle}></div>\n </div>\n </div>\n\n <div className=\"cube-shadow\"></div>\n <div className=\"hi-tech-floor\"></div>\n </div>\n\n {showResult && (\n <div\n className=\"winner-text\"\n style={{ marginTop: \"4rem\", minHeight: \"50px\", ...resultStyle }}\n >\n {winner ? `Result: ${winner}` : \"...\"}\n </div>\n )}\n\n <div className=\"controls\" style={{ marginTop: 20 }}>\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","content","color","_ref","_ref$items","items","onWinner","_ref$perspective","perspective","_ref$initialSpeed","initialSpeed","_ref$friction","friction","_ref$showResult","showResult","_ref$resultStyle","resultStyle","_ref$cubeStyle","cubeStyle","_useState","useState","status","setStatus","_useState2","winner","setWinner","_useState3","transform","driftStyle","setDriftStyle","cubeRef","useRef","faceRefs","animationRef","rotationRef","speedRef","listPointerRef","statusRef","getItemData","index","rawItem","length","useEffect","cancelAnimationFrame","current","updateFaceContent","timeoutId","floatRandomly","rX","Math","random","rY","rZ","tY","nextMoveTime","setTimeout","clearTimeout","loop","style","finishGame","requestAnimationFrame","startIndex","i","data","el","innerText","borderColor","boxShadow","textShadow","winningData","React","createElement","position","zIndex","width","display","flexDirection","alignItems","className","ref","transition","map","key","_extends","marginTop","minHeight","onClick","disabled"],"mappings":"ikBAIA,IAAMA,EAAa,CACjB,CAAEC,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,WACvB,CAAED,QAAS,IAAKC,MAAO,mBAGJ,SAAHC,OASZC,EAAAD,EARJE,MAAAA,WAAKD,EAAGJ,EAAUI,EAClBE,EAAQH,EAARG,SAAQC,EAAAJ,EACRK,YAAAA,WAAWD,EAAG,SAAQA,EAAAE,EAAAN,EACtBO,aAAAA,OAAY,IAAAD,EAAG,GAAEA,EAAAE,EAAAR,EACjBS,SAAAA,OAAW,IAAHD,EAAG,IAAIA,EAAAE,EAAAV,EACfW,WAAAA,OAAU,IAAAD,GAAOA,EAAAE,EAAAZ,EACjBa,YAAAA,OAAc,IAAHD,EAAG,CAAA,EAAEA,EAAAE,EAAAd,EAChBe,UAAAA,OAAY,IAAHD,EAAG,CAAE,EAAAA,EAEdE,EAA4BC,WAAS,QAA9BC,EAAMF,EAAEG,GAAAA,EAASH,EAAA,GACxBI,EAA4BH,EAAQA,SAAC,MAA9BI,EAAMD,EAAA,GAAEE,EAASF,EAExB,GAAAG,EAAoCN,EAAAA,SAAS,CAC3CO,UAAW,wDADNC,EAAUF,EAAA,GAAEG,EAAaH,EAIhC,GAAMI,EAAUC,EAAAA,OAAO,MACjBC,EAAWD,SAAO,IAClBE,EAAeF,EAAAA,OAAO,MAEtBG,EAAcH,SAAO,GACrBI,EAAWJ,SAAO,GAClBK,EAAiBL,SAAO,GACxBM,EAAYN,EAAMA,OAAC,QAMnBO,EAAc,SAACC,GACnB,IAAMC,EAAUnC,EAAMkC,EAAQlC,EAAMoC,QACpC,MAAuB,iBAAZD,EACF,CAAEvC,QAASuC,EAAStC,MAAO,WAE7B,CACLD,QAASuC,EAAQvC,QACjBC,MAAOsC,EAAQtC,OAAS,UAE5B,EAEAwC,YAAU,WACR,OAAa,WAAA,OAAAC,qBAAqBV,EAAaW,QAAQ,CACzD,EAAG,IAEHF,EAAAA,UAAU,WACRG,EAAkB,EACpB,EAAG,CAACxC,IAGJqC,EAASA,UAAC,WACR,IAAII,EACEC,EAAgB,WACpB,GAA0B,SAAtBV,EAAUO,QAAd,CAEA,IAAMI,EAA6B,IAAvBC,KAAKC,SAAW,IACtBC,EAA6B,IAAvBF,KAAKC,SAAW,IACtBE,EAA6B,IAAvBH,KAAKC,SAAW,IACtBG,EAA6B,IAAvBJ,KAAKC,SAAW,IAAY,EAExCrB,EAAc,CACZF,UAA+B0B,oBAAAA,sBAAsBL,EAAE,gBAAgBG,EAAE,gBAAgBC,EAC3F,SAEA,IAAME,EAAe,IAAuB,IAAhBL,KAAKC,SACjCJ,EAAYS,WAAWR,EAAeO,EAVtC,CAWF,EAUA,MARe,SAAXjC,EACF0B,KAEAS,aAAaV,GACbjB,EAAc,CACZF,UAAW,yDAGF,WAAA,OAAA6B,aAAaV,EAAU,CACtC,EAAG,CAACzB,IAEJ,IAsBMoC,EAAO,WACXvB,EAAYU,SAAWT,EAASS,QAG5BV,EAAYU,SAAW,KACzBV,EAAYU,SAAW,GACvBR,EAAeQ,SAAWR,EAAeQ,QAAU,GAAKvC,EAAMoC,OAC9DI,EAAkBT,EAAeQ,UAG/Bd,EAAQc,UACVd,EAAQc,QAAQc,MAAM/B,UAAS,WAAcO,EAAYU,QAC3D,QAG0B,aAAtBP,EAAUO,UAEZT,EAASS,SAAWhC,EAEhBuB,EAASS,QA9FO,KA+FlBT,EAASS,QA/FS,IAiGhBT,EAASS,SAjGO,IAiGuBV,EAAYU,QAAU,GAC/De,IAIJ1B,EAAaW,QAAUgB,sBAAsBH,EAC/C,EAEMZ,EAAoB,SAACgB,GACzB,IAAK,IAAIC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IACMC,EAAOzB,GADMuB,EAAaC,GAAKzD,EAAMoC,QAErCuB,EAAKhC,EAASY,QAAQkB,GAExBE,IACFA,EAAGC,UAAYF,EAAK9D,QAIpB+D,EAAGN,MAAMQ,YAAcH,EAAK7D,MAC5B8D,EAAGN,MAAMS,UAAS,YAAeJ,EAAK7D,MAA2B6D,sBAAAA,EAAK7D,MAAK,KAC3E8D,EAAGN,MAAMU,WAAU,YAAeL,EAAK7D,MAE3C,CACF,EAEMyD,EAAa,WACb7B,EAAQc,UAASd,EAAQc,QAAQc,MAAM/B,UAAS,iBAEpD,IAAM0C,EAAc/B,EAAYF,EAAeQ,SAE/CtB,EAAU,QACVe,EAAUO,QAAU,OACpBnB,EAAU4C,EAAYpE,SAElBK,GAAUA,EAAS+D,EAAYpE,QACrC,eAEA,OACEqE,EAAAA,QAAAC,cAAA,MAAA,CACEb,MAAO,CACLc,SAAU,WACVC,OAAQ,GACRC,MAAO,OACPC,QAAS,OACTC,cAAe,SACfC,WAAY,wBAGdP,EAAAA,QAAAC,cAAKO,MAAAA,CAAAA,UAAU,QAAQpB,MAAO,CAAElD,YAAAA,iBAE9B8D,EAAA,QAAAC,cAAA,MAAA,CAAKO,UAAU,8BAEfR,EAAA,QAAAC,cAAA,MAAA,CACEO,UAAS,iBAA6B,SAAXzD,EAAoB,SAAW,IAC1DqC,MAAkB,SAAXrC,EAAoBO,EAAa,CAAG,gBAE3C0C,EAAA,QAAAC,cACEQ,MAAAA,CAAAA,IAAKjD,EACLgD,UAAS,SAAqB,SAAXzD,EAAoB,cAAgB,IACvDqC,MAAO,CAAEsB,WAAY,SAGpB,CAAC,EAAG,EAAG,EAAG,GAAGC,IAAI,SAACnB,gBACjBQ,OAAAA,EAAA,QAAAC,qBACEW,IAAKpB,EACLgB,UAAmB,QAAA,CAAC,QAAS,SAAU,OAAQ,OAAOhB,GACtDiB,IAAK,SAACf,GAAE,OAAMhC,EAASY,QAAQkB,GAAKE,CAAE,EACtCN,MAAOxC,GACF,gBAIToD,EAAA,QAAAC,cAAA,MAAA,CAAKO,UAAU,YAAYpB,MAAOxC,iBAClCoD,EAAAA,QAAAC,cAAKO,MAAAA,CAAAA,UAAU,aAAapB,MAAOxC,mBAIvCoD,EAAA,QAAAC,cAAA,MAAA,CAAKO,UAAU,6BACfR,EAAA,QAAAC,cAAA,MAAA,CAAKO,UAAU,mBAGhBhE,gBACCwD,EAAA,QAAAC,cAAA,MAAA,CACEO,UAAU,cACVpB,MAAKyB,GAAIC,UAAW,OAAQC,UAAW,QAAWrE,IAEjDQ,EAAoBA,WAAAA,EAAW,oBAIpC8C,UAAAC,cAAA,MAAA,CAAKO,UAAU,WAAWpB,MAAO,CAAE0B,UAAW,kBAC5Cd,EAAAA,QAAAC,cACEO,SAAAA,CAAAA,UAAU,eACVQ,QA1IY,WACQ,SAAtBjD,EAAUO,UACdnB,EAAU,MACVH,EAAU,YACVe,EAAUO,QAAU,WAGpBT,EAASS,QAAUlC,EAEnB0B,EAAeQ,QAAU,EACzBV,EAAYU,QAAU,EACtBC,EAAkB,GAClBY,IACF,EA8HQ8B,SAAqB,SAAXlE,GACX,qBAGDiD,UAAAC,cAAA,SAAA,CACEO,UAAU,wBACVQ,QAlIW,WACS,aAAtBjD,EAAUO,UACZtB,EAAU,YACVe,EAAUO,QAAU,WAExB,EA8HQ2C,SAAqB,aAAXlE,GACX,SAMT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-holographic-cube",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "A 3D holographic spinning cube component for React",
5
5
  "source": "src/index.js",
6
6
  "main": "dist/index.js",