├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── README.md ├── kartRacer ├── app.ts ├── assets.ts ├── billboard.ts ├── input.ts ├── kart.ts ├── menu.ts ├── multiplayer.ts └── track.ts ├── package-lock.json ├── package.json ├── public ├── environment │ └── environment.env ├── index.html ├── models │ ├── bomb │ │ ├── bomb.bin │ │ ├── bomb.gltf │ │ ├── bomb_skullbombMat_Normal.png │ │ ├── bomb_skullbombMat_ORM.png │ │ └── bomb_skullbombMat_basecolor.png │ ├── bumper │ │ ├── bumper.bin │ │ ├── bumper.gltf │ │ ├── bumper_image0.png │ │ ├── bumper_image1.png │ │ ├── bumper_image2.png │ │ └── bumper_image3.png │ ├── camp │ │ ├── campMesh.bin │ │ ├── campMesh.gltf │ │ └── camp_baseColor.png │ ├── evergreen2 │ │ ├── evergreen2.bin │ │ ├── evergreen2.gltf │ │ └── evergreen_baseColor.png │ ├── poison_cloud │ │ ├── poison_cloud.bin │ │ ├── poison_cloud.gltf │ │ ├── poison_cloud_image0.png │ │ ├── poison_cloud_image1.png │ │ ├── poison_cloud_image2.png │ │ └── poison_cloud_image3.png │ ├── roadsterKart │ │ ├── driverBodyMat_ORM1.png │ │ ├── driverBodyMat_ORM2.png │ │ ├── driverBodyMat_ORM3.png │ │ ├── driverBodyMat_baseColor1.png │ │ ├── driverBodyMat_baseColor2.png │ │ ├── driverBodyMat_baseColor3.png │ │ ├── driverBodyMat_normal.png │ │ ├── engineWheels_roadsterWheelsMat_ORM.png │ │ ├── engineWheels_roadsterWheelsMat_basecolor.png │ │ ├── engineWheels_roadsterWheelsMat_normal.png │ │ ├── kartBodyMat_ORM1.png │ │ ├── kartBodyMat_ORM2.png │ │ ├── kartBodyMat_ORM3.png │ │ ├── kartBodyMat_baseColor1.png │ │ ├── kartBodyMat_baseColor2.png │ │ ├── kartBodyMat_baseColor3.png │ │ ├── kartBodyMat_normal.png │ │ ├── roadsterKart.bin │ │ └── roadsterKart.gltf │ ├── rocks │ │ ├── rock1.bin │ │ ├── rock1.gltf │ │ ├── rock2.bin │ │ ├── rock2.gltf │ │ ├── rock3.bin │ │ ├── rock3.gltf │ │ ├── rock4.bin │ │ ├── rock4.gltf │ │ └── rocks_baseColor.png │ └── wing │ │ ├── wing.bin │ │ ├── wing.gltf │ │ ├── wing_image0.png │ │ ├── wing_image1.png │ │ ├── wing_image2.png │ │ └── wing_image3.png ├── sounds │ ├── go.mp3 │ └── music.mp3 └── textures │ ├── SimpleTrack_ORM.png │ ├── SimpleTrack_basecolor.png │ ├── SimpleTrack_normal.png │ ├── StylizedWall_ORM.png │ ├── StylizedWall_basecolor.png │ ├── StylizedWall_normal.png │ ├── TrackBoundary_ORM.png │ ├── TrackBoundary_basecolor.png │ ├── TrackBoundary_normal.png │ ├── flare.png │ ├── goal_basecolor.png │ ├── logo.png │ └── skybox │ ├── TropicalSunnyDay_nx.jpg │ ├── TropicalSunnyDay_ny.jpg │ ├── TropicalSunnyDay_nz.jpg │ ├── TropicalSunnyDay_px.jpg │ ├── TropicalSunnyDay_py.jpg │ ├── TropicalSunnyDay_pz.jpg │ ├── skybox2_nx.jpg │ ├── skybox2_ny.jpg │ ├── skybox2_nz.jpg │ ├── skybox2_px.jpg │ ├── skybox2_py.jpg │ ├── skybox2_pz.jpg │ ├── skybox3_nx.jpg │ ├── skybox3_ny.jpg │ ├── skybox3_nz.jpg │ ├── skybox3_px.jpg │ ├── skybox3_py.jpg │ ├── skybox3_pz.jpg │ ├── skybox_nx.jpg │ ├── skybox_ny.jpg │ ├── skybox_nz.jpg │ ├── skybox_px.jpg │ ├── skybox_py.jpg │ └── skybox_pz.jpg ├── server.ts ├── tsconfig.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | bower_components/ 4 | .cache/ 5 | server.js -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Kart Racer (Chrome)", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceRoot}", 13 | "preLaunchTask": "start" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "start", 8 | "type": "npm", 9 | "script": "start", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | }, 14 | "isBackground": true, 15 | "problemMatcher": { 16 | "pattern": [ 17 | { 18 | "regexp": "dummy", 19 | "file": 1, 20 | "location": 2, 21 | "message": 3 22 | } 23 | ], 24 | "background": { 25 | "activeOnStart": true, 26 | "beginsPattern": "Compilation starting", 27 | "endsPattern": "Compilation finished" 28 | } 29 | }, 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to run this project 2 | clone this repo Install NodeJS cd into the repo and run: 3 | ``` 4 | npm install 5 | npm run start 6 | ``` 7 | Then open http://localhost:3000/ in a web browser. 8 | 9 | 10 | # TODOS 11 | Deploy to azure 12 | 13 | Multiplayer 14 | 15 | Loading models 16 | 17 | Setting up mobile controls 18 | 19 | Driving mechanics 20 | 21 | Physics/crashing 22 | 23 | Game ui/meunus 24 | 25 | Level design 26 | 27 | # VM setup Ubuntu 28 | ``` 29 | apt-get install build-essential libssl-dev 30 | curl https://raw.githubusercontent.com/creationix/nvm/v0.25.0/install.sh | bash 31 | ``` 32 | -------------------------------------------------------------------------------- /kartRacer/app.ts: -------------------------------------------------------------------------------- 1 | import "@babylonjs/core/Debug/debugLayer"; 2 | import "@babylonjs/inspector"; 3 | import { Vector3, DirectionalLight, CubeTexture, Tools, Scene, Engine, Observer, Nullable } from "@babylonjs/core"; 4 | import { Billboard } from "./billboard"; 5 | import { Kart } from "./kart"; 6 | import { IKartInput, KartInput } from "./input"; 7 | import { Assets } from "./assets"; 8 | import { Multiplayer } from "./multiplayer"; 9 | import { Track } from "./track"; 10 | import { Menu } from "./menu"; 11 | 12 | class App { 13 | private _scene: Scene; 14 | private _assets: Assets; 15 | private _input: IKartInput; 16 | private _mainKart: Kart; 17 | private _track: Track; 18 | 19 | constructor() { 20 | const canvas = this._createCanvas(); 21 | 22 | // Initialize Babylon scene and engine 23 | const engine = new Engine(canvas, true); 24 | engine.enableOfflineSupport = false; 25 | this._scene = new Scene(engine); 26 | 27 | // Load environment 28 | const environmentTexture = CubeTexture.CreateFromPrefilteredData("public/environment/environment.env", this._scene); 29 | environmentTexture.rotationY = Tools.ToRadians(45); 30 | this._scene.createDefaultSkybox(environmentTexture, true, 1000, 0.2); 31 | const light = new DirectionalLight("light", new Vector3(1, -2, 0), this._scene); 32 | light.intensity = 3.0; 33 | 34 | window.addEventListener("resize", () => { 35 | engine.resize(); 36 | }) 37 | 38 | window.addEventListener("keydown", (ev) => { 39 | // Shift+Ctrl+Alt+I 40 | if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) { 41 | if (this._scene.debugLayer.isVisible()) { 42 | this._scene.debugLayer.hide(); 43 | } 44 | else { 45 | this._scene.debugLayer.show(); 46 | } 47 | } 48 | }); 49 | 50 | this._assets = new Assets(); 51 | this._input = new KartInput(this._scene); 52 | this._initializeAsync(); 53 | } 54 | 55 | private _createCanvas(): HTMLCanvasElement { 56 | // Get rid of margin 57 | document.documentElement.style["overflow"] = "hidden"; 58 | document.documentElement.style.overflow = "hidden"; 59 | document.documentElement.style.width = "100%"; 60 | document.documentElement.style.height = "100%"; 61 | document.documentElement.style.margin = "0"; 62 | document.documentElement.style.padding = "0"; 63 | document.body.style.overflow = "hidden"; 64 | document.body.style.width = "100%"; 65 | document.body.style.height = "100%"; 66 | document.body.style.margin = "0"; 67 | document.body.style.padding = "0"; 68 | 69 | // Create canvas html element on webpage 70 | const canvas = document.createElement("canvas"); 71 | canvas.style.width = "100%"; 72 | canvas.style.height = "100%"; 73 | document.body.appendChild(canvas); 74 | 75 | return canvas; 76 | } 77 | 78 | private async _initializeAsync(): Promise { 79 | const engine = this._scene.getEngine(); 80 | 81 | engine.displayLoadingUI(); 82 | 83 | await this._assets.loadAsync(this._scene); 84 | 85 | const bodyMaterialIndex = Math.floor((Math.random() * 3)); 86 | const driverMaterialIndex = Math.floor((Math.random() * 3)); 87 | this._mainKart = new Kart("player_kart", this._scene, this._assets, bodyMaterialIndex, driverMaterialIndex, this._input); 88 | 89 | const billboard = new Billboard(this._scene, this._assets); 90 | const multiplayer = new Multiplayer(this._scene, this._assets, this._mainKart); 91 | 92 | await this._scene.whenReadyAsync(); 93 | 94 | engine.hideLoadingUI(); 95 | 96 | engine.runRenderLoop(() => { 97 | this._scene.render(); 98 | }); 99 | 100 | billboard.onGameStartObservable.add(async () => { 101 | // Save racer name to local storage 102 | const racerName = billboard.racerName; 103 | localStorage.setItem("KartRacer.PlayerName", racerName); 104 | 105 | engine.displayLoadingUI(); 106 | 107 | const raceInfo = await multiplayer.connectAsync("testRoom", racerName, this._mainKart, 108 | this._mainKart.bodyMaterialIndex, this._mainKart.driverMaterialIndex); 109 | 110 | multiplayer.onNewRaceObservable.add(async (newRaceInfo) => { 111 | engine.displayLoadingUI(); 112 | 113 | this._newRace(newRaceInfo.trackVarianceSeed); 114 | 115 | await this._scene.whenReadyAsync(); 116 | engine.hideLoadingUI(); 117 | }); 118 | 119 | const camera = this._mainKart.activateKartCamera(); 120 | const menu = new Menu(camera, this._scene, this._assets); 121 | this._mainKart.PlayerMenu = menu; 122 | this._mainKart.kartName = racerName; 123 | menu.EnableHud(); 124 | 125 | this._newRace(raceInfo.trackVarianceSeed); 126 | 127 | // Main render loop 128 | this._scene.onBeforeRenderObservable.add(() => { 129 | multiplayer.update(); 130 | 131 | const trackProgress = this._mainKart.trackProgress; 132 | menu.UpdateHUD(trackProgress); 133 | 134 | if (trackProgress === 100) { 135 | if (this._mainKart.TrackTime.length == 0) { 136 | this._mainKart.TrackTime = menu.StopTimer(); 137 | } 138 | 139 | multiplayer.raceComplete(this._mainKart.kartName); 140 | } 141 | }); 142 | 143 | await this._scene.whenReadyAsync(); 144 | engine.hideLoadingUI(); 145 | }); 146 | } 147 | 148 | private _newRace(varianceSeed: number): void { 149 | if (this._track) { 150 | this._track.dispose(); 151 | } 152 | 153 | this._track = new Track(this._scene, this._assets, { 154 | radius: 200, 155 | numPoints: 16, 156 | varianceSeed: varianceSeed, 157 | lateralVariance: 30, 158 | heightVariance: 20, 159 | width: 35, 160 | height: 5 161 | }); 162 | 163 | const checkpoints = this._track.trackPoints.map(value => value.point); 164 | const offset = new Vector3(0, 0.5, 0); 165 | this._mainKart.initializeTrackProgress(checkpoints, this._track.startPoint.add(offset), this._track.startTarget.add(offset)); 166 | this._mainKart.setDeathPositionY(this._track.trackPoints.reduce((p, c) => p.point.y < c.point.y ? p : c).point.y - 0.1); 167 | this._mainKart.reset(); 168 | } 169 | } 170 | 171 | new App(); 172 | -------------------------------------------------------------------------------- /kartRacer/assets.ts: -------------------------------------------------------------------------------- 1 | import { SceneLoader, Mesh, Sound, TransformNode, Scene, AnimationGroup, PBRMaterial, Texture, Vector3, Quaternion } from "@babylonjs/core"; 2 | import { GLTFFileLoader, GLTFLoaderAnimationStartMode } from "@babylonjs/loaders/glTF"; 3 | 4 | // HACK to fix the kart asset 5 | function cleanAnimationGroup(scene: Scene, animationGroup: AnimationGroup): AnimationGroup { 6 | const newAnimationGroup = new AnimationGroup(`${animationGroup.name}_cleaned`, scene); 7 | for (const targetedAnimation of animationGroup.targetedAnimations) { 8 | const values = targetedAnimation.animation.getKeys().map(key => key.value); 9 | if (((values[0] instanceof Vector3) && !values.every(value => Vector3.DistanceSquared(value, values[0]) < 0.0001)) || 10 | ((values[0] instanceof Quaternion) && !values.every(value => Quaternion.AreClose(value, values[0])))) { 11 | newAnimationGroup.addTargetedAnimation(targetedAnimation.animation, targetedAnimation.target); 12 | } 13 | } 14 | return newAnimationGroup; 15 | } 16 | 17 | export interface IAssetInfo { 18 | mesh: Mesh; 19 | animationGroups: Array; 20 | } 21 | 22 | export class Assets { 23 | public tree: IAssetInfo; 24 | public bomb: IAssetInfo; 25 | public boost: IAssetInfo; 26 | public bumper: IAssetInfo; 27 | public poison: IAssetInfo; 28 | public engineSound: Sound; 29 | public music: Sound; 30 | public unlitMaterial: PBRMaterial; 31 | public trackRoadMaterial: PBRMaterial; 32 | public trackBoundaryMaterial: PBRMaterial; 33 | public trackWallMaterial: PBRMaterial; 34 | public trackGoalMaterial: PBRMaterial; 35 | 36 | public async loadKartAsync(scene: Scene, bodyMaterialIndex: number, driverMaterialIndex: number): Promise { 37 | const result = await SceneLoader.ImportMeshAsync(null, "/public/models/roadsterKart/roadsterKart.gltf", undefined, scene); 38 | const root = result.meshes[0]; 39 | root.scaling.scaleInPlace(0.05); 40 | 41 | if (bodyMaterialIndex < 2) { 42 | const bodyMaterials = [ 43 | root.getChildMeshes(false).find(c => c.name === "bodyMat2").material, 44 | root.getChildMeshes(false).find(c => c.name === "bodyMat3").material, 45 | ]; 46 | 47 | const bodyMeshes = root.getChildTransformNodes(false).find(c => c.name === "carBody_low").getChildMeshes(false); 48 | for (const bodyMesh of bodyMeshes) { 49 | bodyMesh.material = bodyMaterials[bodyMaterialIndex]; 50 | } 51 | } 52 | 53 | if (driverMaterialIndex < 2) { 54 | const driverMaterials = [ 55 | root.getChildMeshes(false).find(c => c.name === "driverMat2").material, 56 | root.getChildMeshes(false).find(c => c.name === "driverMat3").material, 57 | ]; 58 | 59 | const driverMesh = root.getChildMeshes(false).find(c => c.name === "driver_low"); 60 | driverMesh.material = driverMaterials[driverMaterialIndex]; 61 | } 62 | 63 | return { 64 | mesh: root as Mesh, 65 | animationGroups: result.animationGroups 66 | }; 67 | } 68 | 69 | public async loadAsync(scene: Scene): Promise { 70 | const observer = SceneLoader.OnPluginActivatedObservable.add((loader: GLTFFileLoader) => { 71 | loader.animationStartMode = GLTFLoaderAnimationStartMode.NONE; 72 | }); 73 | 74 | const assets = new TransformNode("assets", scene); 75 | 76 | async function loadMergedAssetAsync(name: string, path: string): Promise { 77 | const container = await SceneLoader.LoadAssetContainerAsync(path, undefined, scene); 78 | const root = container.meshes[0]; 79 | const merged = Mesh.MergeMeshes(root.getChildMeshes() as Mesh[], false, undefined, undefined, undefined, true); 80 | merged.setEnabled(false); 81 | merged.name = name; 82 | merged.parent = assets; 83 | root.dispose(); 84 | return { 85 | mesh: merged, 86 | animationGroups: container.animationGroups.map(animationGroup => cleanAnimationGroup(scene, animationGroup)) 87 | }; 88 | } 89 | 90 | this.bomb = await loadMergedAssetAsync("bomb", "/public/models/bomb/bomb.gltf"); 91 | this.tree = await loadMergedAssetAsync("tree", "/public/models/evergreen2/evergreen2.gltf"); 92 | this.boost = await loadMergedAssetAsync("boost", "/public/models/wing/wing.gltf"); 93 | this.bumper = await loadMergedAssetAsync("bumper", "/public/models/bumper/bumper.gltf"); 94 | this.poison = await loadMergedAssetAsync("poison", "/public/models/poison_cloud/poison_cloud.gltf"); 95 | 96 | this.engineSound = new Sound("Music", "/public/sounds/go.mp3", scene, () => { 97 | this.engineSound.setVolume(0); 98 | this.engineSound.loop = true; 99 | this.engineSound.play(); 100 | }); 101 | 102 | this.music = new Sound("Music", "/public/sounds/music.mp3", scene, () => { 103 | this.music.loop = true; 104 | this.music.play(); 105 | }); 106 | 107 | this.unlitMaterial = new PBRMaterial("unlit", scene); 108 | this.unlitMaterial.unlit = true; 109 | 110 | this.trackRoadMaterial = this._createMaterial("trackRoad", scene); 111 | this.trackRoadMaterial.albedoTexture = new Texture("public/textures/SimpleTrack_basecolor.png", scene); 112 | this.trackRoadMaterial.bumpTexture = new Texture("public/textures/SimpleTrack_normal.png", scene); 113 | this.trackRoadMaterial.metallicTexture = new Texture("public/textures/SimpleTrack_ORM.png", scene); 114 | 115 | this.trackBoundaryMaterial = this._createMaterial("trackBoundary", scene); 116 | this.trackBoundaryMaterial.albedoTexture = new Texture("public/textures/TrackBoundary_basecolor.png", scene); 117 | this.trackBoundaryMaterial.bumpTexture = new Texture("public/textures/TrackBoundary_normal.png", scene); 118 | this.trackBoundaryMaterial.metallicTexture = new Texture("public/textures/TrackBoundary_ORM.png", scene); 119 | 120 | this.trackWallMaterial = this._createMaterial("trackWall", scene); 121 | this.trackWallMaterial.albedoTexture = new Texture("public/textures/StylizedWall_basecolor.png", scene); 122 | this.trackWallMaterial.bumpTexture = new Texture("public/textures/StylizedWall_normal.png", scene); 123 | this.trackWallMaterial.metallicTexture = new Texture("public/textures/StylizedWall_ORM.png", scene); 124 | 125 | this.trackGoalMaterial = this._createMaterial("trackGoal", scene); 126 | this.trackGoalMaterial.albedoTexture = new Texture("public/textures/goal_basecolor.png", scene); 127 | 128 | SceneLoader.OnPluginActivatedObservable.remove(observer); 129 | } 130 | 131 | private _createMaterial(name: string, scene: Scene): PBRMaterial { 132 | const material = new PBRMaterial(name, scene); 133 | material.metallic = 1; 134 | material.roughness = 1; 135 | material.backFaceCulling = false; 136 | material.twoSidedLighting = true; 137 | material.useMetallnessFromMetallicTextureBlue = true; 138 | material.useRoughnessFromMetallicTextureGreen = true; 139 | material.useRoughnessFromMetallicTextureAlpha = false; 140 | return material; 141 | } 142 | } -------------------------------------------------------------------------------- /kartRacer/billboard.ts: -------------------------------------------------------------------------------- 1 | import { Mesh, Texture, Observable, Scene, FreeCamera, Vector3, PBRMaterial } from "@babylonjs/core"; 2 | import { AdvancedDynamicTexture, StackPanel, Button, InputText } from "@babylonjs/gui"; 3 | import { Assets } from "./assets"; 4 | 5 | export class Billboard { 6 | private _racerName: InputText; 7 | 8 | public readonly onGameStartObservable = new Observable(); 9 | 10 | constructor(scene: Scene, assets: Assets) { 11 | const root = new Mesh("billboard", scene) 12 | 13 | const backgroundPlane = Mesh.CreatePlane("backgroundPlane", 5, scene); 14 | backgroundPlane.scaling.x = 1.8 15 | backgroundPlane.position.set(0, 10, 10 - 0.1); 16 | const backgroundMaterial = assets.unlitMaterial.clone("backgroundPlane"); 17 | backgroundMaterial.unlit = true; 18 | backgroundMaterial.albedoTexture = new Texture("/public/textures/logo.png", scene); 19 | backgroundPlane.material = backgroundMaterial; 20 | backgroundPlane.parent = root; 21 | 22 | const guiPlane = Mesh.CreatePlane("guiPlane", 6, scene); 23 | guiPlane.position.set(0, 10, 10 - 0.2); 24 | guiPlane.material = assets.unlitMaterial; 25 | guiPlane.parent = root; 26 | 27 | const mainMenuGUI = AdvancedDynamicTexture.CreateForMesh(guiPlane); 28 | 29 | const stackPanel = new StackPanel(); 30 | stackPanel.top = "200px"; 31 | mainMenuGUI.addControl(stackPanel); 32 | 33 | const racerName = new InputText("racerName"); 34 | racerName.width = 1; 35 | racerName.height = "100px"; 36 | racerName.placeholderText = "Enter racer name..."; 37 | racerName.fontSize = 50; 38 | racerName.color = "black"; 39 | racerName.background = "white"; 40 | racerName.focusedBackground = "white"; 41 | stackPanel.addControl(racerName); 42 | 43 | const startButton = Button.CreateSimpleButton("start", "Start Game"); 44 | startButton.width = 1; 45 | startButton.height = "100px"; 46 | startButton.color = "white"; 47 | startButton.fontSize = 50; 48 | startButton.background = "green" 49 | stackPanel.addControl(startButton); 50 | 51 | const billBoardBase = Mesh.CreateBox("base", 1, scene) 52 | billBoardBase.scaling.y = 10; 53 | billBoardBase.position.set(0, 5, 10.51); 54 | billBoardBase.setParent(root); 55 | 56 | const billBoardPanel = Mesh.CreateBox("billboard", 1, scene) 57 | billBoardPanel.scaling.x = 12; 58 | billBoardPanel.scaling.y = 6; 59 | billBoardPanel.position.set(0, 10, 10.51); 60 | billBoardPanel.setParent(root); 61 | 62 | startButton.onPointerUpObservable.add(() => { 63 | this.onGameStartObservable.notifyObservers(); 64 | }); 65 | 66 | const camera = new FreeCamera("camera", new Vector3(0, 10, 3), scene); 67 | camera.parent = root; 68 | 69 | scene.activeCamera = camera; 70 | 71 | // Get racer name from local storage if available 72 | if (typeof localStorage === "object") { 73 | const value = localStorage.getItem("KartRacer.PlayerName"); 74 | if (value) { 75 | racerName.text = value; 76 | } 77 | } 78 | 79 | this._racerName = racerName; 80 | } 81 | 82 | public get racerName(): string { 83 | const racerName = this._racerName.text.trim(); 84 | if (!racerName) { 85 | let num = Math.floor(Math.random() * 10000); 86 | this._racerName.text = ("kart_" + num); 87 | } 88 | 89 | return racerName; 90 | } 91 | } -------------------------------------------------------------------------------- /kartRacer/input.ts: -------------------------------------------------------------------------------- 1 | import { Scene, ActionManager, ExecuteCodeAction, Observer, Engine, Scalar } from '@babylonjs/core'; 2 | 3 | export interface IKartInput { 4 | horizontal: number; // Left = -1, Right = 1, Center = 0 5 | accelerate: number; // 1 = completely pressed 6 | brake: number; // 1 = completely pressed 7 | drift: boolean; 8 | } 9 | 10 | export class KartInput implements IKartInput { 11 | public horizontal: number = 0; 12 | public accelerate: number = 0; 13 | public brake: number = 0; 14 | public drift: boolean = false; 15 | 16 | // https://www.babylonjs-playground.com/#Y1W3F9 17 | 18 | private _scene: Scene; 19 | private _keymap: any; 20 | private _inputObserver: Observer; 21 | private _priorX: number; 22 | private _priorY: number; 23 | private _deltaTime: number; 24 | 25 | private updateFromKeyboard(): void { 26 | // Acceleration 27 | this.accelerate = 0; 28 | if (this._keymap["w"] || this._keymap["W"] || this._keymap["ArrowUp"]) { 29 | this.accelerate = 1; 30 | }; 31 | 32 | // Left/Right axis 33 | if (this._keymap["a"] || this._keymap["A"] || this._keymap["ArrowLeft"]) { 34 | this.horizontal = Scalar.Lerp(this.horizontal, -1, 0.2); 35 | } 36 | else if (this._keymap["d"] || this._keymap["D"] || this._keymap["ArrowRight"]) { 37 | this.horizontal = Scalar.Lerp(this.horizontal, 1, 0.2); 38 | } 39 | else { 40 | this.horizontal = Scalar.Lerp(this.horizontal, 0, 0.4); 41 | } 42 | 43 | // Brake 44 | this.brake = 0; 45 | if (this._keymap["s"] || this._keymap["S"] || this._keymap["ArrowDown"] || this._keymap[" "]) { 46 | this.brake = 1; 47 | }; 48 | 49 | // Handbrake/drift 50 | this.drift = false; 51 | if (this._keymap["Shift"]) { 52 | this.drift = true; 53 | }; 54 | } 55 | 56 | private updateFromDragging(): void { 57 | this._deltaTime = Engine.Instances[0].getDeltaTime() / 1000.0; 58 | 59 | this.accelerate += (this._priorY - this._scene.pointerY) * this._deltaTime; 60 | this.horizontal += (this._scene.pointerX - this._priorX) * this._deltaTime; 61 | 62 | this.accelerate = Math.min(1.0, Math.max(-1.0, this.accelerate)); 63 | this.horizontal = Math.min(1.0, Math.max(-1.0, this.horizontal)); 64 | 65 | this._priorX = this._scene.pointerX; 66 | this._priorY = this._scene.pointerY; 67 | } 68 | 69 | private updateFromNotDragging(): void { 70 | this._deltaTime = Engine.Instances[0].getDeltaTime() / 1000.0; 71 | 72 | this.accelerate *= (1.0 - 10.0 * this._deltaTime); 73 | this.horizontal *= (1.0 - 10.0 * this._deltaTime); 74 | 75 | if (Math.abs(this.accelerate) < 0.05 && Math.abs(this.horizontal) < 0.05) { 76 | this._scene.onBeforeRenderObservable.remove(this._inputObserver); 77 | 78 | var self = this; 79 | this._inputObserver = this._scene.onBeforeRenderObservable.add(() => { 80 | self.updateFromKeyboard() 81 | }); 82 | } 83 | } 84 | 85 | constructor(scene: Scene) { 86 | var self = this; 87 | 88 | this._scene = scene; 89 | this._keymap = {}; 90 | if (!scene.actionManager) { 91 | scene.actionManager = new ActionManager(this._scene); 92 | }; 93 | 94 | // register with the action manager to set the keymap values as either pressed or not pressed depending on the event 95 | this._scene.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnKeyDownTrigger, function (evt) { 96 | self._keymap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown"; 97 | })); 98 | 99 | this._scene.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnKeyUpTrigger, function (evt) { 100 | self._keymap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown"; 101 | })); 102 | 103 | var pointersDown: number = 0; 104 | scene.onPointerDown = () => { 105 | // TODO: Constrain touch down to a region. 106 | 107 | pointersDown += 1; 108 | if (pointersDown !== 1) { 109 | return; 110 | } 111 | 112 | self._priorX = scene.pointerX; 113 | self._priorY = scene.pointerY; 114 | 115 | scene.onBeforeRenderObservable.remove(this._inputObserver); 116 | this._inputObserver = scene.onBeforeRenderObservable.add(() => { 117 | self.updateFromDragging(); 118 | }); 119 | }; 120 | scene.onPointerUp = () => { 121 | pointersDown -= 1; 122 | if (pointersDown !== 0) { 123 | return; 124 | } 125 | 126 | scene.onBeforeRenderObservable.remove(this._inputObserver); 127 | this._inputObserver = scene.onBeforeRenderObservable.add(() => { 128 | self.updateFromNotDragging(); 129 | }); 130 | }; 131 | 132 | this._inputObserver = scene.onBeforeRenderObservable.add(() => { 133 | self.updateFromKeyboard() 134 | }); 135 | } 136 | } -------------------------------------------------------------------------------- /kartRacer/kart.ts: -------------------------------------------------------------------------------- 1 | import { Engine, Mesh, Scene, Vector3, Ray, Quaternion, FreeCamera, TransformNode, StandardMaterial, Scalar, AbstractMesh, AnimationGroup, ParticleSystem, MeshBuilder, Texture, Color4, Tags, PickingInfo, Sound, PBRMaterial } from "@babylonjs/core"; 2 | import { AdvancedDynamicTexture, StackPanel, TextBlock } from "@babylonjs/gui"; 3 | import { IKartInput } from "./input"; 4 | import { Menu } from "./menu"; 5 | import { Assets } from "./assets"; 6 | 7 | export class Kart extends TransformNode { 8 | private _engineSound: Sound; 9 | private _unlitMaterial: PBRMaterial; 10 | private _mesh: AbstractMesh; 11 | private _animationGroups?: { wheelsRotation: AnimationGroup, steering: AnimationGroup }; 12 | private _camera: FreeCamera; 13 | private _input: IKartInput; 14 | private _hits: number = 0; 15 | private _deathPositionY: number; 16 | private _particlesLeft: ParticleSystem; 17 | private _particlesRight: ParticleSystem; 18 | private _particlesState: ParticleSystem; 19 | private _particlesConeLeft: Mesh; 20 | private _particlesConeRight: Mesh; 21 | private _particlesSphere: Mesh; 22 | 23 | private static readonly UP_GROUNDED_FILTER_STRENGTH: number = 7.0; 24 | private static readonly UP_FALLING_FILTER_STRENGTH: number = 1.0; 25 | private static readonly TURN_FILTER_STRENGTH: number = 0.1; 26 | private static readonly MAX_TURN_SCALAR: number = Math.PI * 2 / 3; 27 | private static readonly FORWARD_VELOCITY_SCALAR: number = 1.2; 28 | private static readonly VELOCITY_DECAY_SCALAR: number = 4.0; 29 | private static readonly WALL_REBOUND_FACTOR: number = 1.6; 30 | private static readonly TURN_DECAY_SCALAR: number = 5.0; 31 | private static readonly BRAKE_SCALAR: number = 3.0; 32 | private static readonly SLOW_DURATION: number = 3000; 33 | private static readonly BOMB_DURATION: number = 1500; 34 | private static readonly BOOST_DURATION: number = 700; 35 | private static readonly BOOST_VELOCITY_FACTOR: number = 8.9; 36 | private static readonly ACCELERATION: number = 0.267; 37 | private static readonly BABY_ACCELERATION: number = 0.22; 38 | private static readonly BABY_THRESHOLD = 0.53; 39 | private static readonly DECCELERATION: number = 1.35; 40 | private static readonly TOP_DECCELERATION: number = 2; 41 | private static readonly TOP_ACCELERATION: number = 0.2; 42 | private static readonly TOP_THRESHOLD: number = 3.7; 43 | private static readonly MAX_SPEED: number = 4.3; 44 | 45 | private static readonly VELOCITY_DECAY_SCALARS: { [type: string]: number } = { 46 | "road": 4.0, 47 | "apron": 6.0, 48 | "flat": 10.0, 49 | }; 50 | 51 | private _velocity: Vector3 = Vector3.Zero(); 52 | private _relocity: number = 0.0; 53 | private _filteredUp: Vector3 = Vector3.Up(); 54 | private _deltaTime: number = 0.0; 55 | private _lastSafePosition: Vector3 = Vector3.Zero(); 56 | private _lastSafeFilteredUp: Vector3 = Vector3.Zero(); 57 | private _turnFactor: number = 0.0; 58 | private _kartName: string = ""; 59 | private _lastHazardId: number = -1; 60 | private _lastHazardType: string = ""; 61 | private _bombHitTime: number = 0; 62 | private _velocityFactor: number; 63 | private _currentVelocityFactor: number = 0; 64 | private _initialPosition: Vector3; 65 | private _velocityDecayScalar: number = Kart.VELOCITY_DECAY_SCALARS["road"]; 66 | 67 | private _initialLookAt: Vector3; 68 | private _checkpoints: Vector3[]; 69 | private _totalCheckpoints: number = 0; 70 | private _boostHitTime: number = 0; 71 | private _slowHitTime: number = 0; 72 | private _state: string = "ok"; 73 | 74 | public TrackTime: string = ""; 75 | public PlayerMenu: Menu; 76 | 77 | private _wheelsRotationSpeedRatio = 0; 78 | public get wheelsRotationSpeedRatio(): number { 79 | return this._wheelsRotationSpeedRatio; 80 | } 81 | public set wheelsRotationSpeedRatio(value: number) { 82 | this._wheelsRotationSpeedRatio = value; 83 | if (this._animationGroups) { 84 | this._animationGroups.wheelsRotation.speedRatio = this._wheelsRotationSpeedRatio; 85 | } 86 | } 87 | 88 | private _steeringAnimationFrame = 0; 89 | public get steeringAnimationFrame(): number { 90 | return this._steeringAnimationFrame; 91 | } 92 | public set steeringAnimationFrame(value: number) { 93 | this._steeringAnimationFrame = value; 94 | if (this._animationGroups) { 95 | this._animationGroups.steering.goToFrame(this._steeringAnimationFrame); 96 | } 97 | } 98 | 99 | public readonly bodyMaterialIndex: number; 100 | public readonly driverMaterialIndex: number; 101 | 102 | constructor(kartName: string, scene: Scene, assets: Assets, bodyMaterialIndex: number, driverMaterialIndex: number, input?: IKartInput) { 103 | super(kartName, scene); 104 | 105 | this.bodyMaterialIndex = bodyMaterialIndex; 106 | this.driverMaterialIndex = driverMaterialIndex; 107 | 108 | this._engineSound = assets.engineSound; 109 | this._unlitMaterial = assets.unlitMaterial; 110 | 111 | assets.loadKartAsync(scene, bodyMaterialIndex, driverMaterialIndex).then(assetInfo => { 112 | this._mesh = assetInfo.mesh; 113 | this._mesh.name = "model"; 114 | this._mesh.parent = this; 115 | 116 | this._animationGroups = { 117 | wheelsRotation: assetInfo.animationGroups[0], 118 | steering: assetInfo.animationGroups[1] 119 | }; 120 | 121 | this._animationGroups.wheelsRotation.play(true); 122 | this._animationGroups.wheelsRotation.speedRatio = this._wheelsRotationSpeedRatio; 123 | 124 | this._animationGroups.steering.play(true); 125 | this._animationGroups.steering.pause(); 126 | this._animationGroups.steering.goToFrame(this._steeringAnimationFrame); 127 | }); 128 | 129 | this._input = input; 130 | 131 | this.setUpParticleSystems(scene); 132 | 133 | this.rotationQuaternion = new Quaternion(); 134 | } 135 | 136 | public setDeathPositionY(value: number): void { 137 | this._deathPositionY = value; 138 | } 139 | 140 | public activateKartCamera(): FreeCamera { 141 | this.setup3rdPersonKartCamera(); 142 | 143 | this._scene.registerBeforeRender(() => { 144 | this.beforeRenderUpdate(); 145 | }); 146 | 147 | return this._camera; 148 | } 149 | 150 | public initializeTrackProgress(checkpoints: Vector3[], startingPosition: Vector3, startingLookAt: Vector3): void { 151 | this._initialPosition = startingPosition; 152 | this._initialLookAt = startingLookAt; 153 | this._checkpoints = checkpoints; 154 | // checkpoints.forEach((c)=>{ 155 | // var s = Mesh.CreateSphere("", 16, 60) 156 | // s.position.copyFrom(c) 157 | // s.isPickable = false 158 | // }) 159 | this._totalCheckpoints = checkpoints.length; 160 | } 161 | 162 | public get trackProgress(): number { 163 | return Math.round(this._hits / this._totalCheckpoints * 100); 164 | } 165 | 166 | public set kartName(value: string) { 167 | var namePlane = Mesh.CreatePlane("namePlane", 3.5, this._scene); 168 | namePlane.material = this._unlitMaterial; 169 | 170 | var nameMesh = AdvancedDynamicTexture.CreateForMesh(namePlane); 171 | var stackPanel = new StackPanel(); 172 | stackPanel.height = "100%"; 173 | nameMesh.addControl(stackPanel); 174 | 175 | var nameText = new TextBlock(); 176 | nameText.height = "100%"; 177 | nameText.textVerticalAlignment = TextBlock.VERTICAL_ALIGNMENT_TOP; 178 | nameText.fontSize = 96; 179 | nameText.color = "white" 180 | nameText.text = value; 181 | nameText.textWrapping = true; 182 | nameText.outlineColor = "black"; 183 | nameText.outlineWidth = 3; 184 | stackPanel.addControl(nameText); 185 | namePlane.position.set(0, 1, 0); 186 | namePlane.parent = this; 187 | 188 | this._kartName = value; 189 | } 190 | 191 | public get kartName(): string { 192 | return this._kartName; 193 | } 194 | 195 | private updateFromTrackPhysics(): void { 196 | var ray = new Ray(this.position, this.up.scale(-1.0), 0.7); 197 | var hit = this.getScene().pickWithRay(ray, mesh => Tags.HasTags(mesh)); 198 | if (hit.hit) { 199 | // MAGIC: There is a bug in the picking code where the barycentric coordinates 200 | // returned for bu and bv are actually bv and bw. This causes the normals to be 201 | // calculated incorrectly. 202 | const bv = hit.bu; 203 | const bw = hit.bv; 204 | const bu = 1.0 - bv - bw; 205 | hit.bu = bu; 206 | hit.bv = bv; 207 | 208 | var normal = hit.getNormal(true, true); 209 | 210 | this._filteredUp = Vector3.Lerp( 211 | this._filteredUp, 212 | normal, 213 | Kart.UP_GROUNDED_FILTER_STRENGTH * this._deltaTime); 214 | this._filteredUp.normalize(); 215 | 216 | this.position = hit.pickedPoint.add(this._filteredUp.scale(0.55)); 217 | 218 | this._velocity.subtractInPlace(normal.scale(Vector3.Dot(this._velocity, normal))); 219 | 220 | this._lastSafePosition.copyFrom(this.position); 221 | this._lastSafeFilteredUp.copyFrom(this._filteredUp); 222 | 223 | const tags = Tags.GetTags(hit.pickedMesh); 224 | this._velocityDecayScalar = Kart.VELOCITY_DECAY_SCALARS[tags]; 225 | } 226 | else { 227 | this._filteredUp = Vector3.Lerp( 228 | this._filteredUp, 229 | Vector3.Up(), 230 | Kart.UP_FALLING_FILTER_STRENGTH * this._deltaTime); 231 | this._filteredUp.normalize(); 232 | 233 | this._velocity.addInPlace(Vector3.Down().scale(this._deltaTime)); 234 | 235 | if (this.position.y < this._deathPositionY) { 236 | this.position.copyFrom(this._lastSafePosition); 237 | this._filteredUp.copyFrom(this._lastSafeFilteredUp); 238 | this._velocity.set(0.0, 0.0, 0.0); 239 | this._relocity = 0.0; 240 | } 241 | } 242 | 243 | var forward = Vector3.Cross(this.right, this._filteredUp); 244 | var right = Vector3.Cross(this._filteredUp, forward); 245 | Quaternion.RotationQuaternionFromAxisToRef(right, this._filteredUp, forward, this.rotationQuaternion); 246 | } 247 | 248 | private updateFromWallPhysics(): void { 249 | var hit: PickingInfo; 250 | 251 | var ray = new Ray(this.up, Vector3.Zero(), 0.0); 252 | ray.origin.scaleInPlace(0.5); 253 | ray.origin.addInPlace(this.position); 254 | [this.forward, this.right, this.forward.scale(-1.0), this.right.scale(-1.0)].forEach((direction) => { 255 | ray.direction = direction; 256 | ray.length = 2.0; 257 | hit = this.getScene().pickWithRay(ray, mesh => Tags.GetTags(mesh) === "wall"); 258 | if (hit.hit) { 259 | var normal = hit.getNormal(true, true); 260 | var velocityNormalDot = Vector3.Dot(this._velocity, normal); 261 | 262 | if (velocityNormalDot < 0.0) { 263 | this._velocity.subtractInPlace(normal.scale(Kart.WALL_REBOUND_FACTOR * velocityNormalDot)); 264 | } 265 | 266 | var projection = normal.scale(Vector3.Dot(normal, direction.scale(-hit.distance))); 267 | if (projection.lengthSquared() < 1.0) { 268 | this.position.addInPlace(normal.scale(1.0 - projection.length())); 269 | } 270 | } 271 | }); 272 | } 273 | 274 | private checkHazardCollision(name: string): number { 275 | const radiusCollisionSquared = 4; 276 | 277 | const hazards = this.getScene().getTransformNodeByName(name); 278 | 279 | if (hazards == null) { 280 | return -1; 281 | } 282 | 283 | const meshes = hazards.getChildMeshes(); 284 | 285 | for (var index = 0; index < meshes.length; ++index) { 286 | const position = meshes[index].absolutePosition; 287 | const distanceSquared = Vector3.DistanceSquared(this.position, position); 288 | if (distanceSquared < radiusCollisionSquared && meshes[index].isVisible) { 289 | return index; 290 | } 291 | } 292 | 293 | return -1; 294 | } 295 | 296 | private disappearHazard(name: string, index: number) { 297 | const hazards = this.getScene().getTransformNodeByName(name); 298 | const hazardMeshes = hazards.getChildMeshes(); 299 | hazardMeshes[index].isVisible = false; 300 | } 301 | 302 | 303 | private resetAllHazardsOfAType(name: string) { 304 | const hazards = this.getScene().getTransformNodeByName(name); 305 | const hazardMeshes = hazards.getChildMeshes(); 306 | for (var index = 0; index < hazardMeshes.length; ++index) { 307 | hazardMeshes[index].isVisible = true; 308 | } 309 | } 310 | 311 | private resetAllHazards() { 312 | this._lastHazardId = -1; 313 | this._lastHazardType = ""; 314 | this.resetAllHazardsOfAType("bombs"); 315 | this.resetAllHazardsOfAType("poison"); 316 | this.resetAllHazardsOfAType("boosts"); 317 | this.resetAllHazardsOfAType("bumpers"); 318 | } 319 | 320 | private updateFromHazards(): void { 321 | let collisionId = this.checkHazardCollision("bombs"); 322 | if (collisionId != -1 && (collisionId != this._lastHazardId || this._lastHazardType != "bomb")) { 323 | this._velocity.set(0.0, 1.2, 0.0); 324 | this._lastHazardId = collisionId; 325 | this._lastHazardType = "bomb"; 326 | this._bombHitTime = (new Date).getTime(); 327 | this._velocityFactor = 0.5; 328 | this.setCurrentVelocityFactor(true); 329 | this._state = "exploded"; 330 | this.disappearHazard("bombs", collisionId); 331 | } 332 | 333 | collisionId = this.checkHazardCollision("boosts"); 334 | if (collisionId != -1 && (collisionId != this._lastHazardId || this._lastHazardType != "boost")) { 335 | this._lastHazardId = collisionId; 336 | this._lastHazardType = "boost"; 337 | this._boostHitTime = (new Date).getTime(); 338 | this._velocityFactor = Kart.BOOST_VELOCITY_FACTOR; 339 | this.setCurrentVelocityFactor(true); 340 | this._state = "fast"; 341 | this.disappearHazard("boosts", collisionId); 342 | } 343 | 344 | collisionId = this.checkHazardCollision("bumpers"); 345 | if (collisionId != -1) { 346 | const hazards = this.getScene().getTransformNodeByName("bumpers"); 347 | const bumpers = hazards.getChildMeshes(); 348 | const bumper = bumpers[collisionId]; 349 | const bumperPosition = bumper.position; 350 | let direction = this.position.subtract(bumperPosition); 351 | direction.y = 0; 352 | direction.normalize(); 353 | 354 | const angle = Vector3.GetAngleBetweenVectors(this._velocity, direction, new Vector3(0, 1, 0)); 355 | if (angle > 2 * Math.PI / 3.0 && angle < 4 * Math.PI / 3.0) { 356 | this._velocity.set(-this._velocity.x, this._velocity.y, -this._velocity.z); 357 | } 358 | else { 359 | const speed = Math.max(this._velocity.length() * .8, 0.3); 360 | 361 | direction.scaleInPlace(this._velocity.length() * 2); 362 | this._velocity.addInPlace(direction); 363 | this._velocity.normalize(); 364 | this._velocity.scaleInPlace(speed); 365 | } 366 | 367 | this._lastHazardId = collisionId; 368 | this._lastHazardType = "bumper"; 369 | } 370 | collisionId = this.checkHazardCollision("poison"); 371 | if (collisionId != -1 && (collisionId != this._lastHazardId || this._lastHazardType != "poison")) { 372 | this._velocity.set(0.0, 0.0, 0.0); 373 | this._lastHazardId = collisionId; 374 | this._lastHazardType = "poison"; 375 | this._slowHitTime = (new Date).getTime(); 376 | this._velocityFactor = 0.1; 377 | this.setCurrentVelocityFactor(true); 378 | this._state = "slow"; 379 | 380 | this.disappearHazard("poison", collisionId); 381 | } 382 | } 383 | 384 | private getForward(): number { 385 | //return false ? 1.0 : 0.0; 386 | return Math.max(0, Math.min(1, this._input.accelerate)); 387 | } 388 | 389 | private getLeft(): number { 390 | //return false ? 1.0 : 0.0; 391 | return Math.max(0, Math.min(1, -this._input.horizontal)); 392 | } 393 | 394 | private getBack(): number { 395 | //return false ? 1.0 : 0.0; 396 | return Math.max(0, Math.min(1, -this._input.accelerate)); 397 | } 398 | 399 | private getRight(): number { 400 | //return false ? 1.0 : 0.0; 401 | return Math.max(0, Math.min(1, this._input.horizontal)); 402 | } 403 | 404 | private getBrake(): number { 405 | //return false ? 1.0 : 0.0; 406 | return Math.max(0, Math.min(1, this._input.brake)); 407 | } 408 | 409 | private updateFromControls(): void { 410 | this._turnFactor = Kart.TURN_FILTER_STRENGTH * this.getLeft(); 411 | this._relocity = this._turnFactor * -Kart.MAX_TURN_SCALAR * this._deltaTime + (1.0 - this._turnFactor) * this._relocity; 412 | 413 | this._turnFactor = Kart.TURN_FILTER_STRENGTH * this.getRight(); 414 | this._relocity = this._turnFactor * Kart.MAX_TURN_SCALAR * this._deltaTime + (1.0 - this._turnFactor) * this._relocity; 415 | 416 | this.rotateAround(this.position, this.up, this._relocity); 417 | 418 | this._engineSound.setVolume(Scalar.Lerp(this._engineSound.getVolume(), this.getForward(), 0.1)) 419 | this._velocity.addInPlace(this.forward.scale(this.getForward() * Kart.FORWARD_VELOCITY_SCALAR * this._currentVelocityFactor * this._deltaTime)); 420 | this.setCurrentVelocityFactor(false); 421 | 422 | this._velocity.scaleInPlace(1.0 - (this.getBrake() * Kart.BRAKE_SCALAR * this._deltaTime)); 423 | 424 | this._velocity.subtractInPlace(this.forward.scale(this.getBack() * this._deltaTime)); 425 | 426 | if (this._animationGroups) { 427 | this.wheelsRotationSpeedRatio = this._velocity.length() * 300 / 17.825; 428 | this.steeringAnimationFrame = (this._input.horizontal + 1) * 0.5 * this._animationGroups.steering.to; 429 | } 430 | } 431 | 432 | private updateFromTrackProgress(): void { 433 | let i: number; 434 | let closestPoint = this._checkpoints[0]; 435 | let kartPos = this.position; 436 | let closestPos = 0; 437 | let previousPos = this._hits; 438 | 439 | for (i = 1; i < this._checkpoints.length; i++) { 440 | let closeDiff = kartPos.subtract(closestPoint); 441 | let currentDiff = kartPos.subtract(this._checkpoints[i]); 442 | 443 | if (closeDiff.length() > currentDiff.length()) { 444 | closestPoint = this._checkpoints[i]; 445 | closestPos = i; 446 | } 447 | } 448 | 449 | if (Math.abs(previousPos - closestPos) < 3) { 450 | this._hits = closestPos; 451 | } 452 | } 453 | 454 | private beforeRenderUpdate(): void { 455 | this._deltaTime = Engine.Instances[0].getDeltaTime() / 1000.0; 456 | if (this._deltaTime > 0.1) { 457 | return; 458 | } 459 | 460 | if ((this._state == "exploded" && (new Date).getTime() - this._bombHitTime > Kart.BOMB_DURATION) 461 | || (this._state == "fast" && (new Date).getTime() - this._boostHitTime > Kart.BOOST_DURATION) 462 | || (this._state == "slow" && (new Date).getTime() - this._slowHitTime > Kart.SLOW_DURATION)) { 463 | this.resetVelocityFactor(); 464 | this._state = "ok"; 465 | } 466 | 467 | if (this._hits < this._checkpoints.length) { 468 | this.updateFromTrackProgress(); 469 | } 470 | 471 | this.updateFromWallPhysics(); 472 | this.updateFromTrackPhysics(); 473 | this.updateFromHazards(); 474 | 475 | if (this._state != "exploded") { 476 | this.updateFromControls(); 477 | } 478 | 479 | this._velocity.scaleInPlace(1.0 - (this._velocityDecayScalar * this._deltaTime)); 480 | this._relocity *= (1.0 - (Kart.TURN_DECAY_SCALAR * this._deltaTime)); 481 | 482 | this.position.addInPlace(this._velocity.scale(this._deltaTime * 60)); 483 | 484 | this.updateParticles(this._velocity.length()); 485 | } 486 | 487 | private setup3rdPersonKartCamera() { 488 | this._camera = new FreeCamera(this.name + "_camera", new Vector3(0, 4, -8), this.getScene()); 489 | this._camera.setTarget(this.position.add(this.forward.scale(10.0))); 490 | this._camera.parent = this; 491 | this.getScene().activeCamera = this._camera; 492 | } 493 | 494 | private setUpParticleSystems(scene: Scene) { 495 | const scaling = this.scaling; 496 | this._particlesLeft = this.setUpSpeedParticles(scene, this._particlesConeLeft, new Vector3(-scaling.x, 0.5, 2 * scaling.z), new Vector3(-scaling.x, 0.0, 0)) 497 | this._particlesRight = this.setUpSpeedParticles(scene, this._particlesConeRight, new Vector3(scaling.x, 0.5, 2 * scaling.z), new Vector3(scaling.x, 0.0, 0)) 498 | this._particlesSphere = MeshBuilder.CreateSphere("sphere", { diameter: scaling.x * 2, segments: 8 }, scene); 499 | this._particlesSphere.position = this.position 500 | this._particlesSphere.parent = this; 501 | this._particlesSphere.material = new StandardMaterial("particlesSphere", scene); 502 | this._particlesSphere.visibility = 0; 503 | this._particlesSphere.isPickable = false; 504 | 505 | this._particlesState = new ParticleSystem("particles", 2000, scene); 506 | this._particlesState.particleTexture = new Texture("/public/textures/flare.png", scene); 507 | this._particlesState.emitter = this._particlesSphere; 508 | this._particlesState.createSphereEmitter(scaling.x); 509 | this._particlesState.colorDead = new Color4(0, 0.0, 0.0, 0.0); 510 | this._particlesState.minSize = 0.3; 511 | this._particlesState.maxSize = 0.5; 512 | this._particlesState.minLifeTime = 2; 513 | this._particlesState.maxLifeTime = 5; 514 | this._particlesState.emitRate = 0; 515 | this._particlesState.blendMode = ParticleSystem.BLENDMODE_ONEONE; 516 | this._particlesState.minEmitPower = 1; 517 | this._particlesState.maxEmitPower = 2; 518 | this._particlesState.updateSpeed = 0.08; 519 | this._particlesState.start(); 520 | 521 | } 522 | 523 | private setUpSpeedParticles(scene: Scene, cone: Mesh, minEmitBox: Vector3, maxEmitBox: Vector3): ParticleSystem { 524 | cone = MeshBuilder.CreateCylinder("cone", { diameterBottom: 0, diameterTop: 1, height: 1 }, scene); 525 | cone.position = this.position.subtract(new Vector3(0, 0, 1.5)); 526 | // cone.rotate(new Vector3(1,0,0), -Math.PI/2.0); 527 | cone.parent = this; 528 | cone.material = new StandardMaterial("particlesCone", scene); 529 | cone.visibility = 0; 530 | cone.isPickable = false; 531 | 532 | const particlesSystem = new ParticleSystem("particles", 2000, scene); 533 | particlesSystem.particleTexture = new Texture("/public/textures/flare.png", scene); 534 | particlesSystem.emitter = cone; 535 | particlesSystem.minEmitBox = minEmitBox; 536 | particlesSystem.maxEmitBox = maxEmitBox; 537 | 538 | particlesSystem.colorDead = new Color4(0, 0.0, 0.0, 0.0); 539 | particlesSystem.minSize = 0.1; 540 | particlesSystem.maxSize = 0.15; 541 | particlesSystem.minLifeTime = 0.02; 542 | particlesSystem.maxLifeTime = 0.05; 543 | particlesSystem.emitRate = 0; 544 | particlesSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE; 545 | particlesSystem.direction1 = new Vector3(0, 0, -1); 546 | particlesSystem.direction2 = new Vector3(0, 1, -1); 547 | particlesSystem.minAngularSpeed = 0; 548 | particlesSystem.maxAngularSpeed = Math.PI / 8; 549 | particlesSystem.minEmitPower = 0.5; 550 | particlesSystem.maxEmitPower = 1; 551 | particlesSystem.updateSpeed = 0.08; 552 | 553 | particlesSystem.start(); 554 | 555 | return particlesSystem; 556 | } 557 | 558 | private updateSpeedParticle(speed: number) { 559 | this._particlesLeft.emitRate = speed * 100; 560 | this._particlesRight.emitRate = speed * 100; 561 | 562 | 563 | if (speed > 0 && speed < .7) { 564 | const gray1 = new Color4(0.3, 0.3, 0.3, 1.0); 565 | const gray2 = new Color4(0.7, 0.7, 0.7, 1.0); 566 | this._particlesLeft.color1 = gray1; 567 | this._particlesLeft.color2 = gray2; 568 | this._particlesLeft.maxLifeTime = 2; 569 | this._particlesRight.color1 = gray1; 570 | this._particlesRight.color2 = gray2; 571 | this._particlesRight.maxLifeTime = 2; 572 | } 573 | 574 | else if (speed >= .7 && speed < 1.1) { 575 | const yellow1 = new Color4(1, 1, 0.0, 1.0); 576 | const yellow2 = new Color4(1, 0.8, 0.0, 1.0); 577 | this._particlesLeft.color1 = yellow1; 578 | this._particlesLeft.color2 = yellow2; 579 | this._particlesLeft.maxLifeTime = .5; 580 | this._particlesRight.color1 = yellow1; 581 | this._particlesRight.color2 = yellow2; 582 | this._particlesRight.maxLifeTime = .5; 583 | } 584 | 585 | else if (speed >= 1.1 && speed < 1.5) { 586 | const red1 = new Color4(1, 0, 0.0, 1.0); 587 | const red2 = new Color4(.7, 0.0, 0.0, 1.0); 588 | this._particlesLeft.color1 = red1; 589 | this._particlesLeft.color2 = red2; 590 | this._particlesLeft.maxLifeTime = .4; 591 | this._particlesRight.color1 = red1; 592 | this._particlesRight.color2 = red2; 593 | this._particlesRight.maxLifeTime = .4; 594 | } 595 | 596 | else { 597 | const blue1 = new Color4(0, 1, 0.0, 1.0); 598 | const blue2 = new Color4(0, 0.8, 0.0, 1.0); 599 | this._particlesLeft.color1 = blue1; 600 | this._particlesLeft.color2 = blue2; 601 | this._particlesLeft.maxLifeTime = .4; 602 | this._particlesRight.color1 = blue1; 603 | this._particlesRight.color2 = blue2; 604 | this._particlesRight.maxLifeTime = .4; 605 | } 606 | } 607 | 608 | private updateParticles(speed: number) { 609 | this.updateSpeedParticle(speed); 610 | 611 | if (this._state == "slow") { 612 | this._particlesState.color1 = new Color4(.6, 0, .9, 1); 613 | this._particlesState.color2 = new Color4(.5, 0, .8, 1); 614 | this._particlesState.emitRate = 500; 615 | } 616 | 617 | else if (this._state == "exploded") { 618 | this._particlesState.color1 = new Color4(0.5, 0.5, 0.5, 1); 619 | this._particlesState.color2 = new Color4(0.8, 0, 0, 1); 620 | this._particlesState.emitRate = 500; 621 | } 622 | 623 | else if (this._state == "fast") { 624 | this._particlesState.color1 = new Color4(0.0, 0, .8, 1); 625 | this._particlesState.color2 = new Color4(0.0, .8, 0, 1); 626 | this._particlesState.emitRate = 500; 627 | } 628 | 629 | else { 630 | this._particlesState.emitRate = 0; 631 | } 632 | } 633 | 634 | public reset() { 635 | this._hits = 0; 636 | this._state = "ok"; 637 | this._velocity.set(0, 0, 0); 638 | this.resetVelocityFactor(); 639 | this._currentVelocityFactor = 0; 640 | this.position = this._initialPosition; 641 | this.lookAt(this._initialLookAt); 642 | this.computeWorldMatrix(); 643 | this.TrackTime = ""; 644 | this.PlayerMenu.SetWinText(""); 645 | this.PlayerMenu.StartTimer(); 646 | this.resetAllHazards(); 647 | } 648 | 649 | private resetVelocityFactor() { 650 | this._velocityFactor = Kart.MAX_SPEED; 651 | } 652 | 653 | private setCurrentVelocityFactor(hardReset: boolean = false) { 654 | if (hardReset) { 655 | this._currentVelocityFactor = this._velocityFactor; 656 | } 657 | else { 658 | let goalVelocityFactor: number = this._velocityFactor; 659 | let acceleration = Kart.ACCELERATION; 660 | if (this.getForward() === 0) { 661 | goalVelocityFactor = 0; 662 | acceleration = Kart.DECCELERATION; 663 | } 664 | else { 665 | if (this._currentVelocityFactor < Kart.BABY_THRESHOLD) { 666 | acceleration = Kart.BABY_ACCELERATION; 667 | } 668 | if (this._currentVelocityFactor > Kart.TOP_THRESHOLD) { 669 | acceleration = Kart.TOP_ACCELERATION; 670 | } 671 | if (this._currentVelocityFactor > goalVelocityFactor) { 672 | acceleration = Kart.TOP_DECCELERATION; 673 | } 674 | } 675 | this._currentVelocityFactor = Scalar.Lerp(this._currentVelocityFactor, goalVelocityFactor, this._deltaTime * acceleration); 676 | } 677 | } 678 | } 679 | -------------------------------------------------------------------------------- /kartRacer/menu.ts: -------------------------------------------------------------------------------- 1 | import { FreeCamera, Scene, Mesh, StandardMaterial } from "@babylonjs/core"; 2 | import { AdvancedDynamicTexture, TextBlock, StackPanel } from "@babylonjs/gui"; 3 | import { Assets } from "./assets"; 4 | 5 | export class Menu { 6 | private _camera: FreeCamera; 7 | private _UI: Mesh; 8 | private _timeText: TextBlock = null; 9 | private _scoreText: TextBlock = null; 10 | private _winText: TextBlock = null; 11 | private _startTime: number = null; 12 | private _stopTimer: boolean = false; 13 | private _time: number; 14 | 15 | constructor(camera: FreeCamera, scene: Scene, assets: Assets) { 16 | var hudPlane = Mesh.CreatePlane("hudPlane", 4.5, scene); 17 | hudPlane.material = assets.unlitMaterial; 18 | 19 | var driverUI = AdvancedDynamicTexture.CreateForMesh(hudPlane); 20 | 21 | var stackPanel = new StackPanel(); 22 | stackPanel.height = "1000px"; 23 | stackPanel.width = "100%"; 24 | driverUI.addControl(stackPanel); 25 | 26 | var timeText = new TextBlock(); 27 | timeText.height = "100px"; 28 | timeText.width = "100%"; 29 | timeText.textHorizontalAlignment = TextBlock.HORIZONTAL_ALIGNMENT_RIGHT; 30 | timeText.fontSize = 40; 31 | timeText.color = "white" 32 | timeText.text = "00:00:00"; 33 | timeText.outlineColor = "black"; 34 | timeText.outlineWidth = 8; 35 | 36 | var scoreText = new TextBlock(); 37 | scoreText.height = "50px"; 38 | scoreText.width = "100%"; 39 | scoreText.textHorizontalAlignment = TextBlock.HORIZONTAL_ALIGNMENT_RIGHT 40 | scoreText.fontSize = 40; 41 | scoreText.color = "white" 42 | scoreText.text = "0% Complete"; 43 | scoreText.outlineColor = "black"; 44 | scoreText.outlineWidth = 8; 45 | 46 | var winText = new TextBlock(); 47 | winText.height = "250px"; 48 | winText.width = "100%"; 49 | winText.textHorizontalAlignment = TextBlock.HORIZONTAL_ALIGNMENT_CENTER; 50 | winText.textVerticalAlignment = TextBlock.VERTICAL_ALIGNMENT_CENTER; 51 | winText.fontSize = 100; 52 | winText.color = "white" 53 | winText.text = ""; 54 | winText.outlineColor = "black" 55 | winText.outlineWidth = 8; 56 | 57 | stackPanel.addControl(timeText); 58 | stackPanel.addControl(scoreText); 59 | stackPanel.addControl(winText); 60 | 61 | this._UI = hudPlane; 62 | this._timeText = timeText; 63 | this._scoreText = scoreText; 64 | this._winText = winText; 65 | this._camera = camera; 66 | } 67 | 68 | public SetVisible(isEnabled: boolean): void { 69 | this._UI.isVisible = isEnabled; 70 | } 71 | 72 | public UpdateHUD(prog: number): void { 73 | if (this._startTime != null && !this._stopTimer) { 74 | let time = Math.floor((new Date().getTime() - this._startTime) / 1000); 75 | 76 | this._time = time; 77 | this._timeText.text = this.FormatTime(time); 78 | } 79 | 80 | this._scoreText.text = prog + "% Complete"; 81 | } 82 | 83 | public EnableHud(): void { 84 | this._UI.position.set(0, 0, 5); 85 | this._UI.parent = this._camera; 86 | } 87 | 88 | public StartTimer(): void { 89 | this._startTime = new Date().getTime(); 90 | this._stopTimer = false; 91 | } 92 | public StopTimer(): string { 93 | this._stopTimer = true; 94 | 95 | return this.FormatTime(this._time); 96 | } 97 | 98 | public SetWinText(text: string) { 99 | this._winText.text = text; 100 | } 101 | 102 | private FormatTime(time: number): string { 103 | let hours = Math.floor(time / 3600); 104 | time %= 3600; 105 | let minutes = Math.floor(time / 60); 106 | let seconds = time % 60; 107 | var hoursString: string = (hours < 10 ? "0" : "") + hours; 108 | var minutesString: string = (minutes < 10 ? "0" : "") + minutes; 109 | var secondsString: string = (seconds < 10 ? "0" : "") + seconds; 110 | 111 | return (hoursString + ":" + minutesString + ":" + secondsString); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /kartRacer/multiplayer.ts: -------------------------------------------------------------------------------- 1 | import { Vector3, Nullable, Quaternion, Scene, Scalar, Tools, Observable } from '@babylonjs/core'; 2 | import { Kart } from './kart'; 3 | import { Assets } from './assets'; 4 | 5 | // Socket io 6 | declare var io: any; 7 | 8 | export interface IRaceInfo { 9 | trackVarianceSeed: number; 10 | } 11 | 12 | export interface ITrackedObject { 13 | position: Vector3; 14 | rotationQuaternion: Quaternion; 15 | wheelsRotationSpeedRatio: number; 16 | steeringAnimationFrame: number; 17 | } 18 | 19 | // bodyMaterialIndex: number; 20 | // driverMaterialIndex: number; 21 | 22 | export class Multiplayer { 23 | public localId: string = ""; 24 | public trackedObject: Nullable; 25 | public trackedServerObjects: { [key: string]: { lastPose: ITrackedObject, targetPose: ITrackedObject, object: Nullable } } = {}; 26 | public lastTime = Date.now(); 27 | public pingMS = 1; 28 | public onNewRaceObservable = new Observable(); 29 | private _scene: Scene; 30 | private _assets: Assets; 31 | private _mainKart: Kart; 32 | private _raceId = 0; 33 | private _socket: SocketIO.Socket; 34 | private _waitingForNextRace = false; 35 | 36 | constructor(scene: Scene, assets: Assets, mainKart: Kart) { 37 | this._scene = scene; 38 | this._assets = assets; 39 | this._mainKart = mainKart; 40 | } 41 | 42 | public connectAsync(roomName: string, playerName: string, trackedObject: Nullable, bodyMaterialIndex: number, driverMaterialIndex: number): Promise { 43 | return new Promise(resolve => { 44 | var socket: SocketIO.Socket = io(); 45 | this._socket = socket; 46 | socket.emit("joinRoom", { 47 | roomName: "test", 48 | playerName: playerName, 49 | bodyMaterialIndex: bodyMaterialIndex, 50 | driverMaterialIndex: driverMaterialIndex 51 | }); 52 | socket.on("joinRoomComplete", (e) => { 53 | this._raceId = e.raceId; 54 | this.localId = e.id; 55 | this.trackedObject = trackedObject; 56 | this.pingMS = e.pingMS 57 | setInterval(() => { 58 | if (this.trackedObject) { 59 | socket.emit("updateKartPose", { 60 | p: this.trackedObject.position, 61 | r: this.trackedObject.rotationQuaternion, 62 | w: this.trackedObject.wheelsRotationSpeedRatio, 63 | s: this.trackedObject.steeringAnimationFrame, 64 | b: bodyMaterialIndex, 65 | d: driverMaterialIndex, 66 | }) 67 | } 68 | }, e.pingMS) 69 | 70 | socket.on("serverUpdate", (e) => { 71 | e.forEach((p: any) => { 72 | if (p.id != this.localId) { 73 | let trackedServerObject = this.trackedServerObjects[p.id]; 74 | if (!trackedServerObject) { 75 | const kart = new Kart(p.id, this._scene, this._assets, p.b, p.d); 76 | kart.kartName = p.name; 77 | trackedServerObject = { 78 | lastPose: { position: new Vector3(), rotationQuaternion: new Quaternion(), wheelsRotationSpeedRatio: 0, steeringAnimationFrame: 0 }, 79 | targetPose: { position: new Vector3(), rotationQuaternion: new Quaternion(), wheelsRotationSpeedRatio: 0, steeringAnimationFrame: 0 }, 80 | object: kart, 81 | }; 82 | this.trackedServerObjects[p.id] = trackedServerObject; 83 | } 84 | trackedServerObject.lastPose.position.copyFrom(trackedServerObject.targetPose.position); 85 | trackedServerObject.lastPose.rotationQuaternion.copyFrom(trackedServerObject.targetPose.rotationQuaternion); 86 | trackedServerObject.lastPose.wheelsRotationSpeedRatio = trackedServerObject.targetPose.wheelsRotationSpeedRatio; 87 | trackedServerObject.lastPose.steeringAnimationFrame = trackedServerObject.targetPose.steeringAnimationFrame; 88 | trackedServerObject.targetPose.position.copyFrom(p.p); 89 | trackedServerObject.targetPose.rotationQuaternion.copyFrom(p.r); 90 | trackedServerObject.targetPose.wheelsRotationSpeedRatio = p.w; 91 | trackedServerObject.targetPose.steeringAnimationFrame = p.s; 92 | this.lastTime = Date.now(); 93 | } 94 | }) 95 | }) 96 | 97 | socket.on("userDisconnected", (id) => { 98 | if (this.trackedServerObjects[id]) { 99 | (this.trackedServerObjects[id].object as any).dispose(); 100 | delete this.trackedServerObjects[id] 101 | } 102 | }) 103 | 104 | socket.on("raceComplete", (info) => { 105 | if (!this._waitingForNextRace) { 106 | this._waitingForNextRace = true; 107 | this._mainKart.PlayerMenu.SetWinText("GG! The winner is\n" + info.winnerName); 108 | setTimeout(() => { 109 | this._raceId = info.raceId; 110 | this.onNewRaceObservable.notifyObservers({ 111 | trackVarianceSeed: this._raceId 112 | }); 113 | this._waitingForNextRace = false; 114 | }, 4000); 115 | } 116 | }) 117 | 118 | resolve({ 119 | trackVarianceSeed: this._raceId 120 | }); 121 | }); 122 | }); 123 | } 124 | 125 | public update() { 126 | var curTime = Date.now(); 127 | var ratio = Scalar.Clamp((curTime - this.lastTime) / this.pingMS, 0, 1.1); 128 | for (var key in this.trackedServerObjects) { 129 | const trackedServerObject = this.trackedServerObjects[key]; 130 | Vector3.LerpToRef(trackedServerObject.lastPose.position, trackedServerObject.targetPose.position, ratio, trackedServerObject.object.position); 131 | Quaternion.SlerpToRef(trackedServerObject.lastPose.rotationQuaternion, trackedServerObject.targetPose.rotationQuaternion, ratio, trackedServerObject.object.rotationQuaternion); 132 | trackedServerObject.object.wheelsRotationSpeedRatio = Scalar.Lerp(trackedServerObject.lastPose.wheelsRotationSpeedRatio, trackedServerObject.targetPose.wheelsRotationSpeedRatio, ratio); 133 | trackedServerObject.object.steeringAnimationFrame = Scalar.Lerp(trackedServerObject.lastPose.steeringAnimationFrame, trackedServerObject.targetPose.steeringAnimationFrame, ratio); 134 | } 135 | } 136 | 137 | public raceComplete(name: string) { 138 | if (!this._waitingForNextRace) { 139 | this._socket.emit("raceComplete", { name: name, raceId: this._raceId }); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /kartRacer/track.ts: -------------------------------------------------------------------------------- 1 | import { Vector3, Curve3, RibbonBuilder, PBRMaterial, Texture, Tools, Scene, TransformNode, Mesh, Scalar, Vector2, Nullable, Tags, Quaternion, AnimationGroup } from "@babylonjs/core"; 2 | import { Assets, IAssetInfo } from "./assets"; 3 | 4 | export interface ITrackPoint { 5 | point: Vector3; 6 | forward: Vector3; 7 | up: Vector3; 8 | right: Vector3; 9 | 10 | leftEdge: Vector3; 11 | leftApron: Vector3; 12 | leftFlat: Vector3; 13 | leftWallInside: Vector3; 14 | leftWallOutside: Vector3; 15 | 16 | rightEdge: Vector3; 17 | rightApron: Vector3; 18 | rightFlat: Vector3; 19 | rightWallInside: Vector3; 20 | rightWallOutside: Vector3; 21 | } 22 | 23 | export class Track { 24 | public readonly startPoint: Vector3; 25 | public readonly startTarget: Vector3; 26 | public readonly trackPoints: Array; 27 | 28 | private _varianceSeed: number; 29 | private _track: TransformNode; 30 | private _animationGroups = new Array(); 31 | 32 | constructor(scene: Scene, assets: Assets, options: { radius: number, numPoints: number, varianceSeed: number, lateralVariance: number, heightVariance: number, width: number, height: number }) { 33 | this._varianceSeed = options.varianceSeed; 34 | 35 | const controlPoints = this._getControlPoints( 36 | options.numPoints, 37 | options.radius, 38 | options.lateralVariance, 39 | options.heightVariance 40 | ); 41 | 42 | const curvatureFactor = Math.ceil((options.radius + options.lateralVariance + options.heightVariance) * 0.05); 43 | const curve = this._getCurve(controlPoints, curvatureFactor); 44 | const curveLength = curve.length(); 45 | const points = curve.getPoints(); 46 | 47 | function getPoint(index: number): Vector3 { 48 | const length = points.length; 49 | return points[(index + length) % length]; 50 | } 51 | 52 | function getForward(index: number): Vector3 { 53 | return getPoint(index + 1).subtract(getPoint(index - 1)).normalize(); 54 | } 55 | 56 | function getUp(index: number): Vector3 { 57 | const curvatureVector = getPoint(index - curvatureFactor).add(getPoint(index + curvatureFactor)).scaleInPlace(0.5).subtractInPlace(getPoint(index)); 58 | return curvatureVector.addInPlaceFromFloats(0, curvatureFactor * 10, 0).scaleInPlace(0.5).normalize(); 59 | } 60 | 61 | const apronAngle = Tools.ToRadians(15); 62 | const apronLengthPercentage = 0.15; 63 | const flatWidthPercentage = 0.30; 64 | const wallHeight = options.height; 65 | const wallWidth = 1.0; 66 | 67 | this.trackPoints = new Array(points.length); 68 | for (let index = 0; index < points.length; ++index) { 69 | const point = points[index]; 70 | const forward = getForward(index); 71 | const up = getUp(index); 72 | const right = Vector3.Cross(up, forward); 73 | const flatUp = Vector3.UpReadOnly; 74 | const flatRight = Vector3.Cross(flatUp, forward); 75 | 76 | const edgeVector = right.scale(options.width * (0.5 - apronLengthPercentage)); 77 | const apronVector1 = edgeVector.add(right.scale(options.width * apronLengthPercentage * Math.cos(apronAngle))); 78 | const apronVector2 = up.scale(options.width * apronLengthPercentage * Math.sin(apronAngle)); 79 | const flatWidthVector = right.scale(options.width * flatWidthPercentage); 80 | const wallHeightVector = flatUp.scale(wallHeight); 81 | const wallWidthVector = flatRight.scale(wallWidth); 82 | 83 | const leftEdge = point.subtract(edgeVector); 84 | const leftApron = point.subtract(apronVector1).addInPlace(apronVector2); 85 | const leftFlat = leftApron.subtract(flatWidthVector); 86 | const leftWallInside = leftFlat.add(wallHeightVector); 87 | const leftWallOutside = leftWallInside.subtract(wallWidthVector); 88 | 89 | const rightEdge = point.add(edgeVector); 90 | const rightApron = point.add(apronVector1).addInPlace(apronVector2); 91 | const rightFlat = rightApron.add(flatWidthVector); 92 | const rightWallInside = rightFlat.add(wallHeightVector); 93 | const rightWallOutside = rightWallInside.add(wallWidthVector); 94 | 95 | this.trackPoints[index] = { 96 | point: point, 97 | forward: forward, 98 | up: up, 99 | right: right, 100 | 101 | leftEdge: leftEdge, 102 | leftApron: leftApron, 103 | leftFlat: leftFlat, 104 | leftWallInside: leftWallInside, 105 | leftWallOutside: leftWallOutside, 106 | 107 | rightEdge: rightEdge, 108 | rightApron: rightApron, 109 | rightFlat: rightFlat, 110 | rightWallInside: rightWallInside, 111 | rightWallOutside: rightWallOutside, 112 | }; 113 | } 114 | 115 | // Finish loop 116 | this.trackPoints.push(this.trackPoints[0]); 117 | 118 | this._track = new TransformNode("track", scene); 119 | 120 | // Update materials 121 | this._updateTextures(assets.trackRoadMaterial, Math.round(curveLength / options.width)); 122 | this._updateTextures(assets.trackBoundaryMaterial, Math.round(curveLength / options.width)); 123 | this._updateTextures(assets.trackWallMaterial, Math.round(curveLength / (wallHeight * 5))); 124 | 125 | // Create track parts 126 | this._createRoad(scene, assets, this.trackPoints); 127 | this._createAprons(scene, assets, this.trackPoints); 128 | this._createFlats(scene, assets, this.trackPoints); 129 | this._createWalls(scene, assets, this.trackPoints); 130 | this._createGoal(scene, assets, this.trackPoints); 131 | 132 | // Remove extra loop point. 133 | this.trackPoints.length--; 134 | 135 | // Create track objects 136 | this._createTrees(scene, assets, this.trackPoints); 137 | this._createHazards(scene, assets, this.trackPoints); 138 | 139 | this.startPoint = getPoint(0); 140 | this.startTarget = getPoint(1); 141 | } 142 | 143 | public dispose(): void { 144 | this._track.dispose(); 145 | 146 | for (const animationGroup of this._animationGroups) { 147 | animationGroup.dispose(); 148 | } 149 | } 150 | 151 | private _createRoad(scene: Scene, assets: Assets, trackPoints: Array): Mesh { 152 | const road = RibbonBuilder.CreateRibbon("road", { 153 | pathArray: trackPoints.map(p => [p.rightEdge, p.leftEdge]), 154 | uvs: this._createUVs(trackPoints, [0.15, 0.85]), 155 | }, scene); 156 | 157 | road.material = assets.trackRoadMaterial; 158 | road.parent = this._track; 159 | 160 | Tags.AddTagsTo(road, "road"); 161 | 162 | return road; 163 | } 164 | 165 | private _createAprons(scene: Scene, assets: Assets, trackPoints: Array): void { 166 | const aprons = new TransformNode("aprons", scene); 167 | aprons.parent = this._track; 168 | 169 | const right = RibbonBuilder.CreateRibbon("right", { 170 | pathArray: trackPoints.map(p => [p.rightApron, p.rightEdge]), 171 | uvs: this._createUVs(trackPoints, [1/3, 0]), 172 | }, scene); 173 | 174 | const left = RibbonBuilder.CreateRibbon("left", { 175 | pathArray: trackPoints.map(p => [p.leftEdge, p.leftApron]), 176 | uvs: this._createUVs(trackPoints, [0, 1/3]), 177 | }, scene); 178 | 179 | right.material = assets.trackBoundaryMaterial; 180 | right.parent = aprons; 181 | Tags.AddTagsTo(right, "apron"); 182 | 183 | left.material = assets.trackBoundaryMaterial; 184 | left.parent = aprons; 185 | Tags.AddTagsTo(left, "apron"); 186 | } 187 | 188 | private _createFlats(scene: Scene, assets: Assets, trackPoints: Array): void { 189 | const flats = new TransformNode("flats", scene); 190 | flats.parent = this._track; 191 | 192 | const right = RibbonBuilder.CreateRibbon("right", { 193 | pathArray: trackPoints.map(p => [p.rightFlat, p.rightApron]), 194 | uvs: this._createUVs(trackPoints, [1, 1/3]), 195 | }, scene); 196 | 197 | const left = RibbonBuilder.CreateRibbon("left", { 198 | pathArray: trackPoints.map(p => [p.leftApron, p.leftFlat]), 199 | uvs: this._createUVs(trackPoints, [1/3, 1]), 200 | }, scene); 201 | 202 | right.material = assets.trackBoundaryMaterial; 203 | right.parent = flats; 204 | Tags.AddTagsTo(right, "flat"); 205 | 206 | left.material = assets.trackBoundaryMaterial; 207 | left.parent = flats; 208 | Tags.AddTagsTo(left, "flat"); 209 | } 210 | 211 | private _createWalls(scene: Scene, assets: Assets, trackPoints: Array): void { 212 | const walls = new TransformNode("walls", scene); 213 | walls.parent = this._track; 214 | 215 | const right = RibbonBuilder.CreateRibbon("rightWall", { 216 | pathArray: trackPoints.map(p => [p.rightWallOutside, p.rightWallInside, p.rightFlat]), 217 | uvs: this._createUVs(trackPoints, [1, 0.8, 0]), 218 | }, scene); 219 | 220 | const left = RibbonBuilder.CreateRibbon("leftWall", { 221 | pathArray: trackPoints.map(p => [p.leftFlat, p.leftWallInside, p.leftWallOutside]), 222 | uvs: this._createUVs(trackPoints, [0, 0.8, 1]), 223 | }, scene); 224 | 225 | right.material = assets.trackWallMaterial; 226 | right.parent = walls; 227 | Tags.AddTagsTo(right, "wall"); 228 | 229 | left.material = assets.trackWallMaterial; 230 | left.parent = walls; 231 | Tags.AddTagsTo(left, "wall"); 232 | } 233 | 234 | private _createGoal(scene: Scene, assets: Assets, trackPoints: Array): void { 235 | const indices = [0, 1]; 236 | const goal = RibbonBuilder.CreateRibbon("goal", { 237 | pathArray: indices.map(index => [trackPoints[index].rightEdge, trackPoints[index].leftEdge]) 238 | }, scene); 239 | 240 | goal.material = assets.trackGoalMaterial; 241 | goal.parent = this._track; 242 | } 243 | 244 | private _createUVs(trackPoints: Array, us: Array): Array { 245 | let totalDistance = 0; 246 | let lastTrackPoint: Nullable = null; 247 | const uvs = new Array(); 248 | 249 | for (const trackPoint of trackPoints) { 250 | if (lastTrackPoint) { 251 | totalDistance += Vector3.Distance(lastTrackPoint.point, trackPoint.point); 252 | } 253 | 254 | for (const u of us) { 255 | uvs.push(new Vector2(u, totalDistance)); 256 | } 257 | 258 | lastTrackPoint = trackPoint; 259 | } 260 | 261 | for (const uv of uvs) { 262 | uv.y /= totalDistance; 263 | } 264 | 265 | return uvs; 266 | } 267 | 268 | private _createTrees(scene: Scene, assets: Assets, trackPoints: Array): void { 269 | const trees = new TransformNode("trees", scene); 270 | trees.parent = this._track; 271 | const treePoints = this._getTreePoints(trackPoints, 0.9, 10.0, 7.0); 272 | for (const treePoint of treePoints) { 273 | const instance = assets.tree.mesh.createInstance("tree"); 274 | instance.isPickable = false; 275 | instance.position.copyFrom(treePoint); 276 | instance.rotation.y = this._random() * Scalar.TwoPi; 277 | instance.parent = trees; 278 | } 279 | } 280 | 281 | private _createHazards(scene: Scene, assets: Assets, trackPoints: Array): void { 282 | const hazards = new TransformNode("hazards", scene); 283 | hazards.parent = this._track; 284 | const bombHazards = new TransformNode("bombs", scene); 285 | bombHazards.parent = hazards; 286 | const boostHazards = new TransformNode("boosts", scene); 287 | boostHazards.parent = hazards; 288 | const bumperHazards = new TransformNode("bumpers", scene); 289 | bumperHazards.parent = hazards; 290 | const poisonHazards = new TransformNode("poison", scene); 291 | poisonHazards.parent = hazards; 292 | 293 | const createHazard = (name: string, assetInfo: IAssetInfo, point: { position: Vector3, rotation: Quaternion }, group: TransformNode, hazardScale: number): void => { 294 | const transformNode = new TransformNode(name, scene); 295 | transformNode.position.copyFrom(point.position); 296 | transformNode.rotationQuaternion = new Quaternion().copyFrom(point.rotation); 297 | transformNode.scaling.scaleInPlace(hazardScale); 298 | transformNode.parent = group; 299 | 300 | const instance = assetInfo.mesh.createInstance("instance"); 301 | instance.isPickable = false; 302 | instance.parent = transformNode; 303 | 304 | const animationGroups = assetInfo.animationGroups; 305 | if (animationGroups.length > 0) { 306 | const animationGroup = animationGroups[Math.floor(this._random() * animationGroups.length)]; 307 | const animationGroupClone = animationGroup.clone(animationGroup.name, () => instance); 308 | animationGroupClone.play(true); 309 | animationGroupClone.goToFrame(this._random(animationGroup.from, animationGroup.to)); 310 | this._animationGroups.push(animationGroupClone); 311 | } 312 | }; 313 | 314 | const hazardPoints = this._getHazardPoints(1.5, 0.13, trackPoints); 315 | for (const hazardPoint of hazardPoints) { 316 | const hazardType = this._random(); 317 | if (hazardType < 0.2) { 318 | createHazard("bomb", assets.bomb, hazardPoint, bombHazards, 0.2); 319 | } 320 | else if (hazardType < 0.6) { 321 | createHazard("boost", assets.boost, hazardPoint, boostHazards, 8); 322 | } 323 | else if (hazardType < 0.8) { 324 | createHazard("bumper", assets.bumper, hazardPoint, bumperHazards, 4); 325 | } 326 | else { 327 | createHazard("poison", assets.poison, hazardPoint, poisonHazards, 4); 328 | } 329 | } 330 | } 331 | 332 | private _getHazardPoints(height: number, density: number, trackPoints: Array): Array<{ position: Vector3, rotation: Quaternion }> { 333 | const hazardPoints = new Array<{ position: Vector3, rotation: Quaternion }>(); 334 | const percentageDistanceFromSides = .1; 335 | for (let index = 3; index < trackPoints.length - 1; ++index) { 336 | const trackPoint = trackPoints[index]; 337 | const leftSide = trackPoint.leftEdge; 338 | const rightSide = trackPoint.rightEdge; 339 | 340 | const direction = rightSide.subtract(leftSide); 341 | if (this._random() < density) { 342 | const distance = (this._random() * (1 - percentageDistanceFromSides * 2) + percentageDistanceFromSides); 343 | const positionHazard = leftSide.add(direction.scale(distance)); 344 | positionHazard.y += height; 345 | hazardPoints.push({ 346 | position: positionHazard, 347 | rotation: Quaternion.RotationQuaternionFromAxis(trackPoint.right.scale(-1), trackPoint.up, trackPoint.forward.scale(-1)) 348 | }); 349 | } 350 | } 351 | return hazardPoints; 352 | } 353 | 354 | private _getControlPoints(numPoints: number, radius: number, lateralVariance: number, heightVariance: number): Array { 355 | const points = new Array(numPoints); 356 | const reverse = this._random() < 0.5; 357 | 358 | for (let index = 0; index < numPoints; ++index) { 359 | const angle = (reverse ? (numPoints - 1 - index) : index) / numPoints * Scalar.TwoPi; 360 | const pert = this._random() * lateralVariance - lateralVariance / 2; 361 | const x = (radius + pert) * Math.sin(angle); 362 | const y = this._random() * heightVariance - heightVariance / 2; 363 | const z = (radius + pert) * Math.cos(angle); 364 | points[index] = new Vector3(x, y, z); 365 | } 366 | 367 | return points; 368 | } 369 | 370 | private _getCurve(controlPoints: Array, numPoints: number): Curve3 { 371 | const points = new Array(); 372 | const count = controlPoints.length; 373 | const step = 1 / numPoints; 374 | 375 | for (let index = 0; index < count; ++index) { 376 | for (let i = 0, amount = 0; i < numPoints; ++i, amount += step) { 377 | points.push(Vector3.CatmullRom( 378 | controlPoints[(index + count - 1) % count], 379 | controlPoints[(index + count + 0) % count], 380 | controlPoints[(index + count + 1) % count], 381 | controlPoints[(index + count + 2) % count], 382 | amount 383 | )); 384 | } 385 | } 386 | 387 | return new Curve3(points); 388 | } 389 | 390 | private _getTreePoints(trackPoints: Array, density: number, width: number, offset: number): Array { 391 | const trees = new Array(); 392 | for (const trackPoint of trackPoints) { 393 | const leftSide = trackPoint.leftFlat; 394 | const rightSide = trackPoint.rightFlat; 395 | 396 | const direction = rightSide.subtract(leftSide).normalize(); 397 | direction.y = 0; 398 | 399 | if (this._random() < density) { 400 | const distanceFromPath = this._random() * width + offset; 401 | trees.push(rightSide.add(direction.scale(distanceFromPath))); 402 | } 403 | 404 | if (this._random() < density) { 405 | const distanceFromPath = this._random() * width + offset; 406 | trees.push(leftSide.subtract(direction.scale(distanceFromPath))); 407 | } 408 | } 409 | 410 | // Delete trees that are generated too close to each other. 411 | const offsetSquared = offset * offset; 412 | const spacedTrees = new Array(); 413 | for (const tree of trees) { 414 | if (!spacedTrees.some(spacedTree => Vector3.DistanceSquared(tree, spacedTree) < offsetSquared)) { 415 | spacedTrees.push(tree); 416 | } 417 | } 418 | 419 | return spacedTrees; 420 | } 421 | 422 | private _updateTextures(material: PBRMaterial, vScale: number): void { 423 | (material.albedoTexture as Texture).vScale = vScale; 424 | (material.bumpTexture as Texture).vScale = vScale; 425 | (material.metallicTexture as Texture).vScale = vScale; 426 | } 427 | 428 | // https://stackoverflow.com/a/19303725/11256124 429 | private _random(from = 0, to = 1): number { 430 | const x = Math.sin(this._varianceSeed++) * 10000; 431 | return from + (x - Math.floor(x)) * (to - from); 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babylon-kart-racer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack --watch --mode=development --info-verbosity=verbose" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.16.4", 13 | "glob": "^7.1.4", 14 | "socket.io": "^2.2.0" 15 | }, 16 | "devDependencies": { 17 | "@babylonjs/core": "^4.0.3", 18 | "@babylonjs/gui": "^4.0.3", 19 | "@babylonjs/inspector": "^4.0.3", 20 | "@babylonjs/loaders": "^4.0.3", 21 | "@types/express": "^4.16.1", 22 | "@types/socket.io": "^2.1.2", 23 | "acorn": "^6.1.1", 24 | "nodemon": "^1.19.0", 25 | "nodemon-webpack-plugin": "^4.0.8", 26 | "ts-loader": "^6.0.0", 27 | "typescript": "^3.4.5", 28 | "webpack": "^4.31.0", 29 | "webpack-cli": "^3.3.2", 30 | "webpack-node-externals": "^1.7.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/environment/environment.env: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/environment/environment.env -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BabylonJS 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/models/bomb/bomb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bomb/bomb.bin -------------------------------------------------------------------------------- /public/models/bomb/bomb.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[-1.18207014,-0.4510684,0.40482834],"rotation":[-0.00194398616,0.03222658,0.0601816028,0.997665167],"scale":[1.0,1.0,1.0],"name":"skullbomb_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"skullbomb_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":2322,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":499,"max":[4.472966,9.664078,5.42981052],"min":[-4.464872,-4.681548,-5.378503],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":5988,"componentType":5126,"count":499,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":499,"type":"VEC2","name":"accessorUVs"},{"bufferView":3,"componentType":5126,"count":263,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":4,"componentType":5126,"count":263,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":3,"byteOffset":1052,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":5,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"}],"bufferViews":[{"buffer":0,"byteLength":4644,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":4644,"byteLength":11976,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":16620,"byteLength":3992,"byteStride":8,"name":"bufferViewFloatVec2"},{"buffer":0,"byteOffset":20612,"byteLength":2256,"name":"bufferViewAnimationFloatScalar"},{"buffer":0,"byteOffset":22868,"byteLength":4208,"name":"bufferViewAnimationFloatVec4"},{"buffer":0,"byteOffset":27076,"byteLength":3612,"name":"bufferViewAnimationFloatVec3"}],"buffers":[{"uri":"bomb.bin","byteLength":30688}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":2,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":1,"texCoord":0}},"normalTexture":{"index":0,"texCoord":0},"occlusionTexture":{"index":1,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"skullbombMat"}],"textures":[{"sampler":0,"source":0,"name":"bomb_skullbombMat_Normal.png"},{"sampler":1,"source":1,"name":"bomb_skullbombMat_ORM.png"},{"sampler":2,"source":2,"name":"bomb_skullbombMat_basecolor.png"}],"images":[{"uri":"bomb_skullbombMat_Normal.png"},{"uri":"bomb_skullbombMat_ORM.png"},{"uri":"bomb_skullbombMat_basecolor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}],"animations":[{"channels":[{"sampler":0,"target":{"node":0,"path":"rotation"}},{"sampler":1,"target":{"node":0,"path":"translation"}}],"samplers":[{"input":4,"interpolation":"LINEAR","output":5},{"input":6,"interpolation":"LINEAR","output":7}],"name":"bombHover"}]} -------------------------------------------------------------------------------- /public/models/bomb/bomb_skullbombMat_Normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bomb/bomb_skullbombMat_Normal.png -------------------------------------------------------------------------------- /public/models/bomb/bomb_skullbombMat_ORM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bomb/bomb_skullbombMat_ORM.png -------------------------------------------------------------------------------- /public/models/bomb/bomb_skullbombMat_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bomb/bomb_skullbombMat_basecolor.png -------------------------------------------------------------------------------- /public/models/bumper/bumper.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bumper/bumper.bin -------------------------------------------------------------------------------- /public/models/bumper/bumper.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "version": "2.0", 4 | "generator": "Microsoft GLTF Exporter 2.4.2.8" 5 | }, 6 | "accessors": [ 7 | { 8 | "bufferView": 0, 9 | "componentType": 5123, 10 | "count": 28092, 11 | "type": "SCALAR" 12 | }, 13 | { 14 | "bufferView": 1, 15 | "componentType": 5126, 16 | "count": 5221, 17 | "type": "VEC3", 18 | "max": [ 19 | 1.379180908203125, 20 | 2.0508642196655273, 21 | 1.123117208480835 22 | ], 23 | "min": [ 24 | -1.379180908203125, 25 | 0.0, 26 | -1.123117208480835 27 | ] 28 | }, 29 | { 30 | "bufferView": 2, 31 | "componentType": 5126, 32 | "count": 5221, 33 | "type": "VEC3" 34 | }, 35 | { 36 | "bufferView": 3, 37 | "componentType": 5126, 38 | "count": 5221, 39 | "type": "VEC2" 40 | } 41 | ], 42 | "bufferViews": [ 43 | { 44 | "buffer": 0, 45 | "byteOffset": 0, 46 | "byteLength": 56184, 47 | "target": 34963 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteOffset": 56184, 52 | "byteLength": 62652, 53 | "target": 34962 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteOffset": 118836, 58 | "byteLength": 62652, 59 | "target": 34962 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteOffset": 181488, 64 | "byteLength": 41768, 65 | "target": 34962 66 | } 67 | ], 68 | "buffers": [ 69 | { 70 | "byteLength": 223256, 71 | "uri": "bumper.bin" 72 | } 73 | ], 74 | "images": [ 75 | { 76 | "uri": "bumper_image0.png" 77 | }, 78 | { 79 | "uri": "bumper_image1.png" 80 | }, 81 | { 82 | "uri": "bumper_image2.png" 83 | }, 84 | { 85 | "uri": "bumper_image3.png" 86 | } 87 | ], 88 | "materials": [ 89 | { 90 | "pbrMetallicRoughness": { 91 | "baseColorTexture": { 92 | "index": 2 93 | }, 94 | "metallicRoughnessTexture": { 95 | "index": 3 96 | } 97 | }, 98 | "alphaMode": "MASK", 99 | "name": "42", 100 | "doubleSided": true, 101 | "extensions": { 102 | "KHR_materials_pbrSpecularGlossiness": { 103 | "diffuseTexture": { 104 | "index": 0 105 | }, 106 | "specularGlossinessTexture": { 107 | "index": 1 108 | } 109 | } 110 | }, 111 | "extras": { 112 | "MSFT_sRGBFactors": false 113 | } 114 | } 115 | ], 116 | "meshes": [ 117 | { 118 | "name": "mesh_id31", 119 | "primitives": [ 120 | { 121 | "attributes": { 122 | "POSITION": 1, 123 | "NORMAL": 2, 124 | "TEXCOORD_0": 3 125 | }, 126 | "indices": 0, 127 | "material": 0 128 | } 129 | ] 130 | } 131 | ], 132 | "nodes": [ 133 | { 134 | "children": [ 135 | 1 136 | ], 137 | "name": "root" 138 | }, 139 | { 140 | "translation": [ 141 | 0.0, 142 | -0.19033806025981903, 143 | 0.25600001215934753 144 | ], 145 | "scale": [ 146 | 0.18561743199825287, 147 | 0.18561743199825287, 148 | 0.18561743199825287 149 | ], 150 | "mesh": 0, 151 | "name": "node_id30" 152 | } 153 | ], 154 | "samplers": [ 155 | { 156 | "minFilter": 9985 157 | } 158 | ], 159 | "scenes": [ 160 | { 161 | "nodes": [ 162 | 0 163 | ] 164 | } 165 | ], 166 | "scene": 0, 167 | "textures": [ 168 | { 169 | "name": "texture5", 170 | "sampler": 0, 171 | "source": 0 172 | }, 173 | { 174 | "name": "texture7", 175 | "sampler": 0, 176 | "source": 1 177 | }, 178 | { 179 | "name": "42_bc", 180 | "sampler": 0, 181 | "source": 2 182 | }, 183 | { 184 | "name": "42_mr", 185 | "sampler": 0, 186 | "source": 3 187 | } 188 | ], 189 | "extensionsUsed": [ 190 | "KHR_materials_pbrSpecularGlossiness" 191 | ] 192 | } -------------------------------------------------------------------------------- /public/models/bumper/bumper_image0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bumper/bumper_image0.png -------------------------------------------------------------------------------- /public/models/bumper/bumper_image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bumper/bumper_image1.png -------------------------------------------------------------------------------- /public/models/bumper/bumper_image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bumper/bumper_image2.png -------------------------------------------------------------------------------- /public/models/bumper/bumper_image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/bumper/bumper_image3.png -------------------------------------------------------------------------------- /public/models/camp/campMesh.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/camp/campMesh.bin -------------------------------------------------------------------------------- /public/models/camp/camp_baseColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/camp/camp_baseColor.png -------------------------------------------------------------------------------- /public/models/evergreen2/evergreen2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/evergreen2/evergreen2.bin -------------------------------------------------------------------------------- /public/models/evergreen2/evergreen2.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"evergreen2_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"evergreen2_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":1308,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":919,"max":[5.16411829,16.7655487,4.44892073],"min":[-4.031206,-2.525704,-5.16537857],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":11028,"componentType":5126,"count":919,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":919,"type":"VEC2","name":"accessorUVs"}],"bufferViews":[{"buffer":0,"byteLength":2616,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":2616,"byteLength":22056,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":24672,"byteLength":7352,"byteStride":8,"name":"bufferViewFloatVec2"}],"buffers":[{"uri":"evergreen2.bin","byteLength":32024}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0.0,"roughnessFactor":0.6853147},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"evergreenMat"}],"textures":[{"sampler":0,"source":0,"name":"evergreen_baseColor.png"}],"images":[{"uri":"evergreen_baseColor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}]} -------------------------------------------------------------------------------- /public/models/evergreen2/evergreen_baseColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/evergreen2/evergreen_baseColor.png -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/poison_cloud/poison_cloud.bin -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "version": "2.0", 4 | "generator": "Microsoft GLTF Exporter 2.4.2.8" 5 | }, 6 | "accessors": [ 7 | { 8 | "bufferView": 0, 9 | "componentType": 5123, 10 | "count": 56634, 11 | "type": "SCALAR" 12 | }, 13 | { 14 | "bufferView": 1, 15 | "componentType": 5126, 16 | "count": 9449, 17 | "type": "VEC3", 18 | "max": [ 19 | 0.49936172366142273, 20 | 0.49875041842460632, 21 | 0.27806130051612854 22 | ], 23 | "min": [ 24 | -0.49957042932510376, 25 | -0.49811425805091858, 26 | -0.27806130051612854 27 | ] 28 | }, 29 | { 30 | "bufferView": 2, 31 | "componentType": 5126, 32 | "count": 9449, 33 | "type": "VEC3" 34 | } 35 | ], 36 | "bufferViews": [ 37 | { 38 | "buffer": 0, 39 | "byteOffset": 0, 40 | "byteLength": 113268, 41 | "target": 34963 42 | }, 43 | { 44 | "buffer": 0, 45 | "byteOffset": 113268, 46 | "byteLength": 113388, 47 | "target": 34962 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteOffset": 226656, 52 | "byteLength": 113388, 53 | "target": 34962 54 | } 55 | ], 56 | "buffers": [ 57 | { 58 | "byteLength": 340044, 59 | "uri": "poison_cloud.bin" 60 | } 61 | ], 62 | "images": [ 63 | { 64 | "uri": "poison_cloud_image0.png" 65 | }, 66 | { 67 | "uri": "poison_cloud_image1.png" 68 | }, 69 | { 70 | "uri": "poison_cloud_image2.png" 71 | }, 72 | { 73 | "uri": "poison_cloud_image3.png" 74 | } 75 | ], 76 | "materials": [ 77 | { 78 | "pbrMetallicRoughness": { 79 | "baseColorTexture": { 80 | "index": 2 81 | }, 82 | "metallicRoughnessTexture": { 83 | "index": 3 84 | } 85 | }, 86 | "alphaMode": "MASK", 87 | "name": "47", 88 | "doubleSided": true, 89 | "extensions": { 90 | "KHR_materials_pbrSpecularGlossiness": { 91 | "diffuseTexture": { 92 | "index": 0 93 | }, 94 | "specularGlossinessTexture": { 95 | "index": 1 96 | } 97 | } 98 | }, 99 | "extras": { 100 | "MSFT_sRGBFactors": false 101 | } 102 | } 103 | ], 104 | "meshes": [ 105 | { 106 | "name": "mesh_id31", 107 | "primitives": [ 108 | { 109 | "attributes": { 110 | "POSITION": 1, 111 | "NORMAL": 2 112 | }, 113 | "indices": 0, 114 | "material": 0 115 | } 116 | ] 117 | } 118 | ], 119 | "nodes": [ 120 | { 121 | "children": [ 122 | 1 123 | ], 124 | "name": "root" 125 | }, 126 | { 127 | "translation": [ 128 | 5.5532695114379749E-05, 129 | -8.8432316260878E-05, 130 | 0.25601547956466675 131 | ], 132 | "rotation": [ 133 | -0.02848103828728199, 134 | -0.09679432213306427, 135 | 0.039603069424629211, 136 | 0.99410831928253174 137 | ], 138 | "scale": [ 139 | 0.47726601362228394, 140 | 0.29263660311698914, 141 | 0.22452417016029358 142 | ], 143 | "mesh": 0, 144 | "name": "node_id30" 145 | } 146 | ], 147 | "samplers": [ 148 | { 149 | "minFilter": 9985 150 | } 151 | ], 152 | "scenes": [ 153 | { 154 | "nodes": [ 155 | 0 156 | ] 157 | } 158 | ], 159 | "scene": 0, 160 | "textures": [ 161 | { 162 | "name": "texture156", 163 | "sampler": 0, 164 | "source": 0 165 | }, 166 | { 167 | "name": "texture157", 168 | "sampler": 0, 169 | "source": 1 170 | }, 171 | { 172 | "name": "47_bc", 173 | "sampler": 0, 174 | "source": 2 175 | }, 176 | { 177 | "name": "47_mr", 178 | "sampler": 0, 179 | "source": 3 180 | } 181 | ], 182 | "extensionsUsed": [ 183 | "KHR_materials_pbrSpecularGlossiness" 184 | ] 185 | } -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud_image0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/poison_cloud/poison_cloud_image0.png -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud_image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/poison_cloud/poison_cloud_image1.png -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud_image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/poison_cloud/poison_cloud_image2.png -------------------------------------------------------------------------------- /public/models/poison_cloud/poison_cloud_image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/poison_cloud/poison_cloud_image3.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_ORM1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_ORM1.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_ORM2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_ORM2.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_ORM3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_ORM3.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_baseColor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_baseColor1.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_baseColor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_baseColor2.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_baseColor3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_baseColor3.png -------------------------------------------------------------------------------- /public/models/roadsterKart/driverBodyMat_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/driverBodyMat_normal.png -------------------------------------------------------------------------------- /public/models/roadsterKart/engineWheels_roadsterWheelsMat_ORM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/engineWheels_roadsterWheelsMat_ORM.png -------------------------------------------------------------------------------- /public/models/roadsterKart/engineWheels_roadsterWheelsMat_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/engineWheels_roadsterWheelsMat_basecolor.png -------------------------------------------------------------------------------- /public/models/roadsterKart/engineWheels_roadsterWheelsMat_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/engineWheels_roadsterWheelsMat_normal.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_ORM1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_ORM1.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_ORM2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_ORM2.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_ORM3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_ORM3.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_baseColor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_baseColor1.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_baseColor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_baseColor2.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_baseColor3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_baseColor3.png -------------------------------------------------------------------------------- /public/models/roadsterKart/kartBodyMat_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/kartBodyMat_normal.png -------------------------------------------------------------------------------- /public/models/roadsterKart/roadsterKart.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/roadsterKart/roadsterKart.bin -------------------------------------------------------------------------------- /public/models/roadsterKart/roadsterKart.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.31"},"scene":0,"scenes":[{"nodes":[0,2,38,40,41,42,43,44,45],"extensions":{}}],"nodes":[{"children":[1,11,14,20],"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"carBody_low"},{"skin":0,"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"rollCage_low"},{"children":[3,34,35,36,37],"translation":[5.360625E-15,-0.00219974876,-0.104689516],"rotation":[0.7071065,0.7071064,0.000705647,-0.0007056468],"scale":[0.9999999,0.99999994,0.9999999],"name":"carPosition"},{"children":[4,10,15,18,27,32,33],"translation":[8.712237,5.914722E-15,3.12335851E-19],"rotation":[0.0,0.7071067,0.0,0.7071068],"scale":[0.9969883,0.9969884,0.9969883],"name":"bodyAttach"},{"children":[5],"translation":[-3.99543071,1.55253675E-15,7.02451324],"rotation":[0.0,-0.748468637,0.0,0.6631702],"scale":[1.00302052,1.00302064,1.00302052],"name":"hips"},{"children":[6,8,9],"translation":[8.499517,2.10278047E-15,-2.553513E-15],"rotation":[-0.705328,-0.0501253046,-0.0501253046,0.705327868],"scale":[1.0,1.0,1.00000024],"name":"sternum"},{"children":[7],"translation":[3.18486142,1.03604644E-15,6.661338E-16],"rotation":[0.703970969,0.06651959,0.06651959,0.703970969],"scale":[1.0,1.0,0.9999999],"name":"neck"},{"translation":[5.76057625,-1.18017626E-14,-4.432298E-15],"rotation":[-0.48111698,-0.5181954,0.5181954,-0.48111698],"scale":[1.0,1.0,1.0],"name":"head"},{"children":[12],"translation":[2.14761424,-0.490193069,6.688917],"rotation":[0.239769638,0.953606248,-0.14512445,-0.1099297],"scale":[1.0,1.0,0.9999999],"name":"armL"},{"children":[13],"translation":[2.147634,-0.4901847,-5.96252251],"rotation":[0.806481957,-0.2823967,-0.02844882,0.518680632],"scale":[1.0,1.0,1.00000012],"name":"armR"},{"translation":[-13.9568377,6.17809145E-15,15.3363886],"rotation":[0.7071067,0.0,0.0,0.7071068],"scale":[1.00302064,1.00302041,1.00302041],"name":"customAttachTop"},{"skin":1,"mesh":1,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"seat_low"},{"children":[16],"translation":[7.05611324,-2.108071E-15,2.675843E-15],"rotation":[0.0,-0.134845942,0.6444477,0.752664447],"scale":[1.0,1.0,1.0],"name":"elbowL"},{"children":[17],"translation":[-7.05608,-6.89226454E-13,-1.73194792E-13],"rotation":[0.0,-0.6688749,-0.0493411571,0.741735637],"scale":[0.9999999,1.0,0.9999999],"name":"elbowR"},{"skin":2,"mesh":2,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"wheelDash_low"},{"children":[21,24],"translation":[20.2500725,-3.55271368E-15,-1.80412046E-15],"rotation":[-0.7056936,0.7085165,-0.0007098597,0.0007014085],"scale":[1.00302076,1.00302088,1.00302088],"name":"frontAxle"},{"translation":[7.22682571,-8.58189E-16,-2.288504E-16],"rotation":[0.7079211,-0.133242309,-0.503944755,0.4765857],"scale":[0.9999999,0.99999994,1.0],"name":"handL"},{"translation":[-7.2269,-7.034373E-13,-1.74971149E-13],"rotation":[0.9178011,0.189659238,-0.310033023,-0.159843966],"scale":[1.0,1.0,1.0],"name":"handR"},{"children":[19],"translation":[12.3947315,1.54238933E-09,11.3463631],"rotation":[0.06258853,0.7043314,0.704331338,-0.06258853],"scale":[1.00302076,1.00302076,1.00302064],"name":"steeringColumn"},{"translation":[7.055435,-1.61886493E-15,2.0701747E-09],"rotation":[0.011776912,0.9999307,2.1951621E-08,2.58540245E-10],"scale":[0.9999999,0.9999999,0.9999999],"name":"steeringWheel"},{"skin":3,"mesh":3,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"roadsterBody_low"},{"children":[22],"translation":[-14.1891727,0.0566463135,-0.0002261162],"rotation":[-0.001417089,-0.7071054,0.7071054,0.00140582072],"scale":[1.0,1.0,0.99999994],"name":"suspensionFrontL"},{"children":[23],"translation":[2.366152,-6.08541E-15,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"turnFrontL"},{"translation":[1.36573124,6.190187E-14,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"rotateFrontL"},{"children":[25],"translation":[14.189187,-0.0566461757,0.000228109842],"rotation":[0.001405821,0.7071054,0.7071054,0.00141708879],"scale":[1.0,1.0,0.99999994],"name":"suspensionFrontR"},{"children":[26],"translation":[-2.3661,-1.77635684E-15,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"turnFrontR"},{"translation":[-1.3658,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"rotateFrontR"},{"children":[28,30],"translation":[-22.67931,7.10542736E-15,-0.2362317],"rotation":[0.0,-5.41724148E-07,-0.706971049,0.7072425],"scale":[1.00302076,1.00302076,1.00302064],"name":"rearAxle"},{"children":[29],"translation":[14.2709188,7.272995E-15,2.16699488E-15],"rotation":[-5.08844E-06,3.10312167E-08,0.9999937,0.00354797556],"scale":[0.999999762,0.999999762,1.0],"name":"suspensionRearR"},{"translation":[-4.71535826,-0.009921333,0.150371954],"rotation":[-0.00251489226,0.707807362,0.706396639,-0.00250269123],"scale":[1.00000012,0.99999994,1.0],"name":"rotateRearR"},{"children":[31],"translation":[-14.2708969,0.0109485071,1.96261844E-05],"rotation":[0.001995117,-1.06145326E-05,0.00315889553,0.999992967],"scale":[1.0,1.0,0.9999999],"name":"suspensionRearL"},{"translation":[-4.55698872,0.010447843,0.1507041],"rotation":[0.706397653,-0.002228406,-0.0022389607,0.7078082],"scale":[1.0,1.0,1.0],"name":"rotateRearL"},{"translation":[-24.035265,1.06738018E-14,9.122121],"rotation":[0.7071067,0.0,0.0,0.7071068],"scale":[1.00302064,1.00302041,1.00302041],"name":"customAttachEngine"},{"translation":[-34.7605743,1.5436796E-14,-0.7998046],"rotation":[0.7071067,0.0,0.0,0.7071068],"scale":[1.00302064,1.00302041,1.00302041],"name":"customAttachExhaust"},{"translation":[8.93944,-18.41473,-29.01204],"rotation":[0.7071067,0.0,0.0,0.7071068],"scale":[1.0,0.9999999,0.9999999],"name":"raycast_FrontR"},{"translation":[8.819337,-20.3876934,31.1632023],"rotation":[0.7071067,0.0,0.0,0.7071068],"scale":[1.0,0.9999999,0.9999999],"name":"raycast_RearR"},{"translation":[8.939442,18.4147,-29.0120163],"rotation":[-4.329781E-17,-0.707106769,0.707106769,-4.32978063E-17],"scale":[0.999999762,0.9999999,0.9999999],"name":"raycast_FrontL"},{"translation":[8.81934,20.3877,31.1631641],"rotation":[-4.329781E-17,-0.707106769,0.707106769,-4.32978063E-17],"scale":[0.999999762,0.9999999,0.9999999],"name":"raycast_RearL"},{"children":[39],"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"wheelsEngine"},{"skin":4,"mesh":4,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"wheels_low"},{"skin":5,"mesh":5,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"engineExhaust_low"},{"skin":6,"mesh":6,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"driver_low"},{"mesh":7,"translation":[-37.1109047,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1E-12,1E-12,1E-12],"name":"driverMat2"},{"mesh":8,"translation":[-37.1109047,1E-24,1E-24],"rotation":[0.0,0.0,0.0,1.0],"scale":[1E-12,1E-12,1E-12],"name":"driverMat3"},{"mesh":9,"translation":[-37.1109047,1E-24,1E-24],"rotation":[0.0,0.0,0.0,1.0],"scale":[1E-12,1E-12,1E-12],"name":"bodyMat2"},{"mesh":10,"translation":[-37.1109047,1E-24,1E-24],"rotation":[0.0,0.0,0.0,1.0],"scale":[1E-12,1E-12,1E-12],"name":"bodyMat3"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TANGENT":3,"TEXCOORD_0":4,"JOINTS_0":5,"WEIGHTS_0":6},"indices":0,"mode":4,"material":0}],"name":"rollCage_low"},{"primitives":[{"attributes":{"POSITION":8,"NORMAL":9,"TANGENT":10,"TEXCOORD_0":11,"JOINTS_0":12,"WEIGHTS_0":13},"indices":7,"mode":4,"material":0}],"name":"seat_low"},{"primitives":[{"attributes":{"POSITION":15,"NORMAL":16,"TANGENT":17,"TEXCOORD_0":18,"JOINTS_0":19,"WEIGHTS_0":20},"indices":14,"mode":4,"material":0}],"name":"wheelDash_low"},{"primitives":[{"attributes":{"POSITION":22,"NORMAL":23,"TANGENT":24,"TEXCOORD_0":25,"JOINTS_0":26,"WEIGHTS_0":27},"indices":21,"mode":4,"material":0}],"name":"roadsterBody_low"},{"primitives":[{"attributes":{"POSITION":29,"NORMAL":30,"TANGENT":31,"TEXCOORD_0":32,"JOINTS_0":33,"WEIGHTS_0":34},"indices":28,"mode":4,"material":1}],"name":"wheels_low"},{"primitives":[{"attributes":{"POSITION":36,"NORMAL":37,"TANGENT":38,"TEXCOORD_0":39,"JOINTS_0":40,"WEIGHTS_0":41},"indices":35,"mode":4,"material":1}],"name":"engineExhaust_low"},{"primitives":[{"attributes":{"POSITION":43,"NORMAL":44,"TANGENT":45,"TEXCOORD_0":46,"JOINTS_0":47,"WEIGHTS_0":48},"indices":42,"mode":4,"material":2}],"name":"driver_low"},{"primitives":[{"attributes":{"POSITION":50,"NORMAL":51,"TANGENT":52,"TEXCOORD_0":53},"indices":49,"mode":4,"material":3}],"name":"driverMat2"},{"primitives":[{"attributes":{"POSITION":55,"NORMAL":56,"TANGENT":57,"TEXCOORD_0":58},"indices":54,"mode":4,"material":4}],"name":"driverMat3"},{"primitives":[{"attributes":{"POSITION":60,"NORMAL":61,"TANGENT":62,"TEXCOORD_0":63},"indices":59,"mode":4,"material":5}],"name":"bodyMat2"},{"primitives":[{"attributes":{"POSITION":65,"NORMAL":66,"TANGENT":67,"TEXCOORD_0":68},"indices":64,"mode":4,"material":6}],"name":"bodyMat3"}],"accessors":[{"bufferView":0,"componentType":5123,"count":432,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":90,"max":[6.119133,34.17623,-12.14946],"min":[-6.119131,22.1628761,-17.3943329],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":1080,"componentType":5126,"count":90,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":90,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"componentType":5126,"count":90,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"componentType":5123,"count":90,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":1440,"componentType":5126,"count":90,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":864,"componentType":5123,"count":636,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":2160,"componentType":5126,"count":156,"max":[8.880552,26.2391033,1.9979316],"min":[-8.880552,11.9338455,-12.3086147],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":4032,"componentType":5126,"count":156,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":2880,"componentType":5126,"count":156,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":720,"componentType":5126,"count":156,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":720,"componentType":5123,"count":156,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":5376,"componentType":5126,"count":156,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":2136,"componentType":5123,"count":1314,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":5904,"componentType":5126,"count":290,"max":[10.2628746,28.1323624,14.4225616],"min":[-10.2628746,14.6800976,3.25972939],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":9384,"componentType":5126,"count":290,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":7872,"componentType":5126,"count":290,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":1968,"componentType":5126,"count":290,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":1968,"componentType":5123,"count":290,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":12512,"componentType":5126,"count":290,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":4764,"componentType":5123,"count":2694,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":12864,"componentType":5126,"count":593,"max":[22.33614,24.9406147,35.9043961],"min":[-22.33614,4.43964243,-39.7395363],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":19980,"componentType":5126,"count":593,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":17152,"componentType":5126,"count":593,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":4288,"componentType":5126,"count":593,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":4288,"componentType":5123,"count":593,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":26640,"componentType":5126,"count":593,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":10152,"componentType":5123,"count":6912,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":27096,"componentType":5126,"count":2004,"max":[23.3216858,17.811512,29.2677],"min":[-23.3216858,-0.188488,-31.7009583],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":51144,"componentType":5126,"count":2004,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":36128,"componentType":5126,"count":2004,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":9032,"componentType":5126,"count":2004,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":9032,"componentType":5123,"count":2004,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":68192,"componentType":5126,"count":2004,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":23976,"componentType":5123,"count":1914,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":75192,"componentType":5126,"count":734,"max":[14.2993355,27.7442055,32.03943],"min":[-14.2993355,4.84796429,-41.3552],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":84000,"componentType":5126,"count":734,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":100256,"componentType":5126,"count":734,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":25064,"componentType":5126,"count":734,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":25064,"componentType":5123,"count":734,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":112000,"componentType":5126,"count":734,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":27804,"componentType":5123,"count":2316,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":92808,"componentType":5126,"count":624,"max":[9.380848,45.7697525,8.790852],"min":[-9.160623,11.866374,-15.9848728],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":100296,"componentType":5126,"count":624,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":123744,"componentType":5126,"count":624,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":30936,"componentType":5126,"count":624,"type":"VEC2","name":"accessorUVs"},{"bufferView":4,"byteOffset":30936,"componentType":5123,"count":624,"type":"VEC4","name":"accessorJoints"},{"bufferView":2,"byteOffset":133728,"componentType":5126,"count":624,"type":"VEC4","name":"accessorWeights"},{"bufferView":0,"byteOffset":32436,"componentType":5123,"count":6,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":107784,"componentType":5126,"count":4,"max":[0.5,0.0,0.5],"min":[-0.5,0.0,-0.5],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":107832,"componentType":5126,"count":4,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":143712,"componentType":5126,"count":4,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":35928,"componentType":5126,"count":4,"type":"VEC2","name":"accessorUVs"},{"bufferView":0,"byteOffset":32448,"componentType":5123,"count":6,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":107880,"componentType":5126,"count":4,"max":[0.5,0.0,0.5],"min":[-0.5,0.0,-0.5],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":107928,"componentType":5126,"count":4,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":143776,"componentType":5126,"count":4,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":35960,"componentType":5126,"count":4,"type":"VEC2","name":"accessorUVs"},{"bufferView":0,"byteOffset":32460,"componentType":5123,"count":6,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":107976,"componentType":5126,"count":4,"max":[0.5,0.0,0.5],"min":[-0.5,0.0,-0.5],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":108024,"componentType":5126,"count":4,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":143840,"componentType":5126,"count":4,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":35992,"componentType":5126,"count":4,"type":"VEC2","name":"accessorUVs"},{"bufferView":0,"byteOffset":32472,"componentType":5123,"count":6,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"byteOffset":108072,"componentType":5126,"count":4,"max":[0.5,0.0,0.5],"min":[-0.5,0.0,-0.5],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":108120,"componentType":5126,"count":4,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"byteOffset":143904,"componentType":5126,"count":4,"type":"VEC4","name":"accessorTangents"},{"bufferView":3,"byteOffset":36024,"componentType":5126,"count":4,"type":"VEC2","name":"accessorUVs"},{"bufferView":5,"componentType":5126,"count":9,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":576,"componentType":5126,"count":10,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":1216,"componentType":5126,"count":13,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":2048,"componentType":5126,"count":32,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":4096,"componentType":5126,"count":18,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":5248,"componentType":5126,"count":26,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":5,"byteOffset":6912,"componentType":5126,"count":15,"type":"MAT4","name":"accessorInverseBindMatrices"},{"bufferView":6,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":8,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":24,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":16,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":48,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":24,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":72,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":32,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":96,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":40,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":120,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":48,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":144,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":56,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":168,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":64,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":192,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":216,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":72,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":240,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":32,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":264,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":80,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":288,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":64,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":312,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":88,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":336,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":96,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":360,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":96,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":384,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":128,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":408,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":104,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":432,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":160,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":456,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":112,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":480,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":192,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":504,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":120,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":528,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":224,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":552,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":128,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":576,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":256,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":600,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":136,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":624,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":288,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":648,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":144,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":672,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":320,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":696,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":152,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":720,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":352,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":744,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":160,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":768,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":384,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":792,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":168,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":816,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":416,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":840,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":176,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":864,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":448,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":888,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":184,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":912,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":480,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":936,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":192,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":960,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":512,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":984,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":200,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":1008,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":544,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":1032,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":208,"componentType":5126,"count":300,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":1056,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":576,"componentType":5126,"count":300,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":4656,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":1408,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":8256,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":5376,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":8280,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":1416,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":8304,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":5408,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":8328,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":1424,"componentType":5126,"count":300,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":8352,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":5440,"componentType":5126,"count":300,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":11952,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":2624,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":15552,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":10240,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":15576,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":2632,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":15600,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":10272,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":15624,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":2640,"componentType":5126,"count":300,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":15648,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":10304,"componentType":5126,"count":300,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":19248,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":3840,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":22848,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":15104,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":22872,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":3848,"componentType":5126,"count":300,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":22896,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":15136,"componentType":5126,"count":300,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":26496,"componentType":5126,"count":300,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5048,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30096,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":19936,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30120,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5056,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30144,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":19968,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30168,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5064,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30192,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20000,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30216,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5072,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30240,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20032,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30264,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5080,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30288,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20064,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30312,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5088,"componentType":5126,"count":2,"max":[4.983333],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30336,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20096,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30360,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5096,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30384,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5104,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30408,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":5112,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30432,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5120,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30456,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":5128,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30480,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5136,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30504,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":5144,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30528,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5152,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30552,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":6,"byteOffset":5160,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30576,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20128,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30600,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5168,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30624,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20160,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30648,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5176,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30672,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20192,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30696,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5184,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30720,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20224,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":30744,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":5192,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":30768,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":20256,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":34380,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":6396,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":37992,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":25072,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":38016,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":6404,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":38040,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":25104,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":41652,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":7608,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":45264,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":29920,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":48876,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":8812,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":52488,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":34736,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":52512,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":8820,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":52536,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":34768,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":56148,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":10024,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":59760,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":39584,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":63372,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":11228,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":66984,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":44400,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":67008,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":11236,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":67032,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":44432,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":70644,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":12440,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":74256,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":49248,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":77868,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":13644,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":81480,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":54064,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":81504,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":13652,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":81528,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":54096,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":85140,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":14856,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":88752,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":58912,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":88776,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":14864,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":88800,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":58944,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":92412,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":16068,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":96024,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":63760,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":96048,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":16076,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":96072,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":63792,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":96096,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":16084,"componentType":5126,"count":301,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":96120,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":63824,"componentType":5126,"count":301,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":99732,"componentType":5126,"count":301,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17288,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103344,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68640,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103368,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17296,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103392,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68672,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103416,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17304,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103440,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68704,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103464,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17312,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103488,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68736,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103512,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17320,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103536,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68768,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103560,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17328,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103584,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68800,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103608,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17336,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103632,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68832,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103656,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17344,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103680,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68864,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103704,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17352,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103728,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68896,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103752,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17360,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103776,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68928,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103800,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17368,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103824,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68960,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103848,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"},{"bufferView":6,"byteOffset":17376,"componentType":5126,"count":2,"max":[5.0],"min":[0.0],"type":"SCALAR","name":"accessorAnimationInput"},{"bufferView":7,"byteOffset":103872,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationPositions"},{"bufferView":8,"byteOffset":68992,"componentType":5126,"count":2,"type":"VEC4","name":"accessorAnimationRotations"},{"bufferView":7,"byteOffset":103896,"componentType":5126,"count":2,"type":"VEC3","name":"accessorAnimationScales"}],"bufferViews":[{"buffer":0,"byteLength":32484,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":32484,"byteLength":108168,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":140652,"byteLength":143968,"byteStride":16,"name":"bufferViewFloatVec4"},{"buffer":0,"byteOffset":284620,"byteLength":36056,"byteStride":8,"name":"bufferViewFloatVec2"},{"buffer":0,"byteOffset":320676,"byteLength":35928,"byteStride":8,"name":"bufferViewUnsignedShortVec4"},{"buffer":0,"byteOffset":356604,"byteLength":7872,"name":"bufferViewFloatMat4"},{"buffer":0,"byteOffset":364476,"byteLength":17384,"name":"bufferViewAnimationFloatScalar"},{"buffer":0,"byteOffset":381860,"byteLength":103920,"name":"bufferViewAnimationFloatVec3"},{"buffer":0,"byteOffset":485780,"byteLength":69024,"name":"bufferViewAnimationFloatVec4"}],"buffers":[{"uri":"roadsterKart.bin","byteLength":554804}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":2,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":1,"texCoord":0}},"normalTexture":{"index":0,"texCoord":0},"occlusionTexture":{"index":1,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"kartBodyMat1"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":5,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":4,"texCoord":0}},"normalTexture":{"index":3,"texCoord":0},"occlusionTexture":{"index":4,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"roadsterWheelsMat"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":8,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":7,"texCoord":0}},"normalTexture":{"index":6,"texCoord":0},"occlusionTexture":{"index":7,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"driverBodyMat1"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":10,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":9,"texCoord":0}},"normalTexture":{"index":6,"texCoord":0},"occlusionTexture":{"index":9,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"driverBodyMat2"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":12,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":11,"texCoord":0}},"normalTexture":{"index":6,"texCoord":0},"occlusionTexture":{"index":11,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"driverBodyMat3"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":14,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":13,"texCoord":0}},"normalTexture":{"index":0,"texCoord":0},"occlusionTexture":{"index":13,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"kartBodyMat2"},{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":16,"texCoord":0},"metallicFactor":1.0,"roughnessFactor":1.0,"metallicRoughnessTexture":{"index":15,"texCoord":0}},"normalTexture":{"index":0,"texCoord":0},"occlusionTexture":{"index":15,"texCoord":0},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"kartBodyMat3"}],"textures":[{"sampler":0,"source":0,"name":"kartBodyMat_normal.png"},{"sampler":1,"source":1,"name":"kartBodyMat_ORM1.png"},{"sampler":2,"source":2,"name":"kartBodyMat_baseColor1.png"},{"sampler":3,"source":3,"name":"engineWheels_roadsterWheelsMat_normal.png"},{"sampler":4,"source":4,"name":"engineWheels_roadsterWheelsMat_ORM.png"},{"sampler":5,"source":5,"name":"engineWheels_roadsterWheelsMat_basecolor.png"},{"sampler":6,"source":6,"name":"driverBodyMat_normal.png"},{"sampler":7,"source":7,"name":"driverBodyMat_ORM1.png"},{"sampler":8,"source":8,"name":"driverBodyMat_baseColor1.png"},{"sampler":9,"source":9,"name":"driverBodyMat_ORM2.png"},{"sampler":10,"source":10,"name":"driverBodyMat_baseColor2.png"},{"sampler":11,"source":11,"name":"driverBodyMat_ORM3.png"},{"sampler":12,"source":12,"name":"driverBodyMat_baseColor3.png"},{"sampler":13,"source":13,"name":"kartBodyMat_ORM3.png"},{"sampler":14,"source":14,"name":"kartBodyMat_baseColor3.png"},{"sampler":15,"source":15,"name":"kartBodyMat_ORM2.png"},{"sampler":16,"source":16,"name":"kartBodyMat_baseColor2.png"}],"images":[{"uri":"kartBodyMat_normal.png"},{"uri":"kartBodyMat_ORM1.png"},{"uri":"kartBodyMat_baseColor1.png"},{"uri":"engineWheels_roadsterWheelsMat_normal.png"},{"uri":"engineWheels_roadsterWheelsMat_ORM.png"},{"uri":"engineWheels_roadsterWheelsMat_basecolor.png"},{"uri":"driverBodyMat_normal.png"},{"uri":"driverBodyMat_ORM1.png"},{"uri":"driverBodyMat_baseColor1.png"},{"uri":"driverBodyMat_ORM2.png"},{"uri":"driverBodyMat_baseColor2.png"},{"uri":"driverBodyMat_ORM3.png"},{"uri":"driverBodyMat_baseColor3.png"},{"uri":"kartBodyMat_ORM3.png"},{"uri":"kartBodyMat_baseColor3.png"},{"uri":"kartBodyMat_ORM2.png"},{"uri":"kartBodyMat_baseColor2.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497},{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}],"animations":[{"channels":[{"sampler":0,"target":{"node":42,"path":"scale"}},{"sampler":1,"target":{"node":42,"path":"translation"}},{"sampler":2,"target":{"node":43,"path":"scale"}},{"sampler":3,"target":{"node":43,"path":"translation"}},{"sampler":4,"target":{"node":44,"path":"scale"}},{"sampler":5,"target":{"node":44,"path":"translation"}},{"sampler":6,"target":{"node":45,"path":"scale"}},{"sampler":7,"target":{"node":45,"path":"translation"}},{"sampler":8,"target":{"node":2,"path":"translation"}},{"sampler":9,"target":{"node":2,"path":"rotation"}},{"sampler":10,"target":{"node":2,"path":"scale"}},{"sampler":11,"target":{"node":3,"path":"translation"}},{"sampler":12,"target":{"node":3,"path":"rotation"}},{"sampler":13,"target":{"node":3,"path":"scale"}},{"sampler":14,"target":{"node":4,"path":"translation"}},{"sampler":15,"target":{"node":4,"path":"rotation"}},{"sampler":16,"target":{"node":4,"path":"scale"}},{"sampler":17,"target":{"node":5,"path":"translation"}},{"sampler":18,"target":{"node":5,"path":"rotation"}},{"sampler":19,"target":{"node":5,"path":"scale"}},{"sampler":20,"target":{"node":6,"path":"translation"}},{"sampler":21,"target":{"node":6,"path":"rotation"}},{"sampler":22,"target":{"node":6,"path":"scale"}},{"sampler":23,"target":{"node":7,"path":"translation"}},{"sampler":24,"target":{"node":7,"path":"rotation"}},{"sampler":25,"target":{"node":7,"path":"scale"}},{"sampler":26,"target":{"node":8,"path":"translation"}},{"sampler":27,"target":{"node":8,"path":"rotation"}},{"sampler":28,"target":{"node":8,"path":"scale"}},{"sampler":29,"target":{"node":9,"path":"translation"}},{"sampler":30,"target":{"node":9,"path":"rotation"}},{"sampler":31,"target":{"node":9,"path":"scale"}},{"sampler":32,"target":{"node":10,"path":"translation"}},{"sampler":33,"target":{"node":10,"path":"rotation"}},{"sampler":34,"target":{"node":10,"path":"scale"}},{"sampler":35,"target":{"node":12,"path":"translation"}},{"sampler":36,"target":{"node":12,"path":"rotation"}},{"sampler":37,"target":{"node":12,"path":"scale"}},{"sampler":38,"target":{"node":13,"path":"translation"}},{"sampler":39,"target":{"node":13,"path":"rotation"}},{"sampler":40,"target":{"node":13,"path":"scale"}},{"sampler":41,"target":{"node":15,"path":"translation"}},{"sampler":42,"target":{"node":15,"path":"rotation"}},{"sampler":43,"target":{"node":15,"path":"scale"}},{"sampler":44,"target":{"node":16,"path":"translation"}},{"sampler":45,"target":{"node":16,"path":"rotation"}},{"sampler":46,"target":{"node":16,"path":"scale"}},{"sampler":47,"target":{"node":17,"path":"translation"}},{"sampler":48,"target":{"node":17,"path":"rotation"}},{"sampler":49,"target":{"node":17,"path":"scale"}},{"sampler":50,"target":{"node":18,"path":"translation"}},{"sampler":51,"target":{"node":18,"path":"rotation"}},{"sampler":52,"target":{"node":18,"path":"scale"}},{"sampler":53,"target":{"node":19,"path":"translation"}},{"sampler":54,"target":{"node":19,"path":"rotation"}},{"sampler":55,"target":{"node":19,"path":"scale"}},{"sampler":56,"target":{"node":21,"path":"translation"}},{"sampler":57,"target":{"node":21,"path":"rotation"}},{"sampler":58,"target":{"node":21,"path":"scale"}},{"sampler":59,"target":{"node":22,"path":"translation"}},{"sampler":60,"target":{"node":22,"path":"rotation"}},{"sampler":61,"target":{"node":22,"path":"scale"}},{"sampler":62,"target":{"node":23,"path":"translation"}},{"sampler":63,"target":{"node":23,"path":"rotation"}},{"sampler":64,"target":{"node":23,"path":"scale"}},{"sampler":65,"target":{"node":24,"path":"translation"}},{"sampler":66,"target":{"node":24,"path":"rotation"}},{"sampler":67,"target":{"node":24,"path":"scale"}},{"sampler":68,"target":{"node":25,"path":"translation"}},{"sampler":69,"target":{"node":25,"path":"rotation"}},{"sampler":70,"target":{"node":25,"path":"scale"}},{"sampler":71,"target":{"node":26,"path":"translation"}},{"sampler":72,"target":{"node":26,"path":"rotation"}},{"sampler":73,"target":{"node":26,"path":"scale"}},{"sampler":74,"target":{"node":27,"path":"translation"}},{"sampler":75,"target":{"node":27,"path":"rotation"}},{"sampler":76,"target":{"node":27,"path":"scale"}},{"sampler":77,"target":{"node":28,"path":"translation"}},{"sampler":78,"target":{"node":28,"path":"rotation"}},{"sampler":79,"target":{"node":28,"path":"scale"}},{"sampler":80,"target":{"node":29,"path":"translation"}},{"sampler":81,"target":{"node":29,"path":"rotation"}},{"sampler":82,"target":{"node":29,"path":"scale"}},{"sampler":83,"target":{"node":30,"path":"translation"}},{"sampler":84,"target":{"node":30,"path":"rotation"}},{"sampler":85,"target":{"node":30,"path":"scale"}},{"sampler":86,"target":{"node":31,"path":"translation"}},{"sampler":87,"target":{"node":31,"path":"rotation"}},{"sampler":88,"target":{"node":31,"path":"scale"}},{"sampler":89,"target":{"node":32,"path":"translation"}},{"sampler":90,"target":{"node":32,"path":"rotation"}},{"sampler":91,"target":{"node":32,"path":"scale"}},{"sampler":92,"target":{"node":33,"path":"translation"}},{"sampler":93,"target":{"node":33,"path":"rotation"}},{"sampler":94,"target":{"node":33,"path":"scale"}},{"sampler":95,"target":{"node":34,"path":"translation"}},{"sampler":96,"target":{"node":34,"path":"rotation"}},{"sampler":97,"target":{"node":34,"path":"scale"}},{"sampler":98,"target":{"node":35,"path":"translation"}},{"sampler":99,"target":{"node":35,"path":"rotation"}},{"sampler":100,"target":{"node":35,"path":"scale"}},{"sampler":101,"target":{"node":36,"path":"translation"}},{"sampler":102,"target":{"node":36,"path":"rotation"}},{"sampler":103,"target":{"node":36,"path":"scale"}},{"sampler":104,"target":{"node":37,"path":"translation"}},{"sampler":105,"target":{"node":37,"path":"rotation"}},{"sampler":106,"target":{"node":37,"path":"scale"}}],"samplers":[{"input":76,"interpolation":"LINEAR","output":77},{"input":78,"interpolation":"LINEAR","output":79},{"input":80,"interpolation":"LINEAR","output":81},{"input":82,"interpolation":"LINEAR","output":83},{"input":84,"interpolation":"LINEAR","output":85},{"input":86,"interpolation":"LINEAR","output":87},{"input":88,"interpolation":"LINEAR","output":89},{"input":90,"interpolation":"LINEAR","output":91},{"input":92,"interpolation":"LINEAR","output":93},{"input":92,"interpolation":"LINEAR","output":94},{"input":92,"interpolation":"LINEAR","output":95},{"input":96,"interpolation":"LINEAR","output":97},{"input":96,"interpolation":"LINEAR","output":98},{"input":96,"interpolation":"LINEAR","output":99},{"input":100,"interpolation":"LINEAR","output":101},{"input":100,"interpolation":"LINEAR","output":102},{"input":100,"interpolation":"LINEAR","output":103},{"input":104,"interpolation":"LINEAR","output":105},{"input":104,"interpolation":"LINEAR","output":106},{"input":104,"interpolation":"LINEAR","output":107},{"input":108,"interpolation":"LINEAR","output":109},{"input":108,"interpolation":"LINEAR","output":110},{"input":108,"interpolation":"LINEAR","output":111},{"input":112,"interpolation":"LINEAR","output":113},{"input":112,"interpolation":"LINEAR","output":114},{"input":112,"interpolation":"LINEAR","output":115},{"input":116,"interpolation":"LINEAR","output":117},{"input":116,"interpolation":"LINEAR","output":118},{"input":116,"interpolation":"LINEAR","output":119},{"input":120,"interpolation":"LINEAR","output":121},{"input":120,"interpolation":"LINEAR","output":122},{"input":120,"interpolation":"LINEAR","output":123},{"input":124,"interpolation":"LINEAR","output":125},{"input":124,"interpolation":"LINEAR","output":126},{"input":124,"interpolation":"LINEAR","output":127},{"input":128,"interpolation":"LINEAR","output":129},{"input":128,"interpolation":"LINEAR","output":130},{"input":128,"interpolation":"LINEAR","output":131},{"input":132,"interpolation":"LINEAR","output":133},{"input":132,"interpolation":"LINEAR","output":134},{"input":132,"interpolation":"LINEAR","output":135},{"input":136,"interpolation":"LINEAR","output":137},{"input":136,"interpolation":"LINEAR","output":138},{"input":136,"interpolation":"LINEAR","output":139},{"input":140,"interpolation":"LINEAR","output":141},{"input":140,"interpolation":"LINEAR","output":142},{"input":140,"interpolation":"LINEAR","output":143},{"input":144,"interpolation":"LINEAR","output":145},{"input":144,"interpolation":"LINEAR","output":146},{"input":144,"interpolation":"LINEAR","output":147},{"input":148,"interpolation":"LINEAR","output":149},{"input":148,"interpolation":"LINEAR","output":150},{"input":148,"interpolation":"LINEAR","output":151},{"input":152,"interpolation":"LINEAR","output":153},{"input":152,"interpolation":"LINEAR","output":154},{"input":152,"interpolation":"LINEAR","output":155},{"input":156,"interpolation":"LINEAR","output":157},{"input":156,"interpolation":"LINEAR","output":158},{"input":156,"interpolation":"LINEAR","output":159},{"input":160,"interpolation":"LINEAR","output":161},{"input":160,"interpolation":"LINEAR","output":162},{"input":160,"interpolation":"LINEAR","output":163},{"input":164,"interpolation":"LINEAR","output":165},{"input":164,"interpolation":"LINEAR","output":166},{"input":164,"interpolation":"LINEAR","output":167},{"input":168,"interpolation":"LINEAR","output":169},{"input":168,"interpolation":"LINEAR","output":170},{"input":168,"interpolation":"LINEAR","output":171},{"input":172,"interpolation":"LINEAR","output":173},{"input":172,"interpolation":"LINEAR","output":174},{"input":172,"interpolation":"LINEAR","output":175},{"input":176,"interpolation":"LINEAR","output":177},{"input":176,"interpolation":"LINEAR","output":178},{"input":176,"interpolation":"LINEAR","output":179},{"input":180,"interpolation":"LINEAR","output":181},{"input":180,"interpolation":"LINEAR","output":182},{"input":180,"interpolation":"LINEAR","output":183},{"input":184,"interpolation":"LINEAR","output":185},{"input":184,"interpolation":"LINEAR","output":186},{"input":184,"interpolation":"LINEAR","output":187},{"input":188,"interpolation":"LINEAR","output":189},{"input":188,"interpolation":"LINEAR","output":190},{"input":188,"interpolation":"LINEAR","output":191},{"input":192,"interpolation":"LINEAR","output":193},{"input":192,"interpolation":"LINEAR","output":194},{"input":192,"interpolation":"LINEAR","output":195},{"input":196,"interpolation":"LINEAR","output":197},{"input":196,"interpolation":"LINEAR","output":198},{"input":196,"interpolation":"LINEAR","output":199},{"input":200,"interpolation":"LINEAR","output":201},{"input":200,"interpolation":"LINEAR","output":202},{"input":200,"interpolation":"LINEAR","output":203},{"input":204,"interpolation":"LINEAR","output":205},{"input":204,"interpolation":"LINEAR","output":206},{"input":204,"interpolation":"LINEAR","output":207},{"input":208,"interpolation":"LINEAR","output":209},{"input":208,"interpolation":"LINEAR","output":210},{"input":208,"interpolation":"LINEAR","output":211},{"input":212,"interpolation":"LINEAR","output":213},{"input":212,"interpolation":"LINEAR","output":214},{"input":212,"interpolation":"LINEAR","output":215},{"input":216,"interpolation":"LINEAR","output":217},{"input":216,"interpolation":"LINEAR","output":218},{"input":216,"interpolation":"LINEAR","output":219},{"input":220,"interpolation":"LINEAR","output":221},{"input":220,"interpolation":"LINEAR","output":222},{"input":220,"interpolation":"LINEAR","output":223}],"name":"wheelsRotation"},{"channels":[{"sampler":0,"target":{"node":42,"path":"scale"}},{"sampler":1,"target":{"node":42,"path":"translation"}},{"sampler":2,"target":{"node":43,"path":"scale"}},{"sampler":3,"target":{"node":43,"path":"translation"}},{"sampler":4,"target":{"node":44,"path":"scale"}},{"sampler":5,"target":{"node":44,"path":"translation"}},{"sampler":6,"target":{"node":45,"path":"scale"}},{"sampler":7,"target":{"node":45,"path":"translation"}},{"sampler":8,"target":{"node":2,"path":"translation"}},{"sampler":9,"target":{"node":2,"path":"rotation"}},{"sampler":10,"target":{"node":2,"path":"scale"}},{"sampler":11,"target":{"node":3,"path":"translation"}},{"sampler":12,"target":{"node":3,"path":"rotation"}},{"sampler":13,"target":{"node":3,"path":"scale"}},{"sampler":14,"target":{"node":4,"path":"translation"}},{"sampler":15,"target":{"node":4,"path":"rotation"}},{"sampler":16,"target":{"node":4,"path":"scale"}},{"sampler":17,"target":{"node":5,"path":"translation"}},{"sampler":18,"target":{"node":5,"path":"rotation"}},{"sampler":19,"target":{"node":5,"path":"scale"}},{"sampler":20,"target":{"node":6,"path":"translation"}},{"sampler":21,"target":{"node":6,"path":"rotation"}},{"sampler":22,"target":{"node":6,"path":"scale"}},{"sampler":23,"target":{"node":7,"path":"translation"}},{"sampler":24,"target":{"node":7,"path":"rotation"}},{"sampler":25,"target":{"node":7,"path":"scale"}},{"sampler":26,"target":{"node":8,"path":"translation"}},{"sampler":27,"target":{"node":8,"path":"rotation"}},{"sampler":28,"target":{"node":8,"path":"scale"}},{"sampler":29,"target":{"node":9,"path":"translation"}},{"sampler":30,"target":{"node":9,"path":"rotation"}},{"sampler":31,"target":{"node":9,"path":"scale"}},{"sampler":32,"target":{"node":10,"path":"translation"}},{"sampler":33,"target":{"node":10,"path":"rotation"}},{"sampler":34,"target":{"node":10,"path":"scale"}},{"sampler":35,"target":{"node":12,"path":"translation"}},{"sampler":36,"target":{"node":12,"path":"rotation"}},{"sampler":37,"target":{"node":12,"path":"scale"}},{"sampler":38,"target":{"node":13,"path":"translation"}},{"sampler":39,"target":{"node":13,"path":"rotation"}},{"sampler":40,"target":{"node":13,"path":"scale"}},{"sampler":41,"target":{"node":15,"path":"translation"}},{"sampler":42,"target":{"node":15,"path":"rotation"}},{"sampler":43,"target":{"node":15,"path":"scale"}},{"sampler":44,"target":{"node":16,"path":"translation"}},{"sampler":45,"target":{"node":16,"path":"rotation"}},{"sampler":46,"target":{"node":16,"path":"scale"}},{"sampler":47,"target":{"node":17,"path":"translation"}},{"sampler":48,"target":{"node":17,"path":"rotation"}},{"sampler":49,"target":{"node":17,"path":"scale"}},{"sampler":50,"target":{"node":18,"path":"translation"}},{"sampler":51,"target":{"node":18,"path":"rotation"}},{"sampler":52,"target":{"node":18,"path":"scale"}},{"sampler":53,"target":{"node":19,"path":"translation"}},{"sampler":54,"target":{"node":19,"path":"rotation"}},{"sampler":55,"target":{"node":19,"path":"scale"}},{"sampler":56,"target":{"node":21,"path":"translation"}},{"sampler":57,"target":{"node":21,"path":"rotation"}},{"sampler":58,"target":{"node":21,"path":"scale"}},{"sampler":59,"target":{"node":22,"path":"translation"}},{"sampler":60,"target":{"node":22,"path":"rotation"}},{"sampler":61,"target":{"node":22,"path":"scale"}},{"sampler":62,"target":{"node":23,"path":"translation"}},{"sampler":63,"target":{"node":23,"path":"rotation"}},{"sampler":64,"target":{"node":23,"path":"scale"}},{"sampler":65,"target":{"node":24,"path":"translation"}},{"sampler":66,"target":{"node":24,"path":"rotation"}},{"sampler":67,"target":{"node":24,"path":"scale"}},{"sampler":68,"target":{"node":25,"path":"translation"}},{"sampler":69,"target":{"node":25,"path":"rotation"}},{"sampler":70,"target":{"node":25,"path":"scale"}},{"sampler":71,"target":{"node":26,"path":"translation"}},{"sampler":72,"target":{"node":26,"path":"rotation"}},{"sampler":73,"target":{"node":26,"path":"scale"}},{"sampler":74,"target":{"node":27,"path":"translation"}},{"sampler":75,"target":{"node":27,"path":"rotation"}},{"sampler":76,"target":{"node":27,"path":"scale"}},{"sampler":77,"target":{"node":28,"path":"translation"}},{"sampler":78,"target":{"node":28,"path":"rotation"}},{"sampler":79,"target":{"node":28,"path":"scale"}},{"sampler":80,"target":{"node":29,"path":"translation"}},{"sampler":81,"target":{"node":29,"path":"rotation"}},{"sampler":82,"target":{"node":29,"path":"scale"}},{"sampler":83,"target":{"node":30,"path":"translation"}},{"sampler":84,"target":{"node":30,"path":"rotation"}},{"sampler":85,"target":{"node":30,"path":"scale"}},{"sampler":86,"target":{"node":31,"path":"translation"}},{"sampler":87,"target":{"node":31,"path":"rotation"}},{"sampler":88,"target":{"node":31,"path":"scale"}},{"sampler":89,"target":{"node":32,"path":"translation"}},{"sampler":90,"target":{"node":32,"path":"rotation"}},{"sampler":91,"target":{"node":32,"path":"scale"}},{"sampler":92,"target":{"node":33,"path":"translation"}},{"sampler":93,"target":{"node":33,"path":"rotation"}},{"sampler":94,"target":{"node":33,"path":"scale"}},{"sampler":95,"target":{"node":34,"path":"translation"}},{"sampler":96,"target":{"node":34,"path":"rotation"}},{"sampler":97,"target":{"node":34,"path":"scale"}},{"sampler":98,"target":{"node":35,"path":"translation"}},{"sampler":99,"target":{"node":35,"path":"rotation"}},{"sampler":100,"target":{"node":35,"path":"scale"}},{"sampler":101,"target":{"node":36,"path":"translation"}},{"sampler":102,"target":{"node":36,"path":"rotation"}},{"sampler":103,"target":{"node":36,"path":"scale"}},{"sampler":104,"target":{"node":37,"path":"translation"}},{"sampler":105,"target":{"node":37,"path":"rotation"}},{"sampler":106,"target":{"node":37,"path":"scale"}}],"samplers":[{"input":224,"interpolation":"LINEAR","output":225},{"input":226,"interpolation":"LINEAR","output":227},{"input":228,"interpolation":"LINEAR","output":229},{"input":230,"interpolation":"LINEAR","output":231},{"input":232,"interpolation":"LINEAR","output":233},{"input":234,"interpolation":"LINEAR","output":235},{"input":236,"interpolation":"LINEAR","output":237},{"input":238,"interpolation":"LINEAR","output":239},{"input":240,"interpolation":"LINEAR","output":241},{"input":240,"interpolation":"LINEAR","output":242},{"input":240,"interpolation":"LINEAR","output":243},{"input":244,"interpolation":"LINEAR","output":245},{"input":244,"interpolation":"LINEAR","output":246},{"input":244,"interpolation":"LINEAR","output":247},{"input":248,"interpolation":"LINEAR","output":249},{"input":248,"interpolation":"LINEAR","output":250},{"input":248,"interpolation":"LINEAR","output":251},{"input":252,"interpolation":"LINEAR","output":253},{"input":252,"interpolation":"LINEAR","output":254},{"input":252,"interpolation":"LINEAR","output":255},{"input":256,"interpolation":"LINEAR","output":257},{"input":256,"interpolation":"LINEAR","output":258},{"input":256,"interpolation":"LINEAR","output":259},{"input":260,"interpolation":"LINEAR","output":261},{"input":260,"interpolation":"LINEAR","output":262},{"input":260,"interpolation":"LINEAR","output":263},{"input":264,"interpolation":"LINEAR","output":265},{"input":264,"interpolation":"LINEAR","output":266},{"input":264,"interpolation":"LINEAR","output":267},{"input":268,"interpolation":"LINEAR","output":269},{"input":268,"interpolation":"LINEAR","output":270},{"input":268,"interpolation":"LINEAR","output":271},{"input":272,"interpolation":"LINEAR","output":273},{"input":272,"interpolation":"LINEAR","output":274},{"input":272,"interpolation":"LINEAR","output":275},{"input":276,"interpolation":"LINEAR","output":277},{"input":276,"interpolation":"LINEAR","output":278},{"input":276,"interpolation":"LINEAR","output":279},{"input":280,"interpolation":"LINEAR","output":281},{"input":280,"interpolation":"LINEAR","output":282},{"input":280,"interpolation":"LINEAR","output":283},{"input":284,"interpolation":"LINEAR","output":285},{"input":284,"interpolation":"LINEAR","output":286},{"input":284,"interpolation":"LINEAR","output":287},{"input":288,"interpolation":"LINEAR","output":289},{"input":288,"interpolation":"LINEAR","output":290},{"input":288,"interpolation":"LINEAR","output":291},{"input":292,"interpolation":"LINEAR","output":293},{"input":292,"interpolation":"LINEAR","output":294},{"input":292,"interpolation":"LINEAR","output":295},{"input":296,"interpolation":"LINEAR","output":297},{"input":296,"interpolation":"LINEAR","output":298},{"input":296,"interpolation":"LINEAR","output":299},{"input":300,"interpolation":"LINEAR","output":301},{"input":300,"interpolation":"LINEAR","output":302},{"input":300,"interpolation":"LINEAR","output":303},{"input":304,"interpolation":"LINEAR","output":305},{"input":304,"interpolation":"LINEAR","output":306},{"input":304,"interpolation":"LINEAR","output":307},{"input":308,"interpolation":"LINEAR","output":309},{"input":308,"interpolation":"LINEAR","output":310},{"input":308,"interpolation":"LINEAR","output":311},{"input":312,"interpolation":"LINEAR","output":313},{"input":312,"interpolation":"LINEAR","output":314},{"input":312,"interpolation":"LINEAR","output":315},{"input":316,"interpolation":"LINEAR","output":317},{"input":316,"interpolation":"LINEAR","output":318},{"input":316,"interpolation":"LINEAR","output":319},{"input":320,"interpolation":"LINEAR","output":321},{"input":320,"interpolation":"LINEAR","output":322},{"input":320,"interpolation":"LINEAR","output":323},{"input":324,"interpolation":"LINEAR","output":325},{"input":324,"interpolation":"LINEAR","output":326},{"input":324,"interpolation":"LINEAR","output":327},{"input":328,"interpolation":"LINEAR","output":329},{"input":328,"interpolation":"LINEAR","output":330},{"input":328,"interpolation":"LINEAR","output":331},{"input":332,"interpolation":"LINEAR","output":333},{"input":332,"interpolation":"LINEAR","output":334},{"input":332,"interpolation":"LINEAR","output":335},{"input":336,"interpolation":"LINEAR","output":337},{"input":336,"interpolation":"LINEAR","output":338},{"input":336,"interpolation":"LINEAR","output":339},{"input":340,"interpolation":"LINEAR","output":341},{"input":340,"interpolation":"LINEAR","output":342},{"input":340,"interpolation":"LINEAR","output":343},{"input":344,"interpolation":"LINEAR","output":345},{"input":344,"interpolation":"LINEAR","output":346},{"input":344,"interpolation":"LINEAR","output":347},{"input":348,"interpolation":"LINEAR","output":349},{"input":348,"interpolation":"LINEAR","output":350},{"input":348,"interpolation":"LINEAR","output":351},{"input":352,"interpolation":"LINEAR","output":353},{"input":352,"interpolation":"LINEAR","output":354},{"input":352,"interpolation":"LINEAR","output":355},{"input":356,"interpolation":"LINEAR","output":357},{"input":356,"interpolation":"LINEAR","output":358},{"input":356,"interpolation":"LINEAR","output":359},{"input":360,"interpolation":"LINEAR","output":361},{"input":360,"interpolation":"LINEAR","output":362},{"input":360,"interpolation":"LINEAR","output":363},{"input":364,"interpolation":"LINEAR","output":365},{"input":364,"interpolation":"LINEAR","output":366},{"input":364,"interpolation":"LINEAR","output":367},{"input":368,"interpolation":"LINEAR","output":369},{"input":368,"interpolation":"LINEAR","output":370},{"input":368,"interpolation":"LINEAR","output":371}],"name":"steering"}],"skins":[{"inverseBindMatrices":69,"skeleton":2,"joints":[2,3,4,5,6,7,8,9,10],"name":"skeleton #0"},{"inverseBindMatrices":70,"skeleton":2,"joints":[2,3,4,5,6,8,12,9,13,10],"name":"skeleton #1"},{"inverseBindMatrices":71,"skeleton":2,"joints":[2,3,15,4,5,8,12,16,9,13,17,18,19],"name":"skeleton #2"},{"inverseBindMatrices":72,"skeleton":2,"joints":[2,3,15,21,22,23,24,25,26,27,28,29,30,31,4,5,6,8,12,16,9,13,17,18,19,10,32,33,34,35,36,37],"name":"skeleton #3"},{"inverseBindMatrices":73,"skeleton":2,"joints":[2,3,15,21,22,23,24,25,26,27,28,29,30,31,34,35,36,37],"name":"skeleton #4"},{"inverseBindMatrices":74,"skeleton":2,"joints":[2,3,15,21,22,23,24,25,26,27,28,29,30,31,4,5,6,8,9,10,32,33,34,35,36,37],"name":"skeleton #5"},{"inverseBindMatrices":75,"skeleton":2,"joints":[2,3,4,5,6,7,8,12,16,9,13,17,18,19,10],"name":"skeleton #6"}]} -------------------------------------------------------------------------------- /public/models/rocks/rock1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/rocks/rock1.bin -------------------------------------------------------------------------------- /public/models/rocks/rock1.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"Rock1_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"Rock1_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":96,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":96,"max":[2.22259331,4.67246532,1.89877129],"min":[-2.50636578,-0.965973,-1.86824989],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":1152,"componentType":5126,"count":96,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":96,"type":"VEC2","name":"accessorUVs"}],"bufferViews":[{"buffer":0,"byteLength":192,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":192,"byteLength":2304,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":2496,"byteLength":768,"byteStride":8,"name":"bufferViewFloatVec2"}],"buffers":[{"uri":"rock1.bin","byteLength":3264}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0.0,"roughnessFactor":0.734265745},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"rockMat"}],"textures":[{"sampler":0,"source":0,"name":"rocks_baseColor.png"}],"images":[{"uri":"rocks_baseColor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}]} -------------------------------------------------------------------------------- /public/models/rocks/rock2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/rocks/rock2.bin -------------------------------------------------------------------------------- /public/models/rocks/rock2.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"Rock2_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"Rock2_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":96,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":96,"max":[1.9317193,3.20992,2.15627766],"min":[-2.73401976,-0.948011637,-1.92736626],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":1152,"componentType":5126,"count":96,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":96,"type":"VEC2","name":"accessorUVs"}],"bufferViews":[{"buffer":0,"byteLength":192,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":192,"byteLength":2304,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":2496,"byteLength":768,"byteStride":8,"name":"bufferViewFloatVec2"}],"buffers":[{"uri":"rock2.bin","byteLength":3264}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0.0,"roughnessFactor":0.734265745},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"rockMat"}],"textures":[{"sampler":0,"source":0,"name":"rocks_baseColor.png"}],"images":[{"uri":"rocks_baseColor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}]} -------------------------------------------------------------------------------- /public/models/rocks/rock3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/rocks/rock3.bin -------------------------------------------------------------------------------- /public/models/rocks/rock3.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"Rock3_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"Rock3_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":96,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":96,"max":[2.045599,2.786461,3.47145844],"min":[-2.2256124,-0.954606652,-2.74662781],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":1152,"componentType":5126,"count":96,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":96,"type":"VEC2","name":"accessorUVs"}],"bufferViews":[{"buffer":0,"byteLength":192,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":192,"byteLength":2304,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":2496,"byteLength":768,"byteStride":8,"name":"bufferViewFloatVec2"}],"buffers":[{"uri":"rock3.bin","byteLength":3264}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0.0,"roughnessFactor":0.734265745},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"rockMat"}],"textures":[{"sampler":0,"source":0,"name":"rocks_baseColor.png"}],"images":[{"uri":"rocks_baseColor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}]} -------------------------------------------------------------------------------- /public/models/rocks/rock4.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/rocks/rock4.bin -------------------------------------------------------------------------------- /public/models/rocks/rock4.gltf: -------------------------------------------------------------------------------- 1 | {"asset":{"version":"2.0","generator":"babylon.js glTF exporter for maya 2018 v1.2.30"},"scene":0,"scenes":[{"nodes":[0],"extensions":{}}],"nodes":[{"mesh":0,"translation":[0.0,0.0,0.0],"rotation":[0.0,0.0,0.0,1.0],"scale":[1.0,1.0,1.0],"name":"Rock4_low"}],"meshes":[{"primitives":[{"attributes":{"POSITION":1,"NORMAL":2,"TEXCOORD_0":3},"indices":0,"mode":4,"material":0}],"name":"Rock4_low"}],"accessors":[{"bufferView":0,"componentType":5123,"count":96,"type":"SCALAR","name":"accessorIndices"},{"bufferView":1,"componentType":5126,"count":96,"max":[2.71995163,3.13899779,3.18514633],"min":[-2.674862,-0.9998815,-2.97547817],"type":"VEC3","name":"accessorPositions"},{"bufferView":1,"byteOffset":1152,"componentType":5126,"count":96,"type":"VEC3","name":"accessorNormals"},{"bufferView":2,"componentType":5126,"count":96,"type":"VEC2","name":"accessorUVs"}],"bufferViews":[{"buffer":0,"byteLength":192,"name":"bufferViewScalar"},{"buffer":0,"byteOffset":192,"byteLength":2304,"byteStride":12,"name":"bufferViewFloatVec3"},{"buffer":0,"byteOffset":2496,"byteLength":768,"byteStride":8,"name":"bufferViewFloatVec2"}],"buffers":[{"uri":"rock4.bin","byteLength":3264}],"materials":[{"pbrMetallicRoughness":{"baseColorFactor":[1.0,1.0,1.0,1.0],"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0.0,"roughnessFactor":0.734265745},"emissiveFactor":[0.0,0.0,0.0],"alphaMode":"OPAQUE","name":"rockMat"}],"textures":[{"sampler":0,"source":0,"name":"rocks_baseColor.png"}],"images":[{"uri":"rocks_baseColor.png"}],"samplers":[{"magFilter":9729,"minFilter":9987,"wrapS":10497,"wrapT":10497}]} -------------------------------------------------------------------------------- /public/models/rocks/rocks_baseColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/rocks/rocks_baseColor.png -------------------------------------------------------------------------------- /public/models/wing/wing.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/wing/wing.bin -------------------------------------------------------------------------------- /public/models/wing/wing.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset": { 3 | "version": "2.0", 4 | "generator": "Microsoft GLTF Exporter 2.4.2.8" 5 | }, 6 | "accessors": [ 7 | { 8 | "bufferView": 0, 9 | "componentType": 5123, 10 | "count": 112824, 11 | "type": "SCALAR" 12 | }, 13 | { 14 | "bufferView": 1, 15 | "componentType": 5126, 16 | "count": 22657, 17 | "type": "VEC3", 18 | "max": [ 19 | 3.794055700302124, 20 | 5.2351713180541992, 21 | 0.47087574005126953 22 | ], 23 | "min": [ 24 | -3.7938323020935059, 25 | 0.0, 26 | -0.46757358312606812 27 | ] 28 | }, 29 | { 30 | "bufferView": 2, 31 | "componentType": 5126, 32 | "count": 22657, 33 | "type": "VEC3" 34 | }, 35 | { 36 | "bufferView": 3, 37 | "componentType": 5126, 38 | "count": 22657, 39 | "type": "VEC2" 40 | } 41 | ], 42 | "bufferViews": [ 43 | { 44 | "buffer": 0, 45 | "byteOffset": 0, 46 | "byteLength": 225648, 47 | "target": 34963 48 | }, 49 | { 50 | "buffer": 0, 51 | "byteOffset": 225648, 52 | "byteLength": 271884, 53 | "target": 34962 54 | }, 55 | { 56 | "buffer": 0, 57 | "byteOffset": 497532, 58 | "byteLength": 271884, 59 | "target": 34962 60 | }, 61 | { 62 | "buffer": 0, 63 | "byteOffset": 769416, 64 | "byteLength": 181256, 65 | "target": 34962 66 | } 67 | ], 68 | "buffers": [ 69 | { 70 | "byteLength": 950672, 71 | "uri": "wing.bin" 72 | } 73 | ], 74 | "images": [ 75 | { 76 | "uri": "wing_image0.png" 77 | }, 78 | { 79 | "uri": "wing_image1.png" 80 | }, 81 | { 82 | "uri": "wing_image2.png" 83 | }, 84 | { 85 | "uri": "wing_image3.png" 86 | } 87 | ], 88 | "materials": [ 89 | { 90 | "pbrMetallicRoughness": { 91 | "baseColorTexture": { 92 | "index": 2 93 | }, 94 | "metallicRoughnessTexture": { 95 | "index": 3 96 | } 97 | }, 98 | "alphaMode": "MASK", 99 | "name": "42", 100 | "doubleSided": true, 101 | "extensions": { 102 | "KHR_materials_pbrSpecularGlossiness": { 103 | "diffuseTexture": { 104 | "index": 0 105 | }, 106 | "specularGlossinessTexture": { 107 | "index": 1 108 | } 109 | } 110 | }, 111 | "extras": { 112 | "MSFT_sRGBFactors": false 113 | } 114 | } 115 | ], 116 | "meshes": [ 117 | { 118 | "name": "mesh_id31", 119 | "primitives": [ 120 | { 121 | "attributes": { 122 | "POSITION": 1, 123 | "NORMAL": 2, 124 | "TEXCOORD_0": 3 125 | }, 126 | "indices": 0, 127 | "material": 0 128 | } 129 | ] 130 | } 131 | ], 132 | "nodes": [ 133 | { 134 | "children": [ 135 | 1 136 | ], 137 | "name": "root" 138 | }, 139 | { 140 | "translation": [ 141 | -7.54102666178369E-06, 142 | -0.1766241192817688, 143 | 0.25588861107826233 144 | ], 145 | "scale": [ 146 | 0.067475959658622742, 147 | 0.067475959658622742, 148 | 0.067475959658622742 149 | ], 150 | "mesh": 0, 151 | "name": "node_id30" 152 | } 153 | ], 154 | "samplers": [ 155 | { 156 | "minFilter": 9985 157 | } 158 | ], 159 | "scenes": [ 160 | { 161 | "nodes": [ 162 | 0 163 | ] 164 | } 165 | ], 166 | "scene": 0, 167 | "textures": [ 168 | { 169 | "name": "texture5", 170 | "sampler": 0, 171 | "source": 0 172 | }, 173 | { 174 | "name": "texture7", 175 | "sampler": 0, 176 | "source": 1 177 | }, 178 | { 179 | "name": "42_bc", 180 | "sampler": 0, 181 | "source": 2 182 | }, 183 | { 184 | "name": "42_mr", 185 | "sampler": 0, 186 | "source": 3 187 | } 188 | ], 189 | "extensionsUsed": [ 190 | "KHR_materials_pbrSpecularGlossiness" 191 | ] 192 | } -------------------------------------------------------------------------------- /public/models/wing/wing_image0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/wing/wing_image0.png -------------------------------------------------------------------------------- /public/models/wing/wing_image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/wing/wing_image1.png -------------------------------------------------------------------------------- /public/models/wing/wing_image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/wing/wing_image2.png -------------------------------------------------------------------------------- /public/models/wing/wing_image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/models/wing/wing_image3.png -------------------------------------------------------------------------------- /public/sounds/go.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/sounds/go.mp3 -------------------------------------------------------------------------------- /public/sounds/music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/sounds/music.mp3 -------------------------------------------------------------------------------- /public/textures/SimpleTrack_ORM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/SimpleTrack_ORM.png -------------------------------------------------------------------------------- /public/textures/SimpleTrack_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/SimpleTrack_basecolor.png -------------------------------------------------------------------------------- /public/textures/SimpleTrack_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/SimpleTrack_normal.png -------------------------------------------------------------------------------- /public/textures/StylizedWall_ORM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/StylizedWall_ORM.png -------------------------------------------------------------------------------- /public/textures/StylizedWall_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/StylizedWall_basecolor.png -------------------------------------------------------------------------------- /public/textures/StylizedWall_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/StylizedWall_normal.png -------------------------------------------------------------------------------- /public/textures/TrackBoundary_ORM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/TrackBoundary_ORM.png -------------------------------------------------------------------------------- /public/textures/TrackBoundary_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/TrackBoundary_basecolor.png -------------------------------------------------------------------------------- /public/textures/TrackBoundary_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/TrackBoundary_normal.png -------------------------------------------------------------------------------- /public/textures/flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/flare.png -------------------------------------------------------------------------------- /public/textures/goal_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/goal_basecolor.png -------------------------------------------------------------------------------- /public/textures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/logo.png -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_nx.jpg -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_ny.jpg -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_nz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_px.jpg -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_py.jpg -------------------------------------------------------------------------------- /public/textures/skybox/TropicalSunnyDay_pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/TropicalSunnyDay_pz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_nx.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_ny.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_nz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_px.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_py.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox2_pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox2_pz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_nx.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_ny.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_nz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_px.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_py.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox3_pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox3_pz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_nx.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_ny.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_nz.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_px.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_py.jpg -------------------------------------------------------------------------------- /public/textures/skybox/skybox_pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrevorDev/KartRacerFHL/147925b85fd70284744f0c084285068a50fa0476/public/textures/skybox/skybox_pz.jpg -------------------------------------------------------------------------------- /server.ts: -------------------------------------------------------------------------------- 1 | import * as express from "express" 2 | import * as http from "http" 3 | import * as sio from "socket.io"; 4 | 5 | interface ISocket extends sio.Socket { 6 | customData: { 7 | roomName: string; 8 | playerName: string; 9 | position: { x: number, y: number, z: number }; 10 | rotationQuaternion: { x: number, y: number, z: number, w: number }; 11 | wheelsRotationSpeedRatio: number; 12 | steeringAnimationFrame: number; 13 | bodyMaterialIndex: number; 14 | driverMaterialIndex: number; 15 | } 16 | } 17 | 18 | var port = 3000; 19 | var pingMS = 100; 20 | 21 | // Basic express webserver 22 | var app = express() 23 | app.use("/public", express.static("public")) 24 | app.get('/', function (req, res) { 25 | res.sendFile(process.cwd() + "/public/index.html") 26 | }) 27 | var server = http.createServer(app) 28 | server.listen(port) 29 | 30 | // socket io configuration for multiplayer 31 | var io = sio(server) 32 | var rooms: { [name: string]: { users: Array, raceId: number } } = {} 33 | io.on('connection', function (socket: ISocket) { 34 | socket.customData = { 35 | roomName: "", 36 | playerName: "", 37 | position: { x: 0, y: 0, z: 0 }, 38 | rotationQuaternion: { x: 0, y: 0, z: 0, w: 0 }, 39 | wheelsRotationSpeedRatio: 0, 40 | steeringAnimationFrame: 0, 41 | bodyMaterialIndex: 0, 42 | driverMaterialIndex: 0 43 | }; 44 | console.log('a user connected'); 45 | socket.on("joinRoom", (e) => { 46 | if (!rooms[e.roomName]) { 47 | rooms[e.roomName] = { 48 | users: [], 49 | raceId: 1 50 | } 51 | } 52 | socket.customData.roomName = e.roomName; 53 | socket.customData.playerName = e.playerName; 54 | socket.customData.bodyMaterialIndex = e.bodyMaterialIndex; 55 | socket.customData.driverMaterialIndex = e.driverMaterialIndex; 56 | const room = rooms[socket.customData.roomName]; 57 | room.users.push(socket); 58 | socket.emit("joinRoomComplete", { id: socket.id, pingMS: pingMS, raceId: room.raceId }); 59 | }) 60 | socket.on("updateKartPose", (pose) => { 61 | socket.customData.position.x = pose.p.x; 62 | socket.customData.position.y = pose.p.y; 63 | socket.customData.position.z = pose.p.z; 64 | 65 | socket.customData.rotationQuaternion.x = pose.r.x; 66 | socket.customData.rotationQuaternion.y = pose.r.y; 67 | socket.customData.rotationQuaternion.z = pose.r.z; 68 | socket.customData.rotationQuaternion.w = pose.r.w; 69 | 70 | socket.customData.wheelsRotationSpeedRatio = pose.w; 71 | socket.customData.steeringAnimationFrame = pose.s; 72 | 73 | socket.customData.bodyMaterialIndex = pose.b; 74 | socket.customData.driverMaterialIndex = pose.d; 75 | }) 76 | socket.on("disconnect", () => { 77 | if (!rooms[socket.customData.roomName]) { 78 | return; 79 | } 80 | var index = rooms[socket.customData.roomName].users.indexOf(socket) 81 | if (index == -1) { 82 | return; 83 | } 84 | rooms[socket.customData.roomName].users.splice(index, 1) 85 | rooms[socket.customData.roomName].users.forEach((s: ISocket) => { 86 | s.emit("userDisconnected", socket.id) 87 | }) 88 | }) 89 | socket.on("raceComplete", (e) => { 90 | const room = rooms[socket.customData.roomName]; 91 | if (!room) { 92 | return; 93 | } 94 | console.log(e.raceId, room.raceId); 95 | if (e.raceId == room.raceId) { 96 | room.raceId++; 97 | room.users.forEach((s: ISocket) => { 98 | s.emit("raceComplete", { raceId: room.raceId, winnerName: e.name }) 99 | }) 100 | 101 | } 102 | console.log("race reset") 103 | }) 104 | }); 105 | 106 | // Ping loop 107 | setInterval(() => { 108 | for (var key in rooms) { 109 | var ret = rooms[key].users.map((s: ISocket) => { 110 | return { 111 | id: s.id, 112 | name: s.customData.playerName, 113 | p: s.customData.position, 114 | r: s.customData.rotationQuaternion, 115 | w: s.customData.wheelsRotationSpeedRatio, 116 | s: s.customData.steeringAnimationFrame, 117 | b: s.customData.bodyMaterialIndex, 118 | d: s.customData.driverMaterialIndex, 119 | } 120 | }) 121 | rooms[key].users.forEach((s: ISocket) => { 122 | s.emit("serverUpdate", ret); 123 | }) 124 | } 125 | }, pingMS) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "noImplicitAny": true, 6 | "module": "commonjs", 7 | "target": "es6", 8 | "lib": [ 9 | "es6", 10 | "dom" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // https://webpack.js.org/guides/typescript/ 2 | 3 | const NodemonPlugin = require('nodemon-webpack-plugin'); 4 | const nodeExternals = require('webpack-node-externals'); 5 | const path = require('path'); 6 | 7 | module.exports = [ 8 | { 9 | mode: 'development', 10 | entry: './server.ts', 11 | devtool: "inline-source-map", 12 | target: "node", 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.tsx?$/, 17 | use: 'ts-loader', 18 | exclude: /node_modules/ 19 | } 20 | ] 21 | }, 22 | externals: [nodeExternals()], 23 | resolve: { 24 | extensions: ['.tsx', '.ts', '.js'] 25 | }, 26 | output: { 27 | filename: 'server.js', 28 | path: path.resolve(__dirname, 'dist') 29 | }, 30 | plugins: [ 31 | new NodemonPlugin({ 32 | script: './dist/server.js' 33 | }) 34 | ] 35 | }, 36 | { 37 | mode: 'development', 38 | entry: "./kartRacer/app.ts", 39 | devtool: "inline-source-map", 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.tsx?$/, 44 | use: 'ts-loader', 45 | exclude: /node_modules/ 46 | } 47 | ] 48 | }, 49 | resolve: { 50 | extensions: ['.tsx', '.ts', '.js'] 51 | }, 52 | output: { 53 | filename: 'kartRacer.js', 54 | path: path.resolve(__dirname, 'public/dist') 55 | } 56 | } 57 | ]; --------------------------------------------------------------------------------