react-holographic-cube 1.0.0
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/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.modern.mjs +2 -0
- package/dist/index.modern.mjs.map +1 -0
- package/dist/index.module.js +2 -0
- package/dist/index.module.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +20 -0
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.scene{height:200px;margin:0 auto;perspective:1000px;position:relative;transform-style:preserve-3d;width:200px}.light-pillar{background:linear-gradient(180deg,transparent 0,rgba(0,247,255,0) 20%,rgba(0,247,255,.1) 50%,rgba(0,247,255,0) 80%,transparent);filter:blur(20px);height:2000px;transform:translate(-50%,-50%) translateZ(-250px);width:120px;z-index:0}.hi-tech-floor,.light-pillar{left:50%;pointer-events:none;position:absolute;top:50%}.hi-tech-floor{background-color:transparent;background-image:radial-gradient(circle at center,transparent 0,#050510 60%),linear-gradient(rgba(0,247,255,.3) 1px,transparent 0),linear-gradient(90deg,rgba(0,247,255,.3) 1px,transparent 0);background-size:100% 100%,60px 60px,60px 60px;height:4000px;transform:translate(-50%,-50%) rotateX(90deg) translateZ(-130px);width:4000px;z-index:1}.cube-shadow{background:rgba(0,247,255,.2);box-shadow:0 0 50px rgba(0,247,255,.5);filter:blur(15px);height:160px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%) rotateX(90deg) translateZ(-128px);width:160px;z-index:2}.cube-wrapper{align-items:center;display:flex;height:100%;justify-content:center;position:relative;transform-style:preserve-3d;transition:transform 4s ease-in-out;width:100%}.cube-wrapper.locked{transform:translateZ(0) rotateX(0) rotateY(0) rotate(0)!important;transition:transform .5s cubic-bezier(.2,.8,.2,1)}.cube{height:100%;position:relative;transform-style:preserve-3d;transition:none;width:100%;will-change:transform;z-index:10}.face{align-items:center;backdrop-filter:blur(8px);backface-visibility:hidden;background:rgba(0,20,40,.6);border:2px solid #00db46;border-radius:1.25rem;box-shadow:0 0 15px rgba(0,247,255,.3),inset 0 0 30px rgba(0,247,255,.1);display:flex;font-size:80px;height:200px;justify-content:center;position:absolute;text-shadow:0 0 20px rgba(0,219,70,.95);-webkit-user-select:none;-moz-user-select:none;user-select:none;width:200px}.front{transform:rotateX(0deg) translateZ(100px)}.bottom{transform:rotateX(-90deg) translateZ(100px)}.back{transform:rotateX(-180deg) translateZ(100px)}.top{transform:rotateX(-270deg) translateZ(100px)}.left{transform:rotateY(-90deg) translateZ(100px)}.right{transform:rotateY(90deg) translateZ(100px)}.cube.is-spinning .face{animation:energyPulse .1s infinite alternate;border-color:#afffd3;box-shadow:0 0 40px rgba(0,219,70,.6),inset 0 0 60px rgba(0,219,70,.4)}@keyframes energyPulse{0%{box-shadow:0 0 30px rgba(0,219,70,.5),inset 0 0 40px rgba(0,219,70,.3)}to{background:rgba(0,219,70,.2);box-shadow:0 0 60px #00db46,inset 0 0 70px rgba(0,219,70,.6)}}.controls{display:flex;gap:20px;justify-content:center;margin-top:20px}.winner-text{color:#fff;font-size:2rem;font-weight:800;letter-spacing:1px;margin-top:4rem;min-height:50px;text-shadow:0 0 15px rgba(0,219,70,.95)}.cyber-button{background:transparent;border:2px solid #00db46;box-shadow:0 0 10px rgba(0,247,255,.2);color:#00db46;cursor:pointer;font-size:16px;font-weight:700;letter-spacing:2px;outline:none;padding:12px 36px;text-transform:uppercase;transition:all .2s ease}.cyber-button:hover:not(:disabled){background:#00db46;box-shadow:0 0 25px rgba(0,219,70,.8);color:#000}.cyber-button:disabled{border-color:#555;box-shadow:none;color:#555;cursor:not-allowed;opacity:.3}.stop-btn{border-color:#7f63f5;box-shadow:0 0 10px rgba(127,99,245,.5);color:#7f63f5}.stop-btn:hover:not(:disabled){background:#7f63f5;box-shadow:0 0 25px rgba(127,99,245,.8);color:#fff}
|
|
2
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["styles.css"],"names":[],"mappings":"AAKA,OAEE,YAAa,CAEb,aAAc,CADd,kBAAmB,CAEnB,iBAAkB,CAClB,2BAA4B,CAL5B,WAMF,CAGA,cAOE,+HAOC,CACD,iBAAkB,CAZlB,aAAc,CAGd,iDAAmD,CAJnD,WAAY,CAeZ,SACF,CAGA,6BAjBE,QAAS,CAYT,mBAAoB,CAfpB,iBAAkB,CAIlB,OAmCF,CAnBA,eAIE,4BAA6B,CAO7B,8LAGqE,CAErE,6CAAgD,CAbhD,aAAc,CAKd,gEAAkE,CANlE,YAAa,CAgBb,SACF,CAGA,aAIE,6BAAkC,CAClC,sCAA2C,CAI3C,iBAAkB,CANlB,YAAa,CAGb,QAAS,CALT,iBAAkB,CAMlB,OAAQ,CACR,gEAAkE,CANlE,WAAY,CAQZ,SACF,CASA,cAOE,kBAAmB,CADnB,YAAa,CAJb,WAAY,CAMZ,sBAAuB,CALvB,iBAAkB,CAClB,2BAA4B,CAC5B,mCAAoC,CAJpC,UAQF,CAKA,qBAEE,iEAA2E,CAD3E,iDAEF,CAGA,MAEE,WAAY,CACZ,iBAAkB,CAClB,2BAA4B,CAK5B,eAAgB,CARhB,UAAW,CASX,qBAAsB,CALtB,UAMF,CAMA,MAoBE,kBAAmB,CAbnB,yBAA0B,CAmB1B,0BAA2B,CApB3B,2BAAgC,CAIhC,wBAAyB,CACzB,qBAAsB,CAGtB,wEAEuC,CAGvC,YAAa,CAGb,cAAe,CAnBf,YAAa,CAkBb,sBAAuB,CApBvB,iBAAkB,CAsBlB,uCAA4C,CAI5C,wBAAiB,CAAjB,qBAAiB,CAAjB,gBAAiB,CAzBjB,WA0BF,CAGA,OAAU,yCAA4C,CACtD,QAAU,2CAA8C,CACxD,MAAU,4CAA+C,CACzD,KAAU,4CAA+C,CAGzD,MAAU,2CAA8C,CACxD,OAAU,0CAA6C,CAOvD,wBAKE,4CAA8C,CAJ9C,oBAAqB,CACrB,sEAIF,CAEA,uBACE,GACE,sEAGF,CACA,GAIE,4BAAiC,CAHjC,4DAIF,CACF,CAMA,UAEE,YAAa,CAEb,QAAS,CADT,sBAAuB,CAFvB,eAIF,CAEA,aAIE,UAAc,CAFd,cAAe,CACf,eAAgB,CAIhB,kBAAmB,CANnB,eAAgB,CAKhB,eAAgB,CADhB,uCAGF,CAGA,cACE,sBAAuB,CACvB,wBAAyB,CAQzB,sCAA2C,CAP3C,aAAc,CAMd,cAAe,CAJf,cAAe,CACf,eAAiB,CAEjB,kBAAmB,CAInB,YAAa,CARb,iBAAkB,CAGlB,wBAAyB,CAIzB,uBAEF,CAEA,mCACE,kBAAmB,CAEnB,qCAA0C,CAD1C,UAEF,CAEA,uBAGE,iBAAkB,CAElB,eAAgB,CADhB,UAAW,CAFX,kBAAmB,CADnB,UAKF,CAGA,UACE,oBAAqB,CAErB,uCAA4C,CAD5C,aAEF,CAEA,+BACE,kBAAmB,CAEnB,uCAA4C,CAD5C,UAEF","file":"index.css","sourcesContent":["/* =========================================\n 1. The 3D Scene & Environment\n ========================================= */\n\n/* The stage that holds the 3D world */\n.scene {\n width: 200px;\n height: 200px;\n perspective: 1000px; /* Controls the 3D depth */\n margin: 0 auto;\n position: relative;\n transform-style: preserve-3d;\n}\n\n/* The Background Light Pillar (Hologram Beam) */\n.light-pillar {\n position: absolute;\n width: 120px;\n height: 2000px;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%) translateZ(-250px);\n background: linear-gradient(\n to bottom,\n transparent 0%,\n rgba(0, 247, 255, 0.0) 20%,\n rgba(0, 247, 255, 0.1) 50%,\n rgba(0, 247, 255, 0.0) 80%,\n transparent 100%\n );\n filter: blur(20px);\n pointer-events: none;\n z-index: 0;\n}\n\n/* The Infinite Grid Floor */\n.hi-tech-floor {\n position: absolute;\n width: 4000px;\n height: 4000px;\n background-color: transparent;\n left: 50%;\n top: 50%;\n /* Rotate flat and push down below the cube */\n transform: translate(-50%, -50%) rotateX(90deg) translateZ(-130px);\n\n /* Radial fade to black + Cyan Grid */\n background-image: \n radial-gradient(circle at center, transparent 0%, #050510 60%),\n linear-gradient(rgba(0, 247, 255, 0.3) 1px, transparent 1px),\n linear-gradient(90deg, rgba(0, 247, 255, 0.3) 1px, transparent 1px);\n\n background-size: 100% 100%, 60px 60px, 60px 60px;\n pointer-events: none;\n z-index: 1;\n}\n\n/* The Shadow underneath the floating cube */\n.cube-shadow {\n position: absolute;\n width: 160px;\n height: 160px;\n background: rgba(0, 247, 255, 0.2);\n box-shadow: 0 0 50px rgba(0, 247, 255, 0.5);\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%) rotateX(90deg) translateZ(-128px);\n filter: blur(15px);\n z-index: 2;\n}\n\n/* =========================================\n 2. The Cube & Wrapper\n ========================================= */\n\n/* The Wrapper handles the \"Idle Drift\" (Floating).\n It transitions slowly (4s) between random positions.\n*/\n.cube-wrapper {\n width: 100%;\n height: 100%;\n position: relative;\n transform-style: preserve-3d;\n transition: transform 4s ease-in-out; \n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* When spinning, we lock the wrapper to the center \n so the physics spin aligns perfectly.\n*/\n.cube-wrapper.locked {\n transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);\n transform: translate3d(0, 0, 0) rotateX(0) rotateY(0) rotateZ(0) !important;\n}\n\n/* The Inner Cube (Handles the fast vertical spin) */\n.cube {\n width: 100%;\n height: 100%;\n position: relative;\n transform-style: preserve-3d;\n z-index: 10;\n \n /* CRITICAL: No CSS transition allowed here. \n The JS loop handles the rotation frame-by-frame. */\n transition: none; \n will-change: transform;\n}\n\n/* =========================================\n 3. The Faces (Holographic Style)\n ========================================= */\n\n.face {\n position: absolute;\n width: 200px;\n height: 200px;\n\n /* Glassy Transparency */\n background: rgba(0, 20, 40, 0.6);\n backdrop-filter: blur(8px);\n\n /* Neon Green Border */\n border: 2px solid #00db46;\n border-radius: 1.25rem;\n\n /* Inner and Outer Glow */\n box-shadow: \n 0 0 15px rgba(0, 247, 255, 0.3),\n inset 0 0 30px rgba(0, 247, 255, 0.1);\n\n /* Content Styling */\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 80px;\n text-shadow: 0 0 20px rgba(0, 219, 70, 0.95);\n\n /* Optimization */\n backface-visibility: hidden;\n user-select: none;\n}\n\n/* Face Positions */\n.front { transform: rotateX(0deg) translateZ(100px); }\n.bottom { transform: rotateX(-90deg) translateZ(100px); }\n.back { transform: rotateX(-180deg) translateZ(100px); }\n.top { transform: rotateX(-270deg) translateZ(100px); }\n\n/* The Side Caps (Closing the cube) */\n.left { transform: rotateY(-90deg) translateZ(100px); }\n.right { transform: rotateY(90deg) translateZ(100px); }\n\n/* =========================================\n 4. High Energy Spin Effects\n ========================================= */\n\n/* When the cube is spinning, supercharge the glow */\n.cube.is-spinning .face {\n border-color: #afffd3; /* White-hot green */\n box-shadow: \n 0 0 40px rgba(0, 219, 70, 0.6),\n inset 0 0 60px rgba(0, 219, 70, 0.4);\n animation: energyPulse 0.1s infinite alternate;\n}\n\n@keyframes energyPulse {\n 0% {\n box-shadow: \n 0 0 30px rgba(0, 219, 70, 0.5),\n inset 0 0 40px rgba(0, 219, 70, 0.3);\n }\n 100% {\n box-shadow: \n 0 0 60px rgba(0, 219, 70, 1),\n inset 0 0 70px rgba(0, 219, 70, 0.6);\n background: rgba(0, 219, 70, 0.2);\n }\n}\n\n/* =========================================\n 5. UI Controls\n ========================================= */\n\n.controls {\n margin-top: 20px;\n display: flex;\n justify-content: center;\n gap: 20px;\n}\n\n.winner-text {\n margin-top: 4rem;\n font-size: 2rem;\n font-weight: 800;\n color: #ffffff;\n text-shadow: 0 0 15px rgba(0, 219, 70, 0.95);\n min-height: 50px;\n letter-spacing: 1px;\n}\n\n/* Cyberpunk Button Styles */\n.cyber-button {\n background: transparent;\n border: 2px solid #00db46;\n color: #00db46;\n padding: 12px 36px;\n font-size: 16px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 2px;\n cursor: pointer;\n box-shadow: 0 0 10px rgba(0, 247, 255, 0.2);\n transition: all 0.2s ease;\n outline: none;\n}\n\n.cyber-button:hover:not(:disabled) {\n background: #00db46;\n color: #000;\n box-shadow: 0 0 25px rgba(0, 219, 70, 0.8);\n}\n\n.cyber-button:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n border-color: #555;\n color: #555;\n box-shadow: none;\n}\n\n/* Stop Button Variation */\n.stop-btn {\n border-color: #7f63f5;\n color: #7f63f5;\n box-shadow: 0 0 10px rgba(127, 99, 245, 0.5);\n}\n\n.stop-btn:hover:not(:disabled) {\n background: #7f63f5;\n color: #fff;\n box-shadow: 0 0 25px rgba(127, 99, 245, 0.8);\n}"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +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")))};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +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};
|
|
2
|
+
//# sourceMappingURL=index.modern.mjs.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +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};
|
|
2
|
+
//# sourceMappingURL=index.module.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +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")))}});
|
|
2
|
+
//# sourceMappingURL=index.umd.js.map
|
|
@@ -0,0 +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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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-holographic-cube",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A 3D holographic spinning cube component for React",
|
|
5
|
+
"source": "src/index.js",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.module.js",
|
|
8
|
+
"style": "dist/styles.css",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "microbundle",
|
|
11
|
+
"watch": "microbundle watch"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"react": ">=16",
|
|
15
|
+
"react-dom": ">=16"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
]
|
|
20
|
+
}
|