{"id":20662379,"url":"https://github.com/evanzhoudev/cubekit","last_synced_at":"2025-07-12T08:08:18.439Z","repository":{"id":64884874,"uuid":"519883691","full_name":"EvanZhouDev/cubekit","owner":"EvanZhouDev","description":null,"archived":false,"fork":false,"pushed_at":"2022-12-23T04:37:08.000Z","size":105,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-10T05:54:51.405Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EvanZhouDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-31T20:46:35.000Z","updated_at":"2022-12-16T23:53:02.000Z","dependencies_parsed_at":"2023-01-30T17:35:12.380Z","dependency_job_id":null,"html_url":"https://github.com/EvanZhouDev/cubekit","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/EvanZhouDev/cubekit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvanZhouDev%2Fcubekit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvanZhouDev%2Fcubekit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvanZhouDev%2Fcubekit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvanZhouDev%2Fcubekit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EvanZhouDev","download_url":"https://codeload.github.com/EvanZhouDev/cubekit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvanZhouDev%2Fcubekit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264958623,"owners_count":23689035,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T19:13:58.234Z","updated_at":"2025-07-12T08:08:18.420Z","avatar_url":"https://github.com/EvanZhouDev.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CubeKit\n\nA Simple Next-Gen Rubik's Cube Simulator\n\n## Why?\n\nAs a speedcubing enthusiast and programmer, I realized that I could give the programming community a Javascript-based Rubik's Cube simulator that could do whatever I wanted it to quickly and easily.\n\n## Installation\n\nInstallation is very simple. Simply `cd` into your chosen directory and run this command:\n\n```bash\nnpm install cubekit\n```\n\nBecause of the way NPM is structured, cubekit uses CJS module declarations.\n\nAs simple as that! Cubekit is ready to use!\n\n## Usage\n\nCubekit is centralized on simplicity and modularity. You can import everything you need and not bother with everything else. There are two main classes: `Cube` and `Parser`\n\n## Structure\n\nCubekit is built on a vector and rotation-matrix model of a Rubik's Cube. This idea is originally from [user156217 on Stack Exchange](https://softwareengineering.stackexchange.com/a/262847https:/).\n\nHere's how it works.\n\t\n### The position vector\n  The Cube class is composed of different pieces, each with a position vector. In theory, it would be ideal to represent the position $\\vec{l}$ as a column matrix, as follows:\n\t\n```math\n\\vec{l} = \\begin{bmatrix}\nx\\\\\ny\\\\\nz\n\\end{bmatrix}\n```\nHowever, because expressing column matricies in code is tedious (To access, say, y in `let l = [[x],[y],[z]]`, you need to write `l[1][0]`), I actually represent our vector as a row matrix. We transpose the matrix into a column, do operations, and transpose back to a row when I need to operate on the \"column.\"\n\n### The rotation matricies\nBy multiplying each vector by a [rotation matrix](https://en.wikipedia.org/wiki/Rotation_matrix), we are able to \"turn\" the piece. The 3D rotation matricies used are as follows:\n\t\n```math\nR_x(\\theta) = \\begin{bmatrix}\n1 \u0026 0 \u0026 0\\\\\n0 \u0026 \\cos(\\theta) \u0026 -\\sin(\\theta)\\\\\n0 \u0026 \\sin(\\theta) \u0026 \\cos(\\theta)\n\\end{bmatrix}\n```\n\n```math\nR_y(\\theta) = \\begin{bmatrix}\n\\cos(\\theta) \u0026 0 \u0026 \\sin(\\theta)\\\\\n0 \u0026 1 \u0026 0\\\\\n-\\sin(\\theta) \u0026 0 \u0026 \\cos(\\theta)\n\\end{bmatrix}\n```\n\n```math\nR_z(\\theta) = \\begin{bmatrix}\n\\cos(\\theta) \u0026 -\\sin(\\theta) \u0026 0\\\\\n\\sin(\\theta) \u0026 \\cos(\\theta) \u0026 0\\\\\n0 \u0026 0 \u0026 1\n\\end{bmatrix}\n```\nBy multiplying these matricies onto our position vector, we are able \"turn\" our piece!\n\t\n```math\n(R_x(\\theta)\\cdot\\vec{l}^\\intercal)^\\intercal = (\\begin{bmatrix}\n1 \u0026 0 \u0026 0\\\\\n0 \u0026 \\cos(\\theta) \u0026 -\\sin(\\theta)\\\\\n0 \u0026 \\sin(\\theta) \u0026 \\cos(\\theta)\n\\end{bmatrix}\\cdot\\begin{bmatrix}\nx \u0026 y \u0026 z\n\\end{bmatrix}^\\intercal)^\\intercal\n```\n\n### Moving the \"stickers\"\nOther than just the actual position of the piece, the \"stickers\" also move. We can simply keep track of all the colors using a simply array. We can let the first index be the x colors, second index the y colors, and the third index the z colors. It would look something like this: `this.colors=[cx, cy, cz]`. In order to turn it properly, the following things have to occur:\n- When turning the x axis by 90°, swap the y and z colors\n- When turning the y axis by 90°, swap the x and z colors\n- When turning the z axis by 90°, swap the x and y colors\n\u003cbr/\u003e\nAnd there we have it! All our pieces now have their own \"turning\" logic built in!\n\n### Performing a layer turn\nCurrently, all our pieces have their own rotation logic. However, what if we want to perform an actual turn? Well, its really quite simple. For example, if we want to perform an \"R\" turn, all we have to do is select all of the pieces with an x equal to 1, and rotate those pieces along the x axis by 90°. On the inside, each one of the `cube.R()` function calls look like this:\n\t\n```javascript\nCube.turn(\n\t(x) =\u003e x === 1,\n\t(y) =\u003e y !== undefined,\n\t(z) =\u003e z !== undefined,\n\t\"x\",\n\tMath.PI/2\n)\n```\nThe first three parameters look at the conditions of what each one of the x, y, and z parameters need to be to do this turn. The 4th parameter tells the function what axis to turn it on, and the last one is simply the angle to turn it, in radians. You can actually use the ```Cube.turn()``` function, as it is public!\n\n### Conclusion\nWhile this algorithm is very programatically simple, there is a good bit of math behind it. However, one of the cons is that searching for a particular piece may be slower than usual. Nonetheless, it is a very elegant approach!\n\t\n## Cube\n\nThis is where the main magic happens. Simply declare a new cube, initialize, and you're all set up.\n\n```javascript\nlet { Cube, StandardMoves, WesternColors } = require(\"cubekit\");\nlet myCube = new Cube(StandardMoves);\nmyCube.init(WesternColors);\n```\n\nLet's break down the things that are going on here:\n\n### Color Schemes\n\nBecause the Rubik's cube doesn't necessarily have a \"definite\" color scheme (even though most manufacturers use the Western Color scheme), Cubekit supports custom color scheme support.\nThe predefined colors are:\n\n- `WesternColors`\n- `JapaneseColors`\n  You can also define your own colors:\n\n```javascript\nconst MyAmazingColors = {\n\tx: [\"R\", \"B\"], // Negative x, positive x\n\ty: [\"W\", \"Y\"], // Negative y, positive y\n\tz: [\"L\", \"M\"], // Negative z, positive z\n};\n```\n\nIn theory, what you put in each individual string doesn't matter. I recommend a single letter that represents something.\n\nThe positive x axis is pointing towards you. The positive z axis is pointing towards your right. The positive y axis is pointing upwards.\n\n### Importing Moves\n\nYou may notice that we are also using something called `StandardMoves`. Beacuse of the modular structure, you only import what you need. Cubekit currently supports\n\n- `StandardMoves` (R, L, U, D, F, B, and all of their double and inverse moves)\n- `WideMoves` (Rw, Lw, Uw, Dw, Fw, Bw, and all of their double and inverse moves)\n- `WideMovesUNSAFE` (r, l, u, d, f, b, and all of their double and inverse moves)\n  - We do not recommend this one, as the lowercase letters may be confusing\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanzhoudev%2Fcubekit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevanzhoudev%2Fcubekit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevanzhoudev%2Fcubekit/lists"}