{"id":20433720,"url":"https://github.com/andygura/gg-web-engine","last_synced_at":"2025-07-20T17:34:52.650Z","repository":{"id":65617461,"uuid":"542475277","full_name":"AndyGura/gg-web-engine","owner":"AndyGura","description":"An attempt to create open source game engine for browser","archived":false,"fork":false,"pushed_at":"2025-05-29T16:54:24.000Z","size":58317,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-05T04:09:49.564Z","etag":null,"topics":["game-development","game-engine","game-engine-framework","gamedev"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndyGura.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":"2022-09-28T08:02:39.000Z","updated_at":"2025-05-25T22:26:19.000Z","dependencies_parsed_at":"2023-10-17T06:47:58.892Z","dependency_job_id":"d78b8310-f8cd-41a5-ad00-7ceb36e5f1dc","html_url":"https://github.com/AndyGura/gg-web-engine","commit_stats":{"total_commits":279,"total_committers":1,"mean_commits":279.0,"dds":0.0,"last_synced_commit":"32fc9db1e0fd690d183c506c00e0d2656620ff36"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/AndyGura/gg-web-engine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyGura%2Fgg-web-engine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyGura%2Fgg-web-engine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyGura%2Fgg-web-engine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyGura%2Fgg-web-engine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndyGura","download_url":"https://codeload.github.com/AndyGura/gg-web-engine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyGura%2Fgg-web-engine/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266166371,"owners_count":23886775,"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":["game-development","game-engine","game-engine-framework","gamedev"],"created_at":"2024-11-15T08:20:37.428Z","updated_at":"2025-07-20T17:34:52.644Z","avatar_url":"https://github.com/AndyGura.png","language":"TypeScript","funding_links":["https://www.buymeacoffee.com/andygura"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e🚀 GG-Web-Engine\u003c/h1\u003e\n\u003ch3 align=\"center\"\u003eA modular, open-source game engine for the web. Build stunning 2D/3D games and simulations with ease.\u003c/h3\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"documentation/assets/logo.png\" style=\"height: 360px; width:360px;\" alt=''/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#-about\"\u003eAbout\u003c/a\u003e •\n  \u003ca href=\"#-key-features\"\u003eKey Features\u003c/a\u003e •\n  \u003ca href=\"#-vision\"\u003eVision\u003c/a\u003e •\n  \u003ca href=\"#-current-status\"\u003eCurrent Status\u003c/a\u003e •\n  \u003ca href=\"#-integrations\"\u003eIntegrations\u003c/a\u003e •\n  \u003ca href=\"#-quickstart\"\u003eQuickstart\u003c/a\u003e •\n  \u003ca href=\"#%EF%B8%8F-examples\"\u003eExamples\u003c/a\u003e •\n  \u003ca href=\"#-documentation\"\u003eDocumentation\u003c/a\u003e •\n  \u003ca href=\"#-architecture\"\u003eArchitecture\u003c/a\u003e •\n  \u003ca href=\"#-faq\"\u003eFAQ\u003c/a\u003e •\n  \u003ca href=\"#-support\"\u003eSupport\u003c/a\u003e •\n  \u003ca href=\"#-license\"\u003eLicense\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## 🎨 About\nGG-Web-Engine is an open-source framework designed to accelerate the development of web-based 2D/3D applications,\nincluding games and simulations. Instead of reinventing the wheel, it integrates seamlessly with powerful libraries\nlike Three.js for rendering and Ammo.js for physics, giving developers complete control over these tools.\n\nBuilt with flexibility in mind, the engine is designed to work with various tech stacks and allows swapping libraries or\ncreating custom solutions with minimal effort.\n\n## 🌟 Key Features\n- Multi-library Integration: Supports rendering and physics libraries like Three.js, Ammo.js, Pixi.js, Matter.js, and more.\n- 2D \u0026 3D Support: Build both 2D and 3D worlds effortlessly.\n- Ready-to-use Tools: Includes core functionalities like rendering loops, physics ticks, input handling, and more.\n- Serialization \u0026 Export: Built-in Blender exporter for 3D geometry and physics properties.\n- Entity System: Modular design with reusable entities for rendering, physics, cameras, vehicles, and more.\n- Extensible Architecture: Easily integrate or replace components with custom implementations.\n- Modern Tech Stack: Written in TypeScript with RxJS for reactive programming.\n\n## 🔭 Vision\n- Provide seamless integrations for existing rendering, physics, and sound libraries.\n- Deliver a robust foundation for both 2D and 3D game worlds.\n- Empower developers with tools like developer console, cameras, and debug utilities.\n- Maintain modularity to ensure maximum flexibility for developers.\n- Stay library-agnostic, enabling developers to switch or customize libraries with ease.\n\n## 🚧 Current Status\n### **\u003cspan style=\"color:red\"\u003eExperimental Release**\u003c/span\u003e\n\nThis engine began as part of a project to recreate an old NFS game\n[The Need For Speed Web](https://tnfsw.guraklgames.com/). Its modular architecture was inspired by the challenges of\nswitching from Cannon.js to Ammo.js and, eventually, to custom reverse-engineered physics engine with minimal changes.\n\nWhile the current focus is on racing game features and 3D worlds, future updates will expand the engine's versatility. Contributions, feature requests, and bug reports are warmly welcomed!\n\n## ✨ Features at a Glance\n- Physics/Rendering Synchronization: Automates position/rotation updates.\n- Customizable Controllers: Add functionality with reusable tick-based controllers.\n- Entities: Predefined entities like rigid bodies, triggers, raycast vehicles, and more.\n- Developer Console: Built-in UI console for debugging and tweaking settings.\n- Map Graph Loading: Load map areas dynamically based on proximity (3D worlds).\n- Free-Fly Camera: Explore 3D worlds effortlessly.\n\n## 🔌 Integrations\n\u003e Note: Current integrations are in early stages and will become more flexible in future releases.\n\n- [**@gg-web-engine/three**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/three/README.md) - 3D rendering ([Three.js](https://github.com/mrdoob/three.js))\n- [**@gg-web-engine/ammo**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/ammo/README.md) - 3D physics ([Ammo.js](https://github.com/kripken/ammo.js))\n- [**@gg-web-engine/rapier3d**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/rapier3d/README.md) - 3D physics ([Rapier.js](https://github.com/dimforge/rapier.js))\n- [**@gg-web-engine/pixi**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/pixi/README.md) - 2D rendering ([Pixi.js](https://github.com/pixijs/pixijs))\n- [**@gg-web-engine/matter**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/matter/README.md) - 2D physics ([Matter.js](https://github.com/liabru/matter-js))\n- [**@gg-web-engine/rapier2d**](https://github.com/AndyGura/gg-web-engine/tree/main/packages/rapier2d/README.md) - 2D physics ([Rapier.js](https://github.com/dimforge/rapier.js))\n\n## ⚡ Quickstart\n### Installation\n1) Install the core package:\n```bash\nnpm install --save @gg-web-engine/core\n```\n2) Install integration modules. For example, to use Three.js and Ammo.js:\n```bash\nnpm install --save @gg-web-engine/three @gg-web-engine/ammo\n```\n\n### Usage:\n1) add somewhere in dom tree: ```\u003ccanvas id=\"gg\"\u003e\u003c/canvas\u003e```\n1) remove default margin from page via CSS: ```body { margin: 0; }```\n1) write bootstrap script, example:\n```typescript\nimport { Gg3dWorld, Pnt3, Qtrn } from '@gg-web-engine/core';\nimport { ThreeSceneComponent } from '@gg-web-engine/three';\nimport { AmmoWorldComponent } from '@gg-web-engine/ammo';\n\n// create world\nconst world = new Gg3dWorld({\n  visualScene: new ThreeSceneComponent(),\n  physicsWorld: new AmmoWorldComponent(),\n});\nawait world.init();\n\n// create viewport and renderer\nconst renderer = world.addRenderer(\n  world.visualScene.factory.createPerspectiveCamera(),\n  document.getElementById('gg')! as HTMLCanvasElement\n);\nrenderer.position = { x: 12, y: 12, z: 12 };\nrenderer.rotation = Qtrn.lookAt(renderer.camera.position, Pnt3.O);\n\n// create floor (static rigid body)\nworld.addPrimitiveRigidBody({\n  shape: { shape: 'BOX', dimensions: { x: 7, y: 7, z: 1 } },\n  body: { dynamic: false },\n});\n\n// spawn cubes with mass 1kg twice a second\nconst spawnTimer = world.createClock(true);\nspawnTimer.tickRateLimit = 2;\nspawnTimer.tick$.subscribe(() =\u003e {\n  // generate cube\n  let item = world.addPrimitiveRigidBody({\n    shape: { shape: 'BOX', dimensions: { x: 1, y: 1, z: 1 } },\n    body: { mass: 1 },\n  });\n  // set position to cube\n  item.position = { x: Math.random() * 5 - 2.5, y: Math.random() * 5 - 2.5, z: 10 };\n  // delete cube from world after 30 seconds\n  setTimeout(() =\u003e { world.removeEntity(item, true); }, 30000);\n});\n\n// start simulation\nworld.start();\n```\nAnd run it:\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"documentation/assets/example.gif\" alt=''/\u003e\n\u003c/p\u003e\n\n## 🛠️ Examples\n### [Interactive Demos](https://gg-web-demos.guraklgames.com/)\n### Framework Usage\n- #### Angular: [Example Project](https://stackblitz.com/github/AndyGura/gg-web-engine/tree/main/examples/framework-angular-three-ammo?file=src%2Fmain.ts)\n- #### React: [Example Project](https://stackblitz.com/github/AndyGura/gg-web-engine/tree/main/examples/framework-react-three-rapier3d?file=src%2FApp.tsx)\n\n## 📚 Documentation\nExplore the complete technical documentation: [GitHub Pages](https://andygura.github.io/gg-web-engine/).\n\n## 🌌 Architecture\nThe most important thing in the engine is [GgWorld](https://andygura.github.io/gg-web-engine/modules/core/base/gg-world.ts/).\nIt encapsulates everything you need in your game runtime: ticker clock, visual scene, physics simulation world etc.\nOne browser tab can run one or many GG worlds. In order to add something to the world, caller code needs to add\n[Entities](https://andygura.github.io/gg-web-engine/modules/core/base/entities/i-entity.ts/). Entity is anything which\nworks in the world: tick-based controller, rigid body, renderer etc. World and entity are self-sufficient in gg core\npackage, so they do not depend on selected integration library. Entity can use from 0 to many\n[World Components](https://andygura.github.io/gg-web-engine/modules/core/base/components/i-world-component.ts/#i-world-component-overview) -\nthose are fully dependent on integration library, so libraries in general case only implement components.\n\nFull technical documentation available at [GitHub Pages](https://andygura.github.io/gg-web-engine/)\n\n### Clock\nClock is an entity, responsible for tracking time and firing ticks. It measures time and on each tick emits two numbers:\n`elapsedTime` and `delta`, where `delta` always equals to difference between current elapsed time, and elapsed time,\nfired on the previous tick. All clock instances have hierarchy: pausing clock will automatically pause all of its child\nclocks, which is nice to use for in-game timers: all timers will be paused when world clock is paused. There are two\nbuilt-in implementations of clock:\n#### [GgGlobalClock](https://andygura.github.io/gg-web-engine/modules/core/base/clock/global-clock.ts/)\nSingleton, starts emitting ticks as soon as accessed. For scheduling ticks, it uses `requestAnimationFrame` API.\nThe elapsed time for each tick is a timestamp, e.g. total amount of milliseconds, passed from\n01.01.1970 00:00:00.000 UTC. The instance of this clock is always the root clock in clocks hierarchy\n#### [PausableClock](https://andygura.github.io/gg-web-engine/modules/core/base/clock/pausable-clock.ts/)\nThe class for all remaining clocks: it measures time elapsed when was started. Has the ability to be paused/resumed,\nand elapsed time will not be affected by pause: it will proceed from the same state it was paused. Every world has its\nown instance of PausableClock, where parent clock is **GgGlobalClock**\n#### Example of clocks hierarchy\n```mermaid\nflowchart LR\n  GgGlobalClock.instance --\u003e w1[world1 clock]\n  GgGlobalClock.instance --\u003e w2[world2 clock]\n  w1 --\u003e l1[Level clock]\n  l1 --\u003e l2[Some timer on level]\n```\n\n### [World](https://andygura.github.io/gg-web-engine/modules/core/base/gg-world.ts/)\nWorld is a container of all entities of your game, manages the entire flow. Though it is possible to have multiple\nworlds in one page, in most cases you only need one. World consists of:\n- clock\n- visual scene, containing everything related to rendering. This is a [component](https://andygura.github.io/gg-web-engine/modules/core/base/components/rendering/i-visual-scene.component.ts/),\n  which has to be implemented by integration library\n- physics world, containing everything related to physics simulation. This is a [component](https://andygura.github.io/gg-web-engine/modules/core/base/components/physics/i-physics-world.component.ts/#iphysicsworldcomponent-interface),\n  which has to be implemented by integration library\n- list of all spawned world entities, sorted by tick order, and API for spawning/removing them\n- logic to propagate clock ticks to every spawned active entity\n- keyboard input\n\nThere are two built-in variants of world implementation: **[Gg2dWorld](https://andygura.github.io/gg-web-engine/modules/core/2d/gg-2d-world.ts/)** and **[Gg3dWorld](https://andygura.github.io/gg-web-engine/modules/core/3d/gg-3d-world.ts/)**\n\nExample of hierarchy of entities of simple scene, which uses three.js + ammo.js:\n```mermaid\nflowchart TB\n  w{\"[CORE]\\n3D World\"} --\u003e cn0[\"[CORE]\\nsome controller\"]\n  w --\u003e rb0[\"[CORE]\\nrigid body entity\"]\n  w --\u003e rb1[\"[CORE]\\n3d model\"]\n  w --\u003e rb2[\"[CORE]\\ntrigger entity\"]\n  rb0 --\u003e c0(\"[THREE]\\nmesh component\")\n  rb0 --\u003e c1(\"[AMMO]\\nphysics body component\")\n  rb1 --\u003e c2(\"[THREE]\\nmesh component\")\n  rb2 --\u003e c3(\"[AMMO]\\nphysics body component\")\n```\n\n### [Component](https://andygura.github.io/gg-web-engine/modules/core/base/components/i-component.ts/#icomponent-interface)\nAnything, which has to be implemented in integration library:\n- **[IVisualScene2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/rendering/i-visual-scene-2d.component.ts/#ivisualscene2dcomponent-interface) / [IVisualScene3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/rendering/i-visual-scene-3d.component.ts/#ivisualscene3dcomponent-interface)** a wrapper around visual scene or display object container\n- **[IDisplayObject2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/rendering/i-display-object-2d.component.ts/#idisplayobject2dcomponent-interface) / [IDisplayObject3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/rendering/i-display-object-3d.component.ts/#idisplayobject3dcomponent-interface)** a wrapper around mesh or sprite\n- **[IRenderer2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/rendering/i-renderer-2d.component.ts/#irenderer2dcomponent-class) / [IRenderer3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/rendering/i-renderer-3d.component.ts/#irenderer3dcomponent-class)** a wrapper around renderer\n- **[IPhysicsWorld2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/physics/i-physics-world-2d.component.ts/#iphysicsworld2dcomponent-interface) / [IPhysicsWorld3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/physics/i-physics-world-3d.component.ts/#iphysicsworld3dcomponent-interface)** a wrapper around physics world\n- **[IRigidBody2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/physics/i-rigid-body-2d.component.ts/#irigidbody2dcomponent-interface) / [IRigidBody3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/physics/i-rigid-body-3d.component.ts/#irigidbody3dcomponent-interface)** a wrapper around rigid body\n- **[ITrigger2dComponent](https://andygura.github.io/gg-web-engine/modules/core/2d/components/physics/i-trigger-2d.component.ts/#itrigger2dcomponent-interface) / [ITrigger3dComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/physics/i-trigger-3d.component.ts/#itrigger3dcomponent-interface)** a wrapper around physics object, which only detects intersections with other physics objects\n- **[ICameraComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/rendering/i-camera.component.ts/#icameracomponent-interface)** a wrapper around camera (3D world)\n- **[IRaycastVehicleComponent](https://andygura.github.io/gg-web-engine/modules/core/3d/components/physics/i-raycast-vehicle.component.ts/#iraycastvehiclecomponent-interface)** raycast vehicle (3D world)\n\nFor instance, `@gg-web-engine/three` implements 4 components: `IVisualScene3d`, `IDisplayObject3d`, `IRenderer3d`, `ICamera`.\n\n### [Entity](https://andygura.github.io/gg-web-engine/modules/core/base/entities/i-entity.ts/)\nBasically, everything that listens ticks and can be added/removed from world. Built-in entities:\n- **[Entity2d](https://andygura.github.io/gg-web-engine/modules/core/2d/entities/entity-2d.ts/#entity2d-class)** / **[Entity3d](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/entity-3d.ts/#entity3d-class)** encapsulates display object (sprite or mesh respectively) and rigid body.\n  Synchronizes position/rotation each tick\n- **[Trigger2dEntity](https://andygura.github.io/gg-web-engine/modules/core/2d/entities/trigger-2d.entity.ts/#trigger2dentity-class)** / **[Trigger3dEntity](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/trigger-3d.entity.ts/#trigger3dentity-class)** has only physics body, but instead of participating in collisions, emits\n  events when some another positionable entity entered/left its area\n- **[InlineTickController](https://andygura.github.io/gg-web-engine/modules/core/base/entities/controllers/inline-controller.ts/#createinlinetickcontroller)** simple controller, which can be created and added to world using one line of code\n- **[Renderer](https://andygura.github.io/gg-web-engine/modules/core/base/entities/i-renderer.entity.ts/#irendererentity-class)** controller, which renders the scene and controls canvas size (if canvas provided). Makes canvas appearing fullscreen by default\n- **[AnimationMixer](https://andygura.github.io/gg-web-engine/modules/core/base/entities/controllers/animation-mixer.ts/#animationmixer-class)** controller, which mixes animations: use-case is if you have some animation function, and you need a\n  smooth transition to another animation function\n- **[Entity2dPositioningAnimator](https://andygura.github.io/gg-web-engine/modules/core/2d/entities/controllers/entity-2d-positioning.animator.ts/#entity2dpositioninganimator-class)** / **[Entity3dPositioningAnimator](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/controllers/animators/entity-3d-positioning.animator.ts/#entity3dpositioninganimator-class)** controllers extending **AnimationMixer**, which apply\n  position/rotation to positionable entity\n- **[Camera3dAnimator](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/controllers/animators/camera-3d.animator.ts/#camera3danimator-class)** dedicated **AnimationMixer** for perspective camera: translates camera, target, up, fov etc.\n- **[FreeCameraController](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/controllers/input/free-camera.controller.ts/#freecameracontroller-class)** a controller, allows to control camera with WASD + mouse\n- **[CarKeyboardHandlingController](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/controllers/input/car-keyboard-handling.controller.ts/#carkeyboardhandlingcontroller-class)** a controller allowing to control car with keyboard\n- **[MapGraph3dEntity](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/map-graph-3d.entity.ts/#mapgraph3dentity-class)** an entity, which loads parts of big map and disposes loaded map chunks, which are far away\n- **[RaycastVehicle3dEntity](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/raycast-vehicle-3d.entity.ts/#raycastvehicle3dentity-class)** a general entity with raycast vehicle. Encapsulates positioning binding for chassis and wheels meshes, provides simplified interface for applying engine or brake forces\n- **[GgCarEntity](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/gg-car/gg-car.entity.ts/#ggCarentity-class)** a more sophisticated 4-wheel car which simulates engine with torque table, gear box etc.\n- **[SurfaceFollowingEntity](https://andygura.github.io/gg-web-engine/modules/core/3d/entities/surface-following.entity.ts/#surfacefollowingentity-class)** An entity which simulates smooth surface collider, declared parametrically\n\n### [Input](https://andygura.github.io/gg-web-engine/modules/core/base/inputs/input.ts/)\nInput is a class, responsible for handling external actions, such as mouse move, key presses, gamepad interactions etc.\nWhen implementing multiplayer, it probably will be the best place to handle incoming data for reflecting it on the world\nstate. Input does not depend on ticks and is not a part of the world, it should be created and used by some controller\nentity, added to the world. All inputs extend abstract class Input\u003cTStartParams, TStartParams\u003e. Engine provides those\ninputs out-of-box:\n#### [KeyboardInput](https://andygura.github.io/gg-web-engine/modules/core/base/inputs/keyboard.input.ts/)\nThis input handles key presses, allows to setup key bindings: provides Observable\u003cboolean\u003e, which emits true on key down\nand false on key up. When binding many keys to the same functionality, will emit true when any of bound keys pressed,\nand false only when all bound keys released. Every world has its own instance of keyboard controller\n#### [MouseInput](https://andygura.github.io/gg-web-engine/modules/core/base/inputs/mouse.input.ts/)\nThis input handles mouse movements and provides an Observable, which emits how much mouse position changed after last\nevent. Supports pointer lock functionality\n#### [DirectionKeyboardInput](https://andygura.github.io/gg-web-engine/modules/core/base/inputs/direction.keyboard-input.ts/)\nA shortcut for implementing direction key bindings: WASD, arrows, or both at once. Provides observable with direction\n#### Example of input usage\n```mermaid\nflowchart LR\n  world --\u003e e1[Player Character]\n  world --\u003e e2[Player Controller]\n  world --\u003e e0[...other world entities]\n  e2 --Creates input, listens to events--\u003e DirectionKeyboardInput\n  e2 --Changes character state on tick--\u003e e1\n```\n\n### Factory\nThere is simple factory, allowing to easily create rigid bodies. See\n[2D](https://andygura.github.io/gg-web-engine/modules/core/2d/factories.ts/) and\n[3D](https://andygura.github.io/gg-web-engine/modules/core/3d/factories.ts/) factories\n\n### Loader\nCurrently, there is only one loader available, and only for 3D world. It uses own format of serializing blender scene:\n**.glb**+**.meta** files, where glb is a binary GLTF file, containing mesh+materials, and meta is a json file,\ncontaining evverything from blend file, not included in glb, such as empty objects; rigid bodies; splines. Right now it\nis on very early stage. The script to make glb+meta from blender file is here:\n[build_blender_scene.py](packages/core/blender_exporter/build_blender_scene.py)\n\n### Console\nEngine provides a simple console, which can be used at runtime (if enabled) by pressing \\`. Your game can\nprovide custom console commands using `GgStatic.instance.registerConsoleCommand` function.\n\n#### Default global console commands\n| Command       | Arguments           | Description                                                                                                                                                                                                             |\n|---------------|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `commands`    | -                   | Print all available commands. List includes global commands and commands, specific to currently selected world. Run \"world\" to check which world is currently selected and \"world {world_name}\" to select desired world |\n| `help`        | `string`            | Print doc string of provided command                                                                                                                                                                                    |\n| `worlds`      | -                   | Print all currently available worlds                                                                                                                                                                                    |\n| `world`       | `string?`           | Get name of selected world or select world by name. Use \"worlds\" to get list of currently available worlds                                                                                                              |\n| `stats_panel` | `0\\|1?`             | Turn on/off stats panel, skip argument to toggle value                                                                                                                                                                  |\n| `debug_panel` | `0\\|1?`             | Turn on/off debug panel, skip argument to toggle value                                                                                                                                                                  |\n| `bind_key`    | `string, ...string` | Bind a keyboard key by code to console command. Check key codes [here](https://www.toptal.com/developers/keycode). Use \"unbind_key\" command to unbind it                                                                |\n| `unbind_key`  | `string`            | Unbind a keyboard key from console command                                                                                                                                                                              |\n\n#### Default world-specific console commands\n| Command       | Arguments          | Description                                                                                                                                                                                                                                                   |\n|---------------|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `timescale`   | `float?`           | Get current time scale of selected world clock or set it. Default value is 1.0 (no time scale applied)                                                                                                                                                        |\n| `fps_limit`   | `int?`             | Get current tick rate limit of selected world clock or set it. 0 means no limit applied                                                                                                                                                                       |\n| `renderers`   | -                  | Print all renderers in selected world                                                                                                                                                                                                                         |\n| `debug_view`  | `0\\|1?, string?`   | Turn on/off physics debug view, skip first argument to toggle value. Second argument expects renderer name, if not provided first renderer will be picked. Use \"renderers\" to get list of renderers in the world                                              |\n| `performance` | `int?, avg\\|peak?` | Measure how much time was spent per entity in world. Arguments are samples amount (20 by default) and \"peak\" or \"avg\" choice, both arguments are optional. \"avg\" report sorts entities by average time consumed, \"peak\" records highest value for each entity |\n\n#### Default 2D world-specific console commands\n| Command   | Arguments        | Description                                                                                                                                         |\n|-----------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|\n| `gravity` | `?float, ?float` | Get or set 2D world gravity vector. 1 argument sets vector {x: 0, y: value}, 2 arguments sets the whole vector. Default value is \"9.82\" or \"0 9.82\" |\n\n#### Default 3D world-specific console commands\n| Command   | Arguments                | Description                                                                                                                                                  |\n|-----------|--------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `gravity` | `?float, ?float, ?float` | Get or set 3D world gravity vector. 1 argument sets vector {x: 0, y: 0, z: -value}, 3 arguments set the whole vector. Default value is \"9.82\" or \"0 0 -9.82\" |\n\n## ❓ FAQ\n### How to access integration module native objects?\n\nAll the component implementations have a reference to the native object. By convention field names are:\n- `nativeScene` for 3D visual world scene\n- `nativeContainer` for 2D visual world container\n- `nativeMesh` for 3D display object\n- `nativeSprite` for 2D display object\n- `nativeWorld` for 2D/3D physics world\n- `nativeBody` for 2D/3D physics bodies\n\nFor instance, `ThreeSceneComponent` has public field `nativeScene: THREE.Scene`\n\n### How to make TypeScript happy?\n\nEverything is strictly typed inside the engine and works abstractly regardless of plugged in integration module.\nHowever, it's not always possible for typescript to infer types which rely on the integration module that you're using.\nFor example:\n\n```typescript\nconst world = new Gg3dWorld({\n  visualScene: new ThreeSceneComponent(),\n  physicsWorld: new AmmoWorldComponent(),\n});\nconst box = world.addPrimitiveRigidBody(...);\n// this is ok\nbox.object3D.scale = { x: 2, y: 2, z: 2 };\n// this gives typescript error\nbox.object3D.nativeMesh.material = myThreeMaterial;\n```\n\nSolution:\n```typescript\nconst world : TypedGg3dWorld\u003cThreeGgWorld, AmmoGgWorld\u003e = new Gg3dWorld({\n  visualScene: new ThreeSceneComponent(),\n  physicsWorld: new AmmoWorldComponent(),\n});\nconst box = world.addPrimitiveRigidBody(...);\n// now this works\nbox.object3D.nativeMesh.material = myThreeMaterial;\n// and this works as well\nbox.objectBody.nativeBody.applyTorque(...);\n```\n\nAll the integration modules provide `[ModuleName]GgWorld` type, where typescript knows which implementation is used.\nYou can define `const world: ThreeGgWorld = new Gg3dWorld(...)` and TS would infer all types for visual features according\nto three-js integration module and use abstract types for physics features.\n\nType `TypedGg3dWorld` \"welds\" two separate world types together: first generic must have types for visual world, second for physics world.\n\n### Why is the viewport not centered or blurry on mobile/retina displays?\n\nAdd the following meta tag to your `\u003chead\u003e`:\n```html\n\u003cmeta name=\"viewport\" content=\"width=device-width, user-scalable=no, minimum-scale=1, maximum-scale=1\"\u003e\n```\n\n## 🤝 Support\nFeel free to dive into the code, contribute, or just have fun creating with GG-Web-Engine. Together, let’s shape the\nfuture of browser-based game development! 🎮\n\nYou can support project by:\n- giving any feedback, bug report, feature request to [Issues](https://github.com/AndyGura/gg-web-engine/issues)\n- fork \u0026 submit a [Pull Request](https://github.com/AndyGura/gg-web-engine/pulls)\n- [![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/andygura)\n\n## 📜 License\n[Apache License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandygura%2Fgg-web-engine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandygura%2Fgg-web-engine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandygura%2Fgg-web-engine/lists"}