Cube 3D is an interactive 3D Rubik's Cube built with React, Three.js, and @react-three/fiber. It focuses on direct manipulation: you can rotate layers with drag gestures or keyboard moves, scramble instantly, and animate a solve sequence based on the moves tracked in the current session.
This README is written against the current codebase in this repository.
- Screenshots
- What It Does
- Current Solve Behavior
- Tech Stack
- Getting Started
- Available Scripts
- How to Use the App
- Architecture Overview
- Project Structure
- Rendering and Interaction Details
- Color and Orientation Model
- Development Notes
- Limitations
The app renders a full 3D Rubik's Cube and lets you:
- rotate the camera around the cube
- turn layers with mouse or touch dragging
- trigger moves from the keyboard
- scramble the cube instantly
- reset the cube to solved
- animate a solve sequence using the move history recorded in the current session
- track the visible move count during play and solve playback
The cube state is represented as individual cubies with per-face sticker colors. Turns are animated in the scene and then committed back into the logical state once the animation completes.
The current Solve button is not a general cube solver.
It works by reversing the normalized move history that produced the current cube state in the running app session. In practice that means:
- if you scramble and then press
Solve, the cube plays back the inverse of that scramble - if you scramble, make manual turns, and then press
Solve, the cube plays back the inverse of the combined tracked history - if the current state was not produced through the tracked history in this session, the app does not derive a fresh solution from cube state alone
When Solve starts, the visible move counter resets to 0, then counts only the animated solve moves.
- React 18
- Three.js
@react-three/fiber@react-three/drei@react-three/postprocessing- Vite
- Node.js 18+ is recommended
- npm
npm installnpm run devVite serves the app on port 5173 by default.
npm run buildnpm run previewStarts the local development server.
Builds the production bundle into dist/.
Serves the production build locally for inspection.
Runs the Node test runner. At the moment, the repository does not include an active automated test suite, so this command completes with zero tests.
- drag on empty space to orbit the camera
- scroll or pinch to zoom
- drag directly on a cubie face to turn a layer
- keyboard input supports face and slice moves
Press the move key for a clockwise quarter turn. Hold Shift for the inverse turn.
Supported keys:
R,L,U,D,F,BM,E,S
Scramble: applies a random 20-move scramble instantly and resets the visible counterSolve: replays the inverse of the tracked move history and resets the visible counter before playback startsReset: returns the cube to the solved state and clears all tracked state
src/App.jsx sets up:
- the
Canvas - lighting and fog
- environment and contact shadows
- post-processing
- the
Cubescene component - the HUD controls
src/hooks/useCubeState.js is the central state hook. It owns:
- the current cubie array
- the visible move history
- the visible move count
- current animation state
- the hidden normalized move history used by
Solve - the queued moves for solve playback
Important behavior in the hook:
- manual moves are not committed until the animation finishes
Scramblemutates the cube instantly but does not count those moves in the visible counterSolveresets the visible counter and replays inverse tracked moves
src/utils/cubeLogic.js contains the pure cube manipulation helpers:
- solved cube creation
- move parsing and application
- position rotation
- sticker rotation
- scramble generation
- solved-state detection
- move inversion and normalization helpers
src/components/Cube.jsx handles:
- active turn animation
- drag gesture interpretation
- keyboard move dispatch
- partitioning animated state from committed cube state
src/components/Cubie.jsx renders each physical cube piece and its stickers.
src/components/Controls.jsx renders:
- move count
- status text
- scramble, solve, and reset buttons
- interaction hints
cube-3d/
├── src/
│ ├── components/
│ │ ├── Controls.jsx
│ │ ├── Cube.jsx
│ │ ├── Cubie.jsx
│ │ └── ErrorBoundary.jsx
│ ├── hooks/
│ │ └── useCubeState.js
│ ├── utils/
│ │ └── cubeLogic.js
│ ├── App.jsx
│ ├── App.css
│ └── main.jsx
├── index.html
├── package.json
├── vite.config.js
└── README.md
Turns are animated over roughly 250ms. During an active turn:
- the intended move is stored as the current animation
- the scene renders the turning layer in motion
- the logical cube state is only committed after the animation completes
This keeps interactions visually smooth while preserving a clean state transition model.
The app uses pointer movement direction and the touched cubie's position to infer which layer the user intended to rotate. Small drags are ignored until a threshold is crossed, which helps prevent accidental turns.
Camera orbiting is disabled only while you are actively dragging a cubie face to start a layer turn. You can still orbit the camera during solve playback and other non-drag animations.
The cube uses this fixed face-color mapping:
+Xright: blue-Xleft: green+Yup: white-Ydown: yellow+Zfront: red-Zback: orange
This mapping lives in src/utils/cubeLogic.js and is used consistently for:
- initial solved state creation
- turn application
- solved-state checks
The app keeps a normalized hidden move history so adjacent turns on the same face can cancel or collapse before Solve reverses them. This reduces unnecessary playback steps.
The current production build emits a large main bundle and Vite will warn about chunk size during npm run build. That warning is expected with the current setup.
There is currently no meaningful automated test coverage in the repository. If you plan to extend the cube logic, adding targeted tests around cubeLogic.js and useCubeState.js would be the highest-value place to start.
Solveis history-based, not state-based- there is no true Rubik's Cube solving algorithm in the current code
- automated tests are not yet in place
- the production bundle is relatively large
If you want to turn this into a true state-based solver, the logical starting points are src/utils/cubeLogic.js and src/hooks/useCubeState.js.

