{"id":17018265,"url":"https://github.com/zlatnaspirala/matrix-engine-wgpu","last_synced_at":"2025-08-27T22:32:33.960Z","repository":{"id":225417881,"uuid":"765774480","full_name":"zlatnaspirala/matrix-engine-wgpu","owner":"zlatnaspirala","description":"webGpu powered pwa application. Crazy fast rendering solution. Scene object based.","archived":false,"fork":false,"pushed_at":"2025-08-26T18:32:45.000Z","size":25874,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-26T21:17:50.832Z","etag":null,"topics":["3d-web","matrix-engine","webgpu","webgpu-api","webgpu-engine","yahtzee-game"],"latest_commit_sha":null,"homepage":"https://maximumroulette.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zlatnaspirala.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-01T15:36:50.000Z","updated_at":"2025-08-22T14:26:10.000Z","dependencies_parsed_at":"2025-07-05T00:23:55.752Z","dependency_job_id":"d4d68d9f-2658-4b84-81be-623bb241447a","html_url":"https://github.com/zlatnaspirala/matrix-engine-wgpu","commit_stats":null,"previous_names":["zlatnaspirala/matrix-engine-wgpu"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zlatnaspirala/matrix-engine-wgpu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zlatnaspirala%2Fmatrix-engine-wgpu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zlatnaspirala%2Fmatrix-engine-wgpu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zlatnaspirala%2Fmatrix-engine-wgpu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zlatnaspirala%2Fmatrix-engine-wgpu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zlatnaspirala","download_url":"https://codeload.github.com/zlatnaspirala/matrix-engine-wgpu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zlatnaspirala%2Fmatrix-engine-wgpu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272389719,"owners_count":24926336,"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","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["3d-web","matrix-engine","webgpu","webgpu-api","webgpu-engine","yahtzee-game"],"created_at":"2024-10-14T06:45:15.144Z","updated_at":"2025-08-27T22:32:33.944Z","avatar_url":"https://github.com/zlatnaspirala.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# matrix-engine-wgpu\n\n**Author:** Nikola Lukić\n📧 [zlatnaspirala@gmail.com](mailto:zlatnaspirala@gmail.com)\n📅 2025\n\n---\n\n## Logo\n\n\u003cimg width=\"320\" height=\"320\" src=\"https://github.com/zlatnaspirala/matrix-engine-wgpu/blob/main/public/res/icons/512.png?raw=true\" /\u003e\n\n\u003e Logo includes the official WebGPU logo.\n\u003e **WebGPU logo by [W3C](https://www.w3.org/)**\n\u003e Licensed under [Creative Commons Attribution 4.0](https://www.w3.org/2023/02/webgpu-logos.html)\n\n---\n\n## Description\n\nThis project is a work-in-progress WebGPU engine inspired by the original **matrix-engine** for WebGL.\nIt uses the `wgpu-matrix` npm package as a modern replacement for `gl-matrix` to handle model-view-projection matrices.\n\nPublished on npm as: **`matrix-engine-wgpu`**\n\n---\n\n## Goals\n\n- ✔️ Support for 3D objects and scene transformations\n- 🎯 Replicate matrix-engine (WebGL) features\n- 📦 Based on the `shadowMapping` sample from [webgpu-samples](https://webgpu.github.io/webgpu-samples/?sample=shadowMapping)\n- ✔️ Ammo.js physics integration (basic cube)\n\n---\n\n## Features\n\n### Scene Management\n\n- Canvas is dynamically created in JavaScript—no `\u003ccanvas\u003e` element needed in HTML.\n\n- Access the main scene objects:\n\n  ```js\n  app.mainRenderBundle[0];\n  ```\n or\n  ```js\n  app.getSceneObjectByName(\"Sphere1\");\n  ```\n\n- Add meshes with `.addMeshObj()`, supporting `.obj` loading, unlit textures, cubes, spheres, etc.\n\n- Cleanly destroy the scene:\n\n  ```js\n  app.destroyProgram();\n  ```\n\n---\n\n### Camera Options\n\nSupported types: `WASD`, `arcball`\n\n```js\nmainCameraParams: {\n  type: 'WASD',\n  responseCoef: 1000\n}\n```\n\n---\n\n### Object Position\n\nBest way for access physics body object:\napp.matrixAmmo.getBodyByName(name)\nalso app.matrixAmmo.getNameByBody\n\nControl object position:\n\n```js\napp.mainRenderBundle[0].position.translateByX(12);\n```\n\nTeleport / set directly:\n\n```js\napp.mainRenderBundle[0].position.SetX(-2);\n```\n\nAdjust movement speed:\n\n```js\napp.mainRenderBundle[0].position.thrust = 0.1;\n```\n\n\u003e ⚠️ For physics-enabled objects, use Ammo.js functions — `.position` and `.rotation` are not visually applied but can be read.\n\nExample:\n\n```js\napp.matrixAmmo.rigidBodies[0].setAngularVelocity(new Ammo.btVector3(0, 2, 0));\napp.matrixAmmo.rigidBodies[0].setLinearVelocity(new Ammo.btVector3(0, 7, 0));\n```\n\n---\n\n### Object Rotation\n\nManual rotation:\n\n```js\napp.mainRenderBundle[0].rotation.x = 45;\n```\n\nAuto-rotate:\n\n```js\napp.mainRenderBundle[0].rotation.rotationSpeed.y = 10;\n```\n\nStop rotation:\n\n```js\napp.mainRenderBundle[0].rotation.rotationSpeed.y = 0;\n```\n\n\u003e ⚠️ For physics-enabled objects, use Ammo.js methods (e.g., `.setLinearVelocity()`).\n\n---\n\n### 3D Camera Example\n\nManipulate WASD camera:\n\n```js\napp.cameras.WASD.pitch = 0.2;\n```\n\n---\n\n💡 Lighting System\n\nMatrix Engine WGPU now supports independent light entities, meaning lights are no longer tied to the camera. You can freely place and configure lights in the scene, and they will affect objects based on their type and parameters.\n\nSupported Light Types\n\nSpotLight – Emits light in a cone shape with configurable cutoff angles.\n\n(Planned: PointLight, DirectionalLight, AmbientLight)\n\nFeatures\n\n✅ Supports multiple lights (20 max)\n✅ Shadow-ready (spotlight0 shadows implemented, extendable to others)\n\nengine.addLight()\nafter explore light props.\n\n\n### Object Interaction (Raycasting)\n\nThe raycast returns:\n\n```js\n{\n  rayOrigin: [x, y, z],\n  rayDirection: [x, y, z] // normalized\n}\n```\n\nManual raycast example:\n\n```js\nwindow.addEventListener(\"click\", event =\u003e {\n  let canvas = document.querySelector(\"canvas\");\n  let camera = app.cameras.WASD;\n  const {rayOrigin, rayDirection} = getRayFromMouse(event, canvas, camera);\n\n  for (const object of app.mainRenderBundle) {\n    if (\n      rayIntersectsSphere(\n        rayOrigin,\n        rayDirection,\n        object.position,\n        object.raycast.radius\n      )\n    ) {\n      console.log(\"Object clicked:\", object.name);\n    }\n  }\n});\n```\n\nAutomatic raycast listener:\n\n```js\naddRaycastListener();\n\nwindow.addEventListener(\"ray.hit.event\", event =\u003e {\n  console.log(\"Ray hit:\", event.detail.hitObject);\n});\n```\n\nEngine also exports (box):\n\n- addRaycastsAABBListener\n- rayIntersectsAABB,\n- computeAABB,\n- computeWorldVertsAndAABB,\n\n---\n\n### How to Load `.obj` Models\n\n```js\nimport MatrixEngineWGPU from \"./src/world.js\";\nimport {downloadMeshes} from \"./src/engine/loader-obj.js\";\n\nexport let application = new MatrixEngineWGPU(\n  {\n    useSingleRenderPass: true,\n    canvasSize: \"fullscreen\",\n    mainCameraParams: {\n      type: \"WASD\",\n      responseCoef: 1000,\n    },\n  },\n  () =\u003e {\n    addEventListener(\"AmmoReady\", () =\u003e {\n      downloadMeshes(\n        {\n          welcomeText: \"./res/meshes/blender/piramyd.obj\",\n          armor: \"./res/meshes/obj/armor.obj\",\n          sphere: \"./res/meshes/blender/sphere.obj\",\n          cube: \"./res/meshes/blender/cube.obj\",\n        },\n        onLoadObj\n      );\n    });\n\n    function onLoadObj(meshes) {\n      application.myLoadedMeshes = meshes;\n      for (const key in meshes) {\n        console.log(`%c Loaded obj: ${key} `, LOG_MATRIX);\n      }\n\n      application.addMeshObj({\n        position: {x: 0, y: 2, z: -10},\n        rotation: {x: 0, y: 0, z: 0},\n        rotationSpeed: {x: 0, y: 0, z: 0},\n        texturesPaths: [\"./res/meshes/blender/cube.png\"],\n        name: \"CubePhysics\",\n        mesh: meshes.cube,\n        physics: {\n          enabled: true,\n          geometry: \"Cube\",\n        },\n      });\n\n      application.addMeshObj({\n        position: {x: 0, y: 2, z: -10},\n        rotation: {x: 0, y: 0, z: 0},\n        rotationSpeed: {x: 0, y: 0, z: 0},\n        texturesPaths: [\"./res/meshes/blender/cube.png\"],\n        name: \"SpherePhysics\",\n        mesh: meshes.sphere,\n        physics: {\n          enabled: true,\n          geometry: \"Sphere\",\n        },\n      });\n    }\n  }\n);\n\nwindow.app = application;\n```\n\n### 🔁 Load OBJ Sequence Animation\n\nThis example shows how to load and animate a sequence of .obj files to simulate mesh-based animation (e.g. walking character).\n\n```js\nimport MatrixEngineWGPU from \"../src/world.js\";\nimport { downloadMeshes, makeObjSeqArg } from \"../src/engine/loader-obj.js\";\nimport { LOG_MATRIX } from \"../src/engine/utils.js\";\n\nexport var loadObjsSequence = function () {\n  let loadObjFile = new MatrixEngineWGPU({\n    useSingleRenderPass: true,\n    canvasSize: \"fullscreen\",\n    mainCameraParams: {\n      type: \"WASD\",\n      responseCoef: 1000,\n    },\n  }, () =\u003e {\n\n    addEventListener(\"AmmoReady\", () =\u003e {\n      downloadMeshes(\n        makeObjSeqArg({\n          id: \"swat-walk-pistol\",\n          path: \"res/meshes/objs-sequence/swat-walk-pistol\",\n          from: 1,\n          to: 20,\n        }),\n        onLoadObj,\n        { scale: [10, 10, 10] }\n      );\n    });\n\n    function onLoadObj(m) {\n      console.log(`%c Loaded objs: ${m} `, LOG_MATRIX);\n      var objAnim = {\n        id: \"swat-walk-pistol\",\n        meshList: m,\n        currentAni: 1,\n        animations: {\n          active: \"walk\",\n          walk: { from: 1, to: 20, speed: 3 },\n          walkPistol: { from: 36, to: 60, speed: 3 },\n        },\n      };\n\n      loadObjFile.addMeshObj({\n        position: { x: 0, y: 2, z: -10 },\n        rotation: { x: 0, y: 0, z: 0 },\n        rotationSpeed: { x: 0, y: 0, z: 0 },\n        scale: [100, 100, 100],\n        texturesPaths: [\"./res/meshes/blender/cube.png\"],\n        name: \"swat\",\n        mesh: m[\"swat-walk-pistol\"],\n        physics: {\n          enabled: false,\n          geometry: \"Cube\",\n        },\n        objAnim: objAnim,\n      });\n\n      app.mainRenderBundle[0].objAnim.play(\"walk\");\n    }\n  });\n\n  window.app = loadObjFile;\n};\n```\n\n### 📽️ Video textures\n\n```js\nTEST.loadVideoTexture({\n  type: 'video', // video , camera  //not tested yet canvas2d , canvas2dinline\n  src: 'res/videos/tunel.mp4'\n});\n```\n\nFor canvasinline attach this to arg (example for direct draw on canvas2d and passing intro webgpu pipeline):\n```js\ncanvaInlineProgram: (ctx, canvas) =\u003e {\n  ctx.fillStyle = 'black';\n  ctx.fillRect(0, 0, canvas.width, canvas.height);\n  ctx.fillStyle = 'white';\n  ctx.font = '20px Orbitron';\n  ctx.fillText(`FPS: ${Math.round(performance.now() % 60)}`, 10, 30);\n}\n```\n\n\n\u003cpre\u003e\n| Scenario                       | Best Approach                      |\n| ------------------------------ | ---------------------------------- |\n| Dynamic 2D canvas animation    | `canvas.captureStream()` → `video` |\n| Static canvas snapshot         | `createImageBitmap(canvas)`        |\n| Replaying real video or webcam | Direct `video` element             |\n\u003c/pre\u003e\n\n### Note\nIf this happen less then 15 times (Loading procces) then it is ok probably...\n\n```json\nDraw func (err):TypeError: Failed to execute 'beginRenderPass' on 'GPUCommandEncoder': The provided value is not of type 'GPURenderPassDescriptor'.\n```\n\n## About URLParams\n\nBuildin Url Param check for multiLang.\n\n```js\nurlQuery.lang;\n```\n\n---\n\n## About `main.js`\n\n`main.js` is the main instance for the Ultimate Yahtzee game template.\nIt contains the game context, e.g., `dices`.\n\nFor a clean startup without extra logic, use `empty.js`.\nThis minimal build is ideal for online editors like CodePen or StackOverflow snippets.\n\n---\n\n## NPM Scripts\n\nUses `watchify` to bundle JavaScript.\n\n```json\n\"main-worker\": \"watchify app-worker.js -p [esmify --noImplicitAny] -o public/app-worker.js\",\n\"examples\": \"watchify examples.js -p [esmify --noImplicitAny] -o public/examples.js\",\n\"main\": \"watchify main.js -p [esmify --noImplicitAny] -o public/app.js\",\n\"empty\": \"watchify empty.js -p [esmify --noImplicitAny] -o public/empty.js\",\n\"build-all\": \"npm run main-worker \u0026\u0026 npm run examples \u0026\u0026 npm run main \u0026\u0026 npm run build-empty\"\n```\n\n---\n\n## Resources\n\nAll resources and output go into the `./public` folder — everything you need in one place.\nThis is static file storage.\n\n---\n\n## Proof of Concept\n\n🎲 The first full app example will be a WebGPU-powered **Ultimate Yahtzee** game.\n\n---\n\n## Live Demos \u0026 Dev Links\n\n- [Jamb WebGPU Demo (WIP)](https://maximumroulette.com/apps/webgpu/)\n- [CodePen Demo](https://codepen.io/zlatnaspirala/pen/VwNKMar?editors=0011)\n  → Uses `empty.js` build from:\n  [https://maximumroulette.com/apps/megpu/empty.js](https://maximumroulette.com/apps/megpu/empty.js)\n- [CodeSandbox Implementation](https://codesandbox.io/p/github/zlatnaspirala/matrix-engine-wgpu/main?file=%2Fpackage.json%3A14%2C16)\n- 📘 Learning Resource: [WebGPU Ray Tracing](https://maierfelix.github.io/2020-01-13-webgpu-ray-tracing/)\n\n---\n\n## License\n\n### Usage Note\n\nYou may use, modify, and sell projects based on this code — just keep this notice and included references intact.\n\n---\n\n### Attribution \u0026 Credits\n\n- Engine design and scene structure inspired by:\n  [WebGPU Samples](https://webgpu.github.io/webgpu-samples/?sample=shadowMapping)\n- OBJ Loader adapted from:\n  [http://math.hws.edu/graphicsbook/source/webgl/cube-camera.html](http://math.hws.edu/graphicsbook/source/webgl/cube-camera.html)\n- Dice roll sound `roll1.wav` sourced from:\n  [https://wavbvkery.com/dice-rolling-sound/](https://wavbvkery.com/dice-rolling-sound/)\n- Raycasting logic assisted by ChatGPT\n\n---\n\n### BSD 3-Clause License (from WebGPU Samples)\n\n[Full License Text](https://github.com/webgpu/webgpu-samples/blob/main/LICENSE.txt)\n\nTop level main.js instance (Ultimate Yahtzee)\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzlatnaspirala%2Fmatrix-engine-wgpu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzlatnaspirala%2Fmatrix-engine-wgpu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzlatnaspirala%2Fmatrix-engine-wgpu/lists"}