├── .github └── workflows │ └── main.yml ├── .gitignore ├── .yarn └── releases │ └── yarn-classic.cjs ├── .yarnrc.yml ├── README.md ├── assets ├── bsconfig.json ├── index.html ├── package.json ├── public ├── assets │ ├── car_1.png │ ├── car_2.png │ ├── car_3.png │ ├── car_4.png │ ├── car_5.png │ ├── post.png │ ├── roadsign.png │ ├── roadsign_left.png │ ├── stone.png │ └── tree.png └── index.html ├── src ├── Car.res ├── Common.res ├── Control.res ├── Index.res ├── IndexHot.res ├── Object.res ├── Road.res ├── Score.res ├── Screen.res ├── Timer.res └── Track.res └── yarn.lock /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | pull_request: 7 | branches: ["master"] 8 | 9 | jobs: 10 | build: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Set Node.js 20.x 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: 20.x 20 | 21 | - name: Run install 22 | uses: borales/actions-yarn@v4 23 | with: 24 | cmd: install --frozen-lockfile 25 | env: 26 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # if needed 27 | - name: Build 28 | uses: borales/actions-yarn@v4 29 | with: 30 | cmd: build # will run `yarn build` 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | lib 3 | node_modules 4 | .yarn/install-state.gz 5 | .merlin 6 | .vscode 7 | .bsb.lock 8 | .DS_Store 9 | .cache 10 | *.bs.js 11 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-classic.cjs 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReTurbo 2 | 3 | ![ReTurbo](https://user-images.githubusercontent.com/8013000/224544078-2e3ec08c-6b98-419b-adfa-55b0ef58d638.mov) 4 | 5 | Some fun with [Reprocessing](https://github.com/schmavery/reprocessing) and [BsbNative](https://github.com/bsansouci/bsb-native) 6 | 7 | ## How To 8 | 9 | ### Install 10 | 11 | `yarn` 12 | 13 | ### Build 14 | 15 | `yarn build` and `yarn vite:build` 16 | 17 | ### Start 18 | 19 | There are a few ways to try this out: 20 | 21 | After building you could run a static server, like `python -m SimpleHTTPServer` and go to `localhost:8000`. Or you're using safari you can simply open the `index.html` and tick `Develop > Disable Cross-Origin Restrictions`. 22 | 23 | Alternatively using Vite: `yarn preview` will host the game at `localhost:4173` 24 | 25 | ### Controls 26 | 27 | Use the arrow keys to turn and brake, whilst space restarts the game. Alternatively, click/touch 28 | the edges to turn and the timer to restart. 29 | 30 | ## Fun Stuff I used or forked 31 | 32 | - [ReScript](https://rescript-lang.org) 33 | - [Reprocessing](https://github.com/schmavery/reprocessing) 34 | - [ReasonGl](https://github.com/bsansouci/reasongl-web) 35 | - [Vite](https://vitejs.dev) 36 | -------------------------------------------------------------------------------- /assets: -------------------------------------------------------------------------------- 1 | public/assets -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "re-turbo", 3 | "sources": "src", 4 | "bs-dependencies": ["reprocessing"], 5 | "entries": [{ 6 | "backend": "js", 7 | "main-module": "Index" 8 | }], 9 | "package-specs": { 10 | "module": "es6" 11 | }, 12 | "refmt": 3 13 | } 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ReTurbo 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "re-turbo", 3 | "scripts": { 4 | "build": "rescript build -with-deps", 5 | "clean": "rescript clean && rimraf dist/", 6 | "refmt": "rescript format src/*", 7 | "dev": "vite", 8 | "vite:build": "vite build", 9 | "preview": "vite preview", 10 | "format": "prettier --write \"src/**/*.ts\"" 11 | }, 12 | "dependencies": { 13 | "reprocessing": "github:RawToast/reprocessing#ml" 14 | }, 15 | "devDependencies": { 16 | "rescript": "^10.1.3", 17 | "rimraf": "^3.0.0", 18 | "vite": "^5.1.6" 19 | }, 20 | "packageManager": "yarn@4.1.1", 21 | "version": "0.0.0" 22 | } 23 | -------------------------------------------------------------------------------- /public/assets/car_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/car_1.png -------------------------------------------------------------------------------- /public/assets/car_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/car_2.png -------------------------------------------------------------------------------- /public/assets/car_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/car_3.png -------------------------------------------------------------------------------- /public/assets/car_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/car_4.png -------------------------------------------------------------------------------- /public/assets/car_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/car_5.png -------------------------------------------------------------------------------- /public/assets/post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/post.png -------------------------------------------------------------------------------- /public/assets/roadsign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/roadsign.png -------------------------------------------------------------------------------- /public/assets/roadsign_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/roadsign_left.png -------------------------------------------------------------------------------- /public/assets/stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/stone.png -------------------------------------------------------------------------------- /public/assets/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RawToast/ReTurbo/20d1199e20e5c0c0337fa499b7e2f3d9ce8ee073/public/assets/tree.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReTurbo 6 | 27 | 28 | 29 | 30 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Car.res: -------------------------------------------------------------------------------- 1 | type state = { 2 | speed: float, 3 | positionBonus: float, 4 | velocity: float, 5 | // slide: option(float), 6 | offset: float, 7 | } 8 | 9 | let carWidth = 110 10 | let carHeight = 55 11 | 12 | module Display = { 13 | type asset = 14 | | Straight 15 | | LeftTurn 16 | | HeavyLeftTurn 17 | | RightTurn 18 | | HeavyRightTurn 19 | 20 | type t = { 21 | offset: float, 22 | width: float, 23 | height: float, 24 | asset: asset, 25 | z: float, 26 | } 27 | 28 | let make = car => { 29 | let asset = switch car.velocity { 30 | | _ if car.velocity == 0. => Straight 31 | | _ if car.velocity > 12. => HeavyRightTurn 32 | | _ if car.velocity > 0.2 => RightTurn 33 | | _ if car.velocity < -12. => HeavyLeftTurn 34 | | _ if car.velocity < 0.2 => LeftTurn 35 | | _ => Straight 36 | } 37 | 38 | { 39 | offset: car.offset, 40 | asset: asset, 41 | width: float_of_int(carWidth), 42 | height: float_of_int(carHeight), 43 | z: 1., 44 | } 45 | } 46 | } 47 | 48 | let vLowSpeed = 90. 49 | let lowSpeed = 110. 50 | let midSpeed = 160. 51 | let highSpeed = 220. 52 | let vHighSpeed = 260. 53 | 54 | let grassMaxSpeed = 100. 55 | 56 | let maxSpeed = 250. 57 | /* 60-0 in 3 seconds */ 58 | let brakeFactor = 60. *. 1.6 /. (Common.frameRate *. 3.) 59 | 60 | let speedInMph = state => state.speed /. 1.6 |> int_of_float |> string_of_int 61 | 62 | let updateOffset = (state, force) => { 63 | let offset = state.offset -. force 64 | let offset = max(offset, Common.minOffset) 65 | let offset = min(offset, Common.maxOffset) 66 | 67 | {...state, offset: offset} 68 | } 69 | 70 | let turn = (key: Control.turn, state: state) => { 71 | let updateOffsetUsingForce = s => updateOffset(s, s.velocity /. 700.) 72 | let highSpeed = state.speed > 176. && state.speed < 200. 73 | let vHighSpeed = state.speed > 200. 74 | let updateVelocity = amount => { 75 | let velocity = state.velocity +. amount 76 | { 77 | ...state, 78 | velocity: velocity >= -0.5 && velocity <= 0.5 ? 0. : velocity, 79 | }} 80 | switch key { 81 | | LEFT if state.velocity > -12. && vHighSpeed => updateVelocity(-0.8) 82 | | LEFT if state.velocity > -13. && highSpeed => updateVelocity(-0.9) 83 | | LEFT if state.velocity > -14. => updateVelocity(-1.) 84 | | P_LEFT if state.velocity > -18. && vHighSpeed => updateVelocity(-2.) 85 | | P_LEFT if state.velocity > -16. => updateVelocity(-3.5) 86 | | RIGHT if state.velocity < 12. && vHighSpeed => updateVelocity(0.8) 87 | | RIGHT if state.velocity < 13. && highSpeed => updateVelocity(0.9) 88 | | RIGHT if state.velocity < 14. => updateVelocity(1.) 89 | | P_RIGHT if state.velocity < 18. && vHighSpeed => updateVelocity(2.) 90 | | P_RIGHT if state.velocity < 16. => updateVelocity(3.5) 91 | | _ if state.velocity > 0. => updateVelocity(-1.) 92 | | _ if state.velocity < 0. => updateVelocity(1.) 93 | | _ => state 94 | } |> updateOffsetUsingForce 95 | } 96 | 97 | let progression = state => 98 | 0. >= state.speed ? 0. : state.speed *. (1. +. state.positionBonus /. 100.) /. 25. 99 | 100 | let roadEffect = (direction, incline, state) => { 101 | /* Current max velocity is 6, curves are from 0.08 to 0.6 */ 102 | let offTrack = state => { 103 | let carCentre = float_of_int(carWidth) /. 2.1 104 | let offset = state.offset 105 | 106 | let offRoadAdjustment = state => { 107 | let isOffLeft = (offset > 0. && offset > 1.) || (offset < 0. && offset < -1.) 108 | let isOffRight = 109 | (offset < 0. && offset < -1. +. carCentre) || (offset > 0. && offset > 1. +. carCentre) 110 | 111 | let offRoadFactor = switch (isOffLeft, isOffRight) { 112 | | (true, true) => 1. 113 | | (false, false) => 0.3 114 | | _ => 0. 115 | } 116 | let isOff = isOffRight || isOffLeft 117 | let update = state => 118 | state.speed > grassMaxSpeed 119 | ? {...state, speed: state.speed -. offRoadFactor *. 0.8} 120 | : {...state, speed: state.speed -. offRoadFactor *. 0.1} 121 | 122 | isOff ? update(state) : state 123 | } 124 | state |> offRoadAdjustment 125 | } 126 | 127 | let apexBonus = state => { 128 | let offset = state.offset 129 | let initBonus = switch direction { 130 | | Track.Right(t) => (0. -. t) *. offset /. 22. 131 | | Track.Left(t) => t *. offset /. 22. 132 | | _ => 0. 133 | } 134 | 135 | let positionBonus = switch initBonus { 136 | | _ if initBonus > 5. => 5. 137 | | _ if initBonus < -5. => -5. 138 | | 0. => 0. 139 | | _ => initBonus 140 | } 141 | 142 | {...state, positionBonus: positionBonus} 143 | } 144 | 145 | let cornerEffect = state => 146 | switch direction { 147 | | Track.Left(force) => force *. 0.1 *. state.speed /. 350. |> updateOffset(state) 148 | | Track.Right(force) => force *. -0.1 *. state.speed /. 350. |> updateOffset(state) 149 | | _ => state 150 | } 151 | 152 | let hillEffect = state => { 153 | let incline = incline > 0. ? incline *. 0.5 : incline 154 | let effect = incline *. 0.02 155 | 156 | effect != 0. ? {...state, speed: state.speed -. effect} : state 157 | } 158 | 159 | state |> cornerEffect |> offTrack |> apexBonus |> hillEffect 160 | } 161 | 162 | let accelerate = (isBrake, state) => { 163 | let accel = switch state.speed { 164 | | _ if maxSpeed == state.speed => maxSpeed 165 | | _ if vLowSpeed > state.speed => log((highSpeed -. state.speed) /. 4.) /. 8. 166 | | _ if lowSpeed > state.speed => log((highSpeed -. state.speed) /. 8.) /. 12. 167 | | _ if midSpeed > state.speed => log((vHighSpeed -. state.speed) /. 10.) /. 20. 168 | | _ if highSpeed > state.speed => log((maxSpeed -. state.speed) /. 12.) /. 22. 169 | | _ if vHighSpeed > state.speed => log((maxSpeed -. state.speed) /. 14.) /. 25. 170 | | _ => log((maxSpeed -. state.speed) /. 16.) /. 25. 171 | } 172 | 173 | let speed = isBrake ? max(0., state.speed -. brakeFactor) : state.speed +. accel 174 | let speed = max(0., speed) 175 | let speed = min(maxSpeed, speed) 176 | 177 | {...state, speed: speed} 178 | } 179 | 180 | let init = { 181 | velocity: 0., 182 | offset: 0., 183 | speed: 0., 184 | positionBonus: 0., 185 | } 186 | -------------------------------------------------------------------------------- /src/Common.res: -------------------------------------------------------------------------------- 1 | let height = 320 2 | let width = 568 3 | let heightF = float_of_int(height) 4 | let widthF = float_of_int(width) 5 | let centrePoint = widthF /. 2. 6 | let centreHeight = heightF /. 2. 7 | let horizon = heightF /. 3. *. 2. 8 | 9 | let minOffset = -2. 10 | let maxOffset = 2. 11 | let roadWidth = 600. 12 | let frameRate = 60. 13 | 14 | let planes = 100 15 | 16 | let cameraDepth = 1. /. tan(80. /. 2. *. 3.1459) 17 | -------------------------------------------------------------------------------- /src/Control.res: -------------------------------------------------------------------------------- 1 | type state = { 2 | right: bool, 3 | left: bool, 4 | brake: bool, 5 | reset: bool, 6 | } 7 | 8 | type turn = 9 | | LEFT 10 | | P_LEFT 11 | | RIGHT 12 | | P_RIGHT 13 | | NONE 14 | 15 | let init = {right: false, left: false, brake: false, reset: false} 16 | let isLeft = state => state.left && !state.right 17 | let isRight = state => state.right && !state.left 18 | let isBrake = state => state.brake 19 | let isReset = state => state.reset 20 | 21 | let getTurn = state => 22 | switch (isRight(state), isLeft(state), isBrake(state)) { 23 | | (true, false, false) => RIGHT 24 | | (true, false, true) => P_RIGHT 25 | | (false, true, false) => LEFT 26 | | (false, true, true) => P_LEFT 27 | | _ => NONE 28 | } 29 | 30 | open Reprocessing_Events 31 | let keyDown = (code, state) => 32 | switch code { 33 | | Left => {...state, left: true} 34 | | Right => {...state, right: true} 35 | | Down => {...state, brake: true} 36 | | Up => {...state, reset: true} 37 | | _ => state 38 | } 39 | 40 | let keyUp = (code, state) => 41 | switch code { 42 | | Left => {...state, left: false} 43 | | Right => {...state, right: false} 44 | | Down => {...state, brake: false} 45 | | Up => {...state, reset: false} 46 | | _ => state 47 | } 48 | 49 | let breakY = 350 50 | let isMHardLeft = (x, y) => 250 > x && y > breakY 51 | let isMHardRight = (x, y) => x > 525 && y > breakY 52 | let isMLeft = x => 250 > x 53 | let isMRight = x => x > 525 54 | 55 | let handleCurrentPress = (x, y, state) => 56 | switch (x, y) { 57 | | _ if isMHardLeft(x, y) => {...state, brake: true, left: true} 58 | | _ if isMHardRight(x, y) => {...state, brake: true, right: true} 59 | | _ if isMLeft(x) => {...state, left: true} 60 | | _ if isMRight(x) => {...state, right: true} 61 | | _ if y > breakY => {...state, brake: true} 62 | | _ if 60 > y => {...state, reset: true} 63 | | _ => state 64 | } 65 | 66 | let handleRemovePress = (x, y, state) => 67 | switch (x, y) { 68 | | _ if isMHardLeft(x, y) => {...state, brake: false, left: false} 69 | | _ if isMHardRight(x, y) => {...state, brake: false, right: false} 70 | | _ if isMLeft(x) => {...state, left: false} 71 | | _ if isMRight(x) => {...state, right: false} 72 | | _ if y > breakY => {...state, brake: false} 73 | | _ => state 74 | } 75 | 76 | let mouseDown = (mousePos, state) => { 77 | let (x, y) = mousePos 78 | handleCurrentPress(x, y, state) 79 | } 80 | 81 | let mouseUp = (mousePos, state) => { 82 | let (x, y) = mousePos 83 | handleRemovePress(x, y, state) 84 | } 85 | 86 | let mouseDragged = (mousePos, previousPosition, state) => { 87 | let (x, y) = mousePos 88 | let (px, py) = previousPosition 89 | 90 | state |> handleRemovePress(px, py) |> handleCurrentPress(x, y) 91 | } 92 | -------------------------------------------------------------------------------- /src/Index.res: -------------------------------------------------------------------------------- 1 | open Common 2 | open Reprocessing 3 | 4 | type state = { 5 | car: Car.state, 6 | road: Road.state, 7 | control: Control.state, 8 | timer: Timer.state, 9 | score: Score.state, 10 | assets: Screen.Sprite.assets, 11 | } 12 | 13 | let setup = env => { 14 | Env.size(~width, ~height, env) 15 | { 16 | car: Car.init, 17 | road: Road.init, 18 | control: Control.init, 19 | timer: Timer.init(), 20 | score: Score.init, 21 | assets: Screen.Sprite.init(env), 22 | } 23 | } 24 | 25 | let control = state => { 26 | let currentPlane = Road.currentPlane(state.road) 27 | let (currentRoadDirection, currentIncline) = (currentPlane.direction, currentPlane.incline) 28 | let isBrake = Control.isBrake(state.control) || Timer.gameOver(state.timer) ? true : false 29 | let turn = Control.getTurn(state.control) 30 | let car = 31 | Car.turn(turn, state.car) 32 | |> Car.roadEffect(currentRoadDirection, currentIncline) 33 | |> Car.accelerate(isBrake) 34 | 35 | {...state, car: car} 36 | } 37 | 38 | let handleCollisions = state => { 39 | let currentPlane = Road.currentPlane2(state.road) 40 | let car = state.car 41 | let objects = currentPlane.objects 42 | 43 | let objects = 44 | objects |> List.filter(Object.calcHit(car.offset, state.road.position, Common.roadWidth)) 45 | let penalty = objects |> List.fold_left((a, b) => Object.speedPenalty(b) +. a, 0.) 46 | 47 | let speed = max(0., car.speed -. penalty) 48 | let car = {...car, speed: speed} 49 | 50 | {...state, car: car} 51 | } 52 | 53 | let updatePosition = state => { 54 | let position = state.road.position +. Car.progression(state.car) 55 | let newRoadState = Road.moveForward(position, state.road) 56 | 57 | let checkpointBonus = 58 | state.road.lastPiece != newRoadState.lastPiece ? Road.checkpointBonus(newRoadState) : 0 59 | let timer = Timer.addTimeInSeconds(checkpointBonus, state.timer) 60 | let startTime = 61 | state.road.lastPiece != newRoadState.lastPiece ? Road.startTime(newRoadState) : 00 62 | 63 | let timer = if (startTime != 0) { 64 | Timer.init(~time=float_of_int(startTime), ()) 65 | } else { 66 | timer 67 | } 68 | // let timer = Timer.addTimeInSeconds(checkpointBonus, state.timer) 69 | 70 | {...state, road: newRoadState, timer: timer} 71 | } 72 | 73 | let updateScoreAndTimer = (lastPosition, state) => { 74 | let score = Score.increment(state.road.position -. lastPosition, state.score) 75 | let timer = Timer.reduce(state.timer) 76 | 77 | {...state, score: score, timer: timer} 78 | } 79 | 80 | let drawSky = env => { 81 | Draw.fill(Utils.color(~r=5, ~g=5, ~b=200, ~a=255), env) 82 | Draw.quad(~p1=(0, 0), ~p2=(width, 0), ~p3=(width, height), ~p4=(0, height), env) // might as well fill. This used to be called *after* drawing the road 83 | } 84 | 85 | let drawGame = (state, env) => { 86 | Draw.background(Utils.color(~r=255, ~g=255, ~b=255, ~a=255), env) 87 | drawSky(env) 88 | 89 | let road = Road.Display.make(~offset=state.car.offset, state.road) 90 | let car = Car.Display.make(state.car) 91 | let screen: Screen.t = {road: road, car: car} 92 | Screen.draw(~offset=state.car.offset, ~screen, state.assets, env) 93 | 94 | Draw.fill(Utils.color(~r=25, ~g=25, ~b=25, ~a=255), env) 95 | 96 | let text = Car.speedInMph(state.car) 97 | let mph = "MPH" 98 | 99 | Draw.text(~body=text, ~pos=(420, 20), env) 100 | Draw.text(~body=mph, ~pos=(480, 20), env) 101 | Score.draw(state.score, env) 102 | Timer.draw(state.timer, env) 103 | 104 | state 105 | } 106 | 107 | let draw = (state, env) => 108 | if Control.isReset(state.control) { 109 | setup(env) 110 | } else { 111 | let lastPosition = state.road.position 112 | 113 | let state = control(state) 114 | let state = handleCollisions(state) 115 | let state = updatePosition(state) 116 | let state = updateScoreAndTimer(lastPosition, state) 117 | 118 | drawGame(state, env) 119 | } 120 | 121 | let keyPressed = (state, env) => { 122 | ...state, 123 | control: Control.keyDown(Env.keyCode(env), state.control), 124 | } 125 | let keyReleased = (state, env) => { 126 | ...state, 127 | control: Control.keyUp(Env.keyCode(env), state.control), 128 | } 129 | let mouseDown = (state, mouseEvent) => { 130 | ...state, 131 | control: Control.mouseDown(Env.mouse(mouseEvent), state.control), 132 | } 133 | let mouseUp = (state, mouseEvent) => { 134 | ...state, 135 | control: Control.mouseUp(Env.mouse(mouseEvent), state.control), 136 | } 137 | let mouseDragged = (state, mouseEvent) => { 138 | ...state, 139 | control: Control.mouseDragged(Env.mouse(mouseEvent), Env.pmouse(mouseEvent), state.control), 140 | } 141 | 142 | run( 143 | ~setup, 144 | ~screen="game", 145 | ~draw, 146 | ~keyPressed, 147 | ~keyReleased, 148 | ~mouseDown, 149 | ~mouseUp, 150 | ~mouseDragged, 151 | (), 152 | ) 153 | -------------------------------------------------------------------------------- /src/IndexHot.res: -------------------------------------------------------------------------------- 1 | let _ = Reprocessing.hotreload("src/index.re") 2 | () 3 | -------------------------------------------------------------------------------- /src/Object.res: -------------------------------------------------------------------------------- 1 | type objectType = 2 | | SIGN_RIGHT 3 | | SIGN_LEFT 4 | | TREE 5 | | STONE 6 | | POST 7 | 8 | type state = { 9 | objectType: objectType, 10 | offset: float, 11 | z: float, 12 | size: (int, int), 13 | hitbox: (float, float), 14 | } 15 | 16 | let calcHit = (playerPosition, distance, roadWidth, obj) => { 17 | let carSizeFactor = 55. /. roadWidth 18 | let playerOffset = playerPosition *. -1. 19 | 20 | let (playerOff1, playerOff2) = (playerOffset -. carSizeFactor, playerOffset +. carSizeFactor) 21 | let adj = mod_float(distance, 40. *. 2.) 22 | let playerTravel = adj >= 40. ? adj -. 40. : adj 23 | 24 | let {objectType: _, offset, z, size: _, hitbox: (hbX, hbY)} = obj 25 | let factor = hbX /. roadWidth 26 | 27 | let x1 = offset -. factor /. 2. 28 | let x2 = offset +. factor /. 2. 29 | let hbY = hbY *. 0.5 30 | 31 | let y1 = (z -. hbY) *. 0.5 32 | let y2 = z 33 | let inHbX = playerOff2 >= x1 && playerOff1 <= x2 34 | let inHbY = playerTravel >= y1 && playerTravel <= y2 35 | 36 | inHbX && inHbY 37 | } 38 | 39 | let speedPenalty = obj => 40 | switch obj.objectType { 41 | | SIGN_RIGHT 42 | | SIGN_LEFT => 14. 43 | | TREE => { 44 | let (x, _) = obj.size 45 | x > 100 ? 15. : 6. 46 | } 47 | | STONE => 22. 48 | | POST => 9. 49 | } 50 | 51 | module Display = { 52 | type t = { 53 | offset: float, 54 | height: float, 55 | width: float, 56 | z: float, 57 | objectType: objectType, 58 | } 59 | 60 | let make = (~z=0., ~offset, ~height, ~width, objectType) => { 61 | z: z, 62 | height: height, 63 | width: width, 64 | offset: offset, 65 | objectType: objectType, 66 | } 67 | 68 | let make = (obj: state) => { 69 | let (width, height) = obj.size 70 | 71 | make( 72 | ~offset=obj.offset, 73 | ~height=float_of_int(height), 74 | ~width=float_of_int(width), 75 | obj.objectType, 76 | ) 77 | } 78 | } 79 | 80 | module Prefabs = { 81 | let makeSignRight = { 82 | objectType: SIGN_RIGHT, 83 | offset: -1.25, 84 | z: 16., 85 | size: (96, 96), 86 | hitbox: (48., 4.), 87 | } 88 | let makeSignLeft = { 89 | objectType: SIGN_LEFT, 90 | offset: 1.25, 91 | z: 16., 92 | size: (92, 92), 93 | hitbox: (48., 4.), 94 | } 95 | let makeTree = offset => { 96 | objectType: TREE, 97 | offset: offset, 98 | z: 16., 99 | size: (128, 216), 100 | hitbox: (64., 4.), 101 | } 102 | let smallTree = offset => { 103 | objectType: TREE, 104 | offset: offset, 105 | z: 16., 106 | size: (64, 108), 107 | hitbox: (32., 3.), 108 | } 109 | let makeStone = offset => { 110 | objectType: STONE, 111 | offset: offset, 112 | z: 16., 113 | size: (64, 64), 114 | hitbox: (48., 4.), 115 | } 116 | let makePost = offset => { 117 | objectType: POST, 118 | offset: offset, 119 | z: 16., // 6, 19 120 | size: (12, 38), 121 | hitbox: (4., 4.), 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Road.res: -------------------------------------------------------------------------------- 1 | /* Road constants */ 2 | let baseLength = 40. 3 | 4 | type state = { 5 | position: float, 6 | lastPiece: int, 7 | track: Track.state, 8 | } 9 | 10 | let currentPlane = state => Track.head(state.track) 11 | let currentPlane2 = state => state.track |> Track.tail |> List.hd 12 | 13 | let moveForward = (newPosition, state) => 14 | float_of_int(state.lastPiece) *. baseLength -. newPosition <= 0. 15 | ? { 16 | lastPiece: state.lastPiece + 1, 17 | position: newPosition, 18 | track: Track.progress(state.track), 19 | } 20 | : {...state, position: newPosition} 21 | 22 | let onCheckpoint = state => state.track |> Track.head |> Track.isCheckpoint 23 | 24 | let checkpointBonus = state => 25 | state.track 26 | |> Track.head 27 | |> ( 28 | p => 29 | switch p.direction { 30 | | Track.Checkpoint(t) => t 31 | | _ => 0 32 | } 33 | ) 34 | let startTime = state => 35 | state.track 36 | |> Track.head 37 | |> ( 38 | p => 39 | switch p.direction { 40 | | Track.Start(t) => t 41 | | _ => 0 42 | } 43 | ) 44 | let init = {position: 0., track: Track.init, lastPiece: 1} 45 | 46 | %%private( 47 | let findInitialCoordinates = (offset, state) => { 48 | let (isLight, remainder) = { 49 | let adj = mod_float(state.position, baseLength *. 2.) 50 | adj >= baseLength ? (true, adj -. baseLength) : (false, adj) 51 | } 52 | let x0 = Common.centrePoint -. Common.roadWidth /. 2. +. offset 53 | let x1 = Common.centrePoint +. Common.roadWidth /. 2. +. offset 54 | (x0, x1, remainder, isLight) 55 | } 56 | ) 57 | 58 | module Display = { 59 | type colour = { 60 | r: int, 61 | g: int, 62 | b: int, 63 | a: int, 64 | } 65 | type t = { 66 | x: float, 67 | y: float, 68 | z: float, 69 | previous: (float, float, float), 70 | colour: colour, 71 | terrainColour: colour, 72 | objects: list, 73 | } 74 | 75 | %%private(let red = {r: 150, g: 80, b: 80, a: 255}) 76 | 77 | %%private(let lightGrey = {r: 78, g: 78, b: 78, a: 255}) 78 | %%private(let darkGrey = {r: 70, g: 70, b: 70, a: 255}) 79 | 80 | %%private(let roadLightGrey = {r: 62, g: 62, b: 62, a: 255}) 81 | %%private(let roadDarkGrey = {r: 56, g: 56, b: 56, a: 255}) 82 | 83 | %%private(let roadBrown = {r: 84, g: 66, b: 33, a: 255}) 84 | %%private(let roadDarkBrown = {r: 70, g: 55, b: 30, a: 255}) 85 | 86 | %%private(let lightGreen = {r: 45, g: 140, b: 30, a: 255}) 87 | %%private(let darkGreen = {r: 30, g: 120, b: 30, a: 255}) 88 | 89 | %%private(let lightBrown = {r: 82, g: 59, b: 32, a: 255}) 90 | %%private(let darkBrown = {r: 70, g: 50, b: 30, a: 255}) 91 | 92 | %%private(let lightBlue = {r: 45, g: 40, b: 140, a: 255}) 93 | %%private(let darkBlue = {r: 36, g: 32, b: 130, a: 255}) 94 | 95 | let make = (~offset, state) => { 96 | let (_, _, remainder, isLight) = findInitialCoordinates(offset, state) 97 | // let iOffset = int_of_float(offset *. 0.4) /* interesting */ 98 | let remainder = baseLength -. remainder 99 | let convert = (~remainder, ~isDark=isLight, track) => { 100 | let isDark = ref(isDark) 101 | let previous = ref(None) 102 | let ddx = ref(0.) 103 | track |> List.mapi((i, plane: Track.plane) => { 104 | let i = float_of_int(i) 105 | let {direction, objects, incline, roadSurface, groundSurface} = plane 106 | 107 | let objects = objects |> List.map(Object.Display.make) 108 | 109 | // Calc position 110 | let findXyz = (~previous, ~remainder, ~direction, ~incline, ~ddx) => { 111 | let curve = switch direction { 112 | | Track.Left(curve) => i == 0. ? remainder /. baseLength *. curve *. -2. : curve *. -2. 113 | | Right(curve) => i == 0. ? remainder /. baseLength *. curve *. 2. : curve *. 2. 114 | | _ => 0. 115 | } 116 | let curve = curve +. ddx 117 | let ddx = curve 118 | let prev = switch previous { 119 | | Some(xyz) => xyz 120 | | None => (0., 50., 0.) 121 | } 122 | let (px, py, _pz) = prev 123 | 124 | let x = px +. curve 125 | let yFactor = 0.36 *. incline 126 | let y = i == 0. ? py +. yFactor *. remainder /. baseLength : py +. yFactor 127 | let z = i *. baseLength +. remainder 128 | 129 | ((x, y, z), ddx, prev) 130 | } 131 | 132 | let ((x, y, z), newddx, prev) = findXyz( 133 | ~previous=previous.contents, 134 | ~remainder, 135 | ~direction, 136 | ~incline, 137 | ~ddx=ddx.contents, 138 | ) 139 | 140 | previous := Some((x, y, z)) 141 | ddx := newddx 142 | 143 | let isCheckpoint = Track.isCheckpoint(plane) 144 | 145 | let dark = isDark.contents 146 | 147 | let terrainColour = switch groundSurface { 148 | | Grass => dark ? darkGreen : lightGreen 149 | | Soil => dark ? darkBrown : lightBrown 150 | | Water => dark ? darkBlue : lightBlue 151 | | Gravel => dark ? darkGrey : lightGrey 152 | } 153 | 154 | let colour = switch roadSurface { 155 | | _ when isCheckpoint => red 156 | | Tarmac when dark => roadLightGrey 157 | | Tarmac => roadDarkGrey 158 | | Dirt when dark => roadBrown 159 | | Dirt => roadDarkBrown 160 | } 161 | 162 | let result = { 163 | x: x, 164 | y: y, 165 | z: z, 166 | previous: prev, 167 | colour: colour, 168 | terrainColour: terrainColour, 169 | objects: objects, 170 | } 171 | 172 | isDark := !isDark.contents 173 | result 174 | }) 175 | } 176 | 177 | convert(~remainder, ~isDark=isLight, state.track.track) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/Score.res: -------------------------------------------------------------------------------- 1 | type state = {score: float} 2 | 3 | let scoreString = state => state.score /. 10. |> int_of_float |> string_of_int 4 | 5 | let increment = (x, state) => {score: state.score +. x} 6 | let init = {score: 0.} 7 | 8 | let draw = (state, env) => { 9 | let score = scoreString(state) 10 | Reprocessing.Draw.text(~body=score, ~pos=(60, 20), env) 11 | } 12 | -------------------------------------------------------------------------------- /src/Screen.res: -------------------------------------------------------------------------------- 1 | type t = { 2 | car: Car.Display.t, 3 | road: list, 4 | } 5 | 6 | let cameraHeight = ref(55.) 7 | 8 | let cameraDepth = Common.cameraDepth 9 | 10 | let projectToScreen = (~offset, x, y, z) => { 11 | let iOffset = Common.roadWidth /. 2. *. offset *. 0.04 12 | let cameraX = x +. iOffset 13 | let cameraY = y -. cameraHeight.contents 14 | let cameraZ = z -. 0. // - cameraZ 15 | let cameraZ = cameraZ == 0. ? 1. : cameraZ 16 | 17 | let scale = cameraDepth /. cameraZ 18 | 19 | let screenX = Common.centrePoint +. scale *. cameraX *. Common.centrePoint 20 | let screenY = Common.centreHeight -. scale *. cameraY *. Common.centreHeight 21 | 22 | let roadWidth = scale *. Common.roadWidth *. (Common.widthF /. 100.) 23 | 24 | let scale = scale *. 8. // objects all appearing small 25 | (screenX, screenY, roadWidth, scale) 26 | } 27 | 28 | module Sprite = { 29 | open Reprocessing 30 | type carAssets = { 31 | straight: Reprocessing_Common.imageT, 32 | leftTurn: Reprocessing_Common.imageT, 33 | heavyLeftTurn: Reprocessing_Common.imageT, 34 | rightTurn: Reprocessing_Common.imageT, 35 | heavyRightTurn: Reprocessing_Common.imageT, 36 | } 37 | type assets = { 38 | roadSignRight: Reprocessing_Common.imageT, 39 | roadSignLeft: Reprocessing_Common.imageT, 40 | tree: Reprocessing_Common.imageT, 41 | stone: Reprocessing_Common.imageT, 42 | post: Reprocessing_Common.imageT, 43 | car: carAssets, 44 | } 45 | type carState = 46 | | Straight 47 | | LeftTurn 48 | | HeavyLeftTurn 49 | | RightTurn 50 | | HeavyRightTurn 51 | 52 | type objectType = 53 | | SIGN_RIGHT 54 | | SIGN_LEFT 55 | | TREE 56 | | STONE 57 | | POST 58 | | CAR(carState) 59 | 60 | type t = { 61 | x: float, 62 | y: float, 63 | height: float, 64 | width: float, 65 | objectType: objectType, 66 | } 67 | 68 | let fromObject = o => 69 | switch o { 70 | | Object.SIGN_RIGHT => SIGN_RIGHT 71 | | SIGN_LEFT => SIGN_LEFT 72 | | TREE => TREE 73 | | STONE => STONE 74 | | POST => POST 75 | } 76 | 77 | let fromCar = c => 78 | switch c { 79 | | Car.Display.Straight => CAR(Straight) 80 | | LeftTurn => CAR(LeftTurn) 81 | | HeavyLeftTurn => CAR(HeavyLeftTurn) 82 | | RightTurn => CAR(RightTurn) 83 | | HeavyRightTurn => CAR(HeavyRightTurn) 84 | } 85 | 86 | let loadAssets = env => { 87 | let loadImage = file => Draw.loadImage(~filename=file, ~isPixel=true, env) 88 | 89 | { 90 | roadSignLeft: loadImage("assets/roadsign_left.png"), 91 | roadSignRight: loadImage("assets/roadsign.png"), 92 | tree: loadImage("assets/tree.png"), 93 | stone: loadImage("assets/stone.png"), 94 | post: loadImage("assets/post.png"), 95 | car: { 96 | straight: loadImage("assets/car_1.png"), 97 | leftTurn: loadImage("assets/car_2.png"), 98 | heavyLeftTurn: loadImage("assets/car_3.png"), 99 | rightTurn: loadImage("assets/car_4.png"), 100 | heavyRightTurn: loadImage("assets/car_5.png"), 101 | }, 102 | } 103 | } 104 | 105 | let init = env => loadAssets(env) 106 | let draw = (~sprite, assets, env) => { 107 | let {x, y, height, width, objectType} = sprite 108 | let pos = (x -. width /. 2., y) 109 | let draw = Draw.imagef(_, ~pos, ~width, ~height, env) 110 | 111 | switch objectType { 112 | | SIGN_RIGHT => draw(assets.roadSignRight) 113 | | SIGN_LEFT => draw(assets.roadSignLeft) 114 | | TREE => draw(assets.tree) 115 | | STONE => draw(assets.stone) 116 | | POST => draw(assets.post) 117 | | CAR(state) => 118 | switch state { 119 | | Straight => draw(assets.car.straight) 120 | | LeftTurn => draw(assets.car.leftTurn) 121 | | HeavyLeftTurn => draw(assets.car.heavyLeftTurn) 122 | | RightTurn => draw(assets.car.rightTurn) 123 | | HeavyRightTurn => draw(assets.car.heavyRightTurn) 124 | } 125 | } 126 | } 127 | } 128 | module Quad = { 129 | type t = { 130 | x: float, 131 | y: float, 132 | w: float, 133 | previous: (float, float, float), 134 | colour: Road.Display.colour, 135 | terrainColour: Road.Display.colour, 136 | objects: list, 137 | } 138 | 139 | let make = (~offset, road: Road.Display.t): t => { 140 | let {x, y, z, previous, colour, terrainColour, objects} = road 141 | 142 | let (x, y, w, scale) = projectToScreen(~offset, x, y, z) 143 | let (px, py, pz) = previous 144 | let (px, py, pw, _) = projectToScreen(~offset, px, py, pz) 145 | let previous = (px, py, pw) 146 | // This places objects in the middle. Using x,y,z puts them at the back and px... at the front 147 | let (ox, oy, ow) = (x -. (x -. px) /. 2., y -. (y -. py) /. 2., w -. (w -. pw) /. 2.) 148 | 149 | let objects = objects |> List.map((o: Object.Display.t) => { 150 | Sprite.x: ox +. ow *. o.offset, 151 | y: oy -. o.height *. scale, 152 | height: o.height *. scale, 153 | width: o.width *. scale, 154 | objectType: o.objectType |> Sprite.fromObject, 155 | }) 156 | 157 | { 158 | x: x, 159 | y: y, 160 | w: w, 161 | previous: previous, 162 | colour: colour, 163 | terrainColour: terrainColour, 164 | objects: objects, 165 | } 166 | } 167 | 168 | let draw = (quad, assets, env) => { 169 | let {x, y, w, previous, colour, terrainColour} = quad 170 | let (px, py, pw) = previous 171 | open Reprocessing 172 | 173 | if abs_float(py) > abs_float(y) { 174 | Draw.fill( 175 | Utils.color(~r=terrainColour.r, ~g=terrainColour.g, ~b=terrainColour.b, ~a=terrainColour.a), 176 | env, 177 | ) 178 | Draw.quadf(~p1=(0., py), ~p2=(Common.widthF, py), ~p3=(Common.widthF, y), ~p4=(0., y), env) 179 | 180 | Draw.fill(Utils.color(~r=colour.r, ~g=colour.g, ~b=colour.b, ~a=colour.a), env) 181 | Draw.quadf(~p1=(px -. pw, py), ~p2=(px +. pw, py), ~p3=(x +. w, y), ~p4=(x -. w, y), env) 182 | let (infront, behind) = quad.objects |> List.partition((a: Sprite.t) => a.y < 276.) 183 | let _infront = infront |> List.map(sprite => Sprite.draw(~sprite, assets, env)) 184 | behind 185 | } else { 186 | list{} 187 | } 188 | } 189 | } 190 | 191 | let makeCar = (car: Car.Display.t): Sprite.t => { 192 | { 193 | Sprite.x: Common.centrePoint, 194 | y: Common.heightF -. car.height +. 1., 195 | height: car.height, 196 | width: car.width, 197 | objectType: car.asset |> Sprite.fromCar, 198 | } 199 | } 200 | 201 | let draw = (~offset, ~screen, assets, env) => { 202 | let {road, car} = screen 203 | 204 | let projectedRoad = 205 | road->Belt.List.take(Common.planes)->Belt.Option.getExn |> List.map(Quad.make(~offset)) 206 | 207 | let projectedCar = car->makeCar 208 | let behind = 209 | projectedRoad 210 | |> List.sort((_a: Quad.t, b: Quad.t) => int_of_float(b.y)) 211 | |> List.map(quad => { 212 | Quad.draw(quad, assets, env) 213 | }) 214 | |> List.flatten 215 | 216 | Sprite.draw(~sprite=projectedCar, assets, env) 217 | 218 | behind->Belt.List.forEach(sprite => Sprite.draw(~sprite, assets, env)) 219 | } 220 | -------------------------------------------------------------------------------- /src/Timer.res: -------------------------------------------------------------------------------- 1 | type state = {remainingTime: float} 2 | 3 | let remainingTimeString = state => 4 | state.remainingTime /. Common.frameRate |> int_of_float |> string_of_int 5 | 6 | let addTimeInSeconds = (seconds, state) => { 7 | let timeInFrames = float_of_int(seconds) *. Common.frameRate 8 | let remainingTime = timeInFrames +. state.remainingTime 9 | {remainingTime: remainingTime} 10 | } 11 | 12 | let reduce = state => 13 | 0. >= state.remainingTime ? {remainingTime: 0.} : {remainingTime: state.remainingTime -. 1.} 14 | let gameOver = state => 0. >= state.remainingTime 15 | 16 | let init = (~time=59.5, ()) => {remainingTime: time *. Common.frameRate} 17 | 18 | let draw = (state, env) => { 19 | let time = remainingTimeString(state) 20 | Reprocessing.Draw.text(~body=time, ~pos=(Common.width / 2, 20), env) 21 | } 22 | -------------------------------------------------------------------------------- /src/Track.res: -------------------------------------------------------------------------------- 1 | type direction = 2 | | Straight 3 | | Left(float) 4 | | Right(float) 5 | | Checkpoint(int) 6 | | Start(int) 7 | 8 | let bunchOfSmallTrees = (offset1, offset2, offset3) => list{ 9 | Object.Prefabs.smallTree(offset1), 10 | Object.Prefabs.smallTree(offset2), 11 | Object.Prefabs.smallTree(offset3), 12 | } 13 | 14 | let edgePosts = list{Object.Prefabs.makePost(1.), Object.Prefabs.makePost(-1.)} 15 | 16 | type roadSurface = 17 | | Tarmac 18 | | Dirt 19 | 20 | type groundSurface = 21 | | Grass 22 | | Soil 23 | | Water 24 | | Gravel 25 | 26 | type plane = { 27 | direction: direction, 28 | objects: list, 29 | incline: float, 30 | roadSurface: roadSurface, 31 | groundSurface: groundSurface, 32 | } 33 | 34 | type state = {track: list} 35 | 36 | let demoTrack = { 37 | open Object.Prefabs 38 | 39 | let ec1 = 0.08 40 | let ec2 = 0.16 41 | let ec3 = 0.20 42 | let ec4 = 0.24 43 | let mc1 = 0.28 44 | let mc2 = 0.32 45 | let mc3 = 0.4 46 | let mc4 = 0.48 47 | let hc1 = 0.54 48 | let hc2 = 0.6 49 | let hc3 = 0.68 50 | let hc4 = 0.72 51 | let hp1 = 0.8 52 | 53 | let makeCheckpoint = ( 54 | ~incline=0., 55 | ~roadSurface=Tarmac, 56 | ~groundSurface=Grass, 57 | duration: int, 58 | ) => list{ 59 | { 60 | direction: Checkpoint(duration), 61 | objects: list{}, 62 | incline: incline, 63 | roadSurface: roadSurface, 64 | groundSurface: groundSurface, 65 | }, 66 | } 67 | let makeStart = ( 68 | ~incline=0., 69 | ~roadSurface=Tarmac, 70 | ~groundSurface=Grass, 71 | timelimit: int, 72 | ) => list{ 73 | { 74 | direction: Start(timelimit), 75 | objects: list{}, 76 | incline: incline, 77 | roadSurface: roadSurface, 78 | groundSurface: groundSurface, 79 | }, 80 | } 81 | let make = ( 82 | ~times=1, 83 | ~objects=list{}, 84 | ~incline=0., 85 | ~roadSurface=Tarmac, 86 | ~groundSurface=Grass, 87 | direction, 88 | ) => 89 | Array.make( 90 | times, 91 | { 92 | direction: direction, 93 | objects: objects, 94 | incline: incline, 95 | roadSurface: roadSurface, 96 | groundSurface: groundSurface, 97 | }, 98 | ) |> Array.to_list 99 | 100 | let track = 101 | list{ 102 | make(~times=3, Straight), 103 | make(~times=2, ~incline=0.5, Straight), 104 | make(~times=1, ~incline=-1., Straight), 105 | make(~times=1, ~incline=-2., ~objects=list{makeStone(0.5)}, Straight), 106 | make(~times=1, ~objects=list{smallTree(1.17), makeTree(1.55)}, ~incline=-3., Straight), 107 | make(~times=1, ~incline=-4., Straight), 108 | make(~times=1, ~incline=-5., Straight), 109 | make(~times=8, ~incline=-6., ~roadSurface=Dirt, ~groundSurface=Water, ~objects=list{}, Straight), 110 | make(~times=8, ~incline=-5., ~roadSurface=Tarmac, ~groundSurface=Soil, ~objects=list{}, Straight), 111 | make(~times=4, ~incline=-4., ~objects=bunchOfSmallTrees(1.3, 1.5, 1.7), Straight), 112 | make(~times=2, ~incline=-3., Straight), 113 | make(~times=2, ~incline=-2., ~objects=bunchOfSmallTrees(1.35, 1.5, 1.65), Straight), 114 | make(~times=2, ~incline=-1., ~objects=list{makeTree(1.6)}, Straight), 115 | make(~times=2, ~objects=list{smallTree(1.35), makeTree(1.95)}, Right(ec2)), 116 | make(~times=2, ~objects=bunchOfSmallTrees(-1.3, 1.5, -1.7), Right(ec2)), 117 | make(~times=2, ~objects=list{smallTree(1.17), makeTree(1.55)}, Right(ec2)), 118 | make(~times=1, ~incline=1., Straight), 119 | make(~times=2, ~incline=2., Straight), 120 | make(~times=9, ~incline=3., Straight), 121 | make(~times=6, ~incline=2., Straight), 122 | make(~times=3, ~incline=0.5, Straight), 123 | make(~times=16, Left(ec1)), 124 | makeCheckpoint(9), 125 | make(~times=16, Left(ec1)), 126 | make(~times=6, ~incline=0.8, Left(ec2)), 127 | make(~times=8, ~incline=1.5, ~objects=list{makePost(0.), makeSignLeft}, Left(ec4)), 128 | make(~times=8, ~incline=3.7, ~objects=list{makePost(0.), makeSignLeft}, Left(mc2)), 129 | make(~times=8, ~incline=4.2, ~objects=list{makePost(0.), makeSignRight}, Right(ec4)), 130 | make(~times=12, ~incline=6.1, ~objects=list{makeSignRight}, Right(mc2)), 131 | make(~times=4, ~incline=4.2, ~objects=list{makeSignRight, makeTree(-1.65)}, Right(ec4)), 132 | make(~times=6, ~incline=3.2, ~objects=list{makeSignRight}, Right(ec4)), 133 | make(~times=4, ~incline=1.2, Right(ec4)), 134 | make(~times=4, ~objects=list{makeSignRight}, Right(ec4)), 135 | make(~times=6, Straight), 136 | make(~times=18, ~objects=list{makeSignRight}, Right(ec2)), 137 | make(~times=2, ~incline=-0.2, Straight), 138 | make(~times=10, ~incline=-0.8, Straight), 139 | make(~times=18, ~incline=-1.2, Right(ec1)), 140 | make(~times=10, ~incline=-0.7, Right(ec2)), 141 | make(~times=2, ~incline=-0.3, Right(ec2)), 142 | make(~times=12, Right(ec4)), 143 | make(~times=12, ~objects=list{makeSignRight}, Right(mc2)), 144 | make(~times=2, ~objects=list{makeStone(1.55)}, Right(mc3)), 145 | make(~times=4, ~incline=-0.5, Straight), 146 | make(~times=2, ~objects=list{makeTree(-1.25), makeTree(1.25)}, ~incline=-1.5, Straight), 147 | make(~times=2, ~objects=list{makeTree(-1.35), makeTree(1.35)}, ~incline=-1.5, Straight), 148 | make(~times=2, ~incline=-1.5, Straight), 149 | make( 150 | ~times=2, 151 | ~objects=list{makeTree(-1.25), makeTree(-1.45), makeTree(1.25), makeTree(1.45)}, 152 | ~incline=-1.5, 153 | Straight, 154 | ), 155 | make(~times=4, ~incline=-0.5, Straight), 156 | make(~times=8, Left(ec1)), 157 | make(~times=1, ~objects=list{makeStone(0.9), makeStone(0.6), makeStone(0.3)}, Left(ec1)), 158 | make(~times=1, ~objects=list{makeStone(0.1)}, Left(ec1)), 159 | make(~times=8, Left(ec1)), 160 | make( 161 | ~times=1, 162 | ~objects=list{makeStone(-0.85), makeStone(-0.65), makeStone(-0.45)}, 163 | Left(ec1), 164 | ), 165 | make(~times=1, ~objects=list{makeStone(-0.1)}, Left(ec1)), 166 | make(~times=4, Left(ec1)), 167 | make(~times=6, Straight), 168 | make(~times=6, Straight), 169 | make(~times=6, ~incline=0.6, Straight), 170 | make(~times=6, ~incline=1.8, ~objects=list{makeSignLeft}, Left(mc3)), 171 | make(~times=3, ~incline=0.3, ~objects=list{makeSignLeft}, Left(mc3)), 172 | make(~times=6, ~incline=-0.2, ~objects=list{makeSignLeft}, Left(hc2)), 173 | make(~times=6, Straight), 174 | make(~times=1, ~objects=bunchOfSmallTrees(1.3, 1.5, 1.7), Straight), 175 | make(~times=1, ~objects=bunchOfSmallTrees(-1.25, -1.5, -1.75), Straight), 176 | make(~times=1, ~objects=bunchOfSmallTrees(1.2, 1.4, 1.6), Straight), 177 | make(~times=1, ~objects=bunchOfSmallTrees(-1.2, -1.4, -1.6), Straight), 178 | make(~times=1, ~objects=bunchOfSmallTrees(1.3, 1.5, 1.7), Straight), 179 | make(~times=1, ~incline=0.4, ~objects=bunchOfSmallTrees(-1.2, -1.5, -1.7), Straight), 180 | make(~times=1, ~incline=0.9, Right(hc3)), 181 | make(~times=1, ~incline=1.3, Right(hc4)), 182 | make(~times=4, ~incline=2.8, Right(hp1)), 183 | make(~times=1, ~incline=1.7, Right(hc4)), 184 | make(~times=1, ~incline=0.5, Right(hc3)), 185 | make(~times=4, ~incline=0.2, Straight), 186 | make(~times=1, ~objects=list{makeStone(1.4), makeStone(1.75)}, Straight), 187 | make(~times=1, ~objects=list{makeStone(1.65)}, Straight), 188 | make(~times=12, Left(hc2)), 189 | make(~times=6, Straight), 190 | makeCheckpoint(9), 191 | make( 192 | ~times=6, 193 | ~objects=list{smallTree(-1.35), makeTree(-1.9), smallTree(1.35), makeTree(1.9)}, 194 | Straight, 195 | ), 196 | make(~times=36, ~objects=list{makeSignRight}, Right(mc2)), 197 | make(~times=12, Left(hc2)), 198 | make(~times=12, Straight), 199 | make(~times=18, ~objects=list{makeSignLeft}, Left(hc2)), 200 | make(~times=6, ~objects=list{makeSignLeft}, Straight), 201 | make(~times=6, Left(1.)), 202 | make(~times=12, Straight), 203 | make(~times=2, ~incline=-1., Straight), 204 | make(~times=2, ~incline=-2., Straight), 205 | make(~times=36, ~incline=-2.4, Right(mc3)), 206 | make(~times=2, ~incline=-2., Straight), 207 | make(~times=2, ~incline=-1., Straight), 208 | make(~times=6, Straight), 209 | makeCheckpoint(9), 210 | make(~times=3, Straight), 211 | make(~times=2, ~incline=0.5, Straight), 212 | make(~times=1, ~incline=-1., Straight), 213 | make(~times=1, ~incline=-2., Straight), 214 | make(~times=1, ~objects=list{smallTree(1.17), makeTree(1.55)}, ~incline=-3., Straight), 215 | make(~times=1, ~incline=-4., ~objects=list{makeStone(-1.75), makeStone(-1.5)}, Straight), 216 | make(~times=1, ~incline=-5., ~objects=list{makeStone(1.75)}, Straight), 217 | make(~times=8, ~incline=-6., Straight), 218 | make(~times=6, ~objects=list{smallTree(1.35), makeStone(1.95)}, ~incline=-7., Right(ec2)), 219 | make(~times=14, ~incline=-7., Left(ec2)), 220 | make(~times=8, ~incline=-7.5, Straight), 221 | make(~times=8, ~incline=-8., Right(ec2)), 222 | make(~times=12, ~objects=list{makeSignRight}, ~incline=-8.5, Right(ec4)), 223 | make(~times=8, ~incline=-8., Right(mc2)), 224 | make(~times=6, ~objects=list{makeStone(1.95)}, ~incline=-7., Right(ec2)), 225 | make(~times=8, ~incline=-5., Straight), 226 | make(~times=4, ~incline=-4., ~objects=bunchOfSmallTrees(1.3, 1.5, 1.7), Straight), 227 | make(~times=2, ~incline=-3., Straight), 228 | make(~times=2, ~incline=-2., ~objects=bunchOfSmallTrees(1.35, 1.5, 1.65), Straight), 229 | make(~times=2, ~incline=-1., ~objects=list{makeTree(1.6)}, Straight), 230 | make(~times=2, ~objects=list{smallTree(1.35), makeTree(1.95)}, Right(ec2)), 231 | make(~times=2, ~objects=bunchOfSmallTrees(-1.3, 1.5, -1.7), Right(ec2)), 232 | make(~times=2, ~objects=list{smallTree(1.17), makeTree(1.55)}, Right(ec2)), 233 | make(~times=1, ~incline=1., Straight), 234 | make(~times=2, ~incline=1.5, Straight), 235 | make(~times=4, ~incline=2.4, Straight), 236 | make(~times=9, ~incline=3.5, Straight), 237 | make(~times=6, ~incline=2., Straight), 238 | make(~times=3, ~incline=0.5, Straight), 239 | make(~times=16, Left(ec1)), 240 | make(~times=8, Left(ec4)), 241 | make(~times=6, ~incline=1., Left(ec1)), 242 | make(~times=6, ~objects=list{makePost(0.)}, ~incline=0.2, Straight), 243 | make(~times=8, ~objects=list{makePost(0.)}, ~incline=0.8, Right(ec4)), 244 | make(~times=8, ~incline=2.2, ~objects=list{makePost(0.), makeSignRight}, Right(mc3)), 245 | make(~times=2, ~incline=3.2, Straight), 246 | make(~times=8, ~incline=5.2, Straight), 247 | make(~times=6, ~incline=6.1, Straight), 248 | make(~times=4, ~incline=5.8, ~objects=list{makePost(0.)}, Left(ec1)), 249 | make(~times=8, ~incline=6.5, ~objects=list{makePost(0.)}, Left(ec4)), 250 | make(~times=8, ~incline=7.5, ~objects=list{makeSignLeft}, Left(mc3)), 251 | make(~times=2, ~incline=8.8, Straight), 252 | makeCheckpoint(~incline=9.2, 6), 253 | make(~times=3, ~incline=9.9, ~objects=list{makePost(0.)}, Left(ec4)), 254 | make(~times=4, ~incline=12.4, ~objects=list{makePost(0.)}, Left(hc2)), 255 | make(~times=4, ~incline=9.4, Left(mc2)), 256 | make(~times=4, ~incline=8.4, ~objects=list{makePost(0.)}, Left(ec1)), 257 | make(~times=4, ~incline=6.2, ~objects=list{makePost(0.)}, Straight), 258 | make(~times=4, ~incline=4.2, Straight), 259 | make(~times=2, ~incline=5.4, Straight), 260 | make(~times=4, ~incline=6.2, Right(ec1)), 261 | make(~times=4, ~incline=6.6, Right(ec2)), 262 | make(~times=8, ~incline=7.1, Right(ec4)), 263 | make(~times=8, ~incline=6.9, Right(mc2)), 264 | make(~times=8, ~incline=6.4, ~objects=list{makePost(0.)}, Right(mc3)), 265 | make(~times=8, ~incline=6.1, ~objects=list{makePost(0.), makeSignRight}, Right(hc2)), 266 | make(~times=4, ~incline=5.2, Straight), 267 | make(~times=2, ~incline=4.7, Straight), 268 | make(~times=2, ~incline=4.4, Straight), 269 | make(~times=6, ~incline=4.2, Straight), 270 | make(~times=1, ~incline=4.5, ~objects=list{makeStone(-0.2)}, Straight), 271 | make(~times=1, ~incline=4.5, ~objects=list{makeStone(-0.4)}, Straight), 272 | make(~times=6, ~incline=5.1, Left(ec4)), 273 | make(~times=4, ~incline=6.2, Straight), 274 | make(~times=4, ~incline=4.2, Straight), 275 | make(~times=2, ~incline=2.2, Straight), 276 | make(~times=1, ~incline=1.2, ~objects=list{makeStone(-0.8)}, Straight), 277 | make(~times=1, ~incline=1.2, Straight), 278 | make(~times=1, ~incline=0.5, Straight), 279 | make( 280 | ~times=1, 281 | ~incline=0., 282 | ~objects=list{makeStone(0.3), makeStone(0.6), makeStone(0.9)}, 283 | Straight, 284 | ), 285 | make(~times=1, ~incline=-0.5, Straight), 286 | makeCheckpoint(~incline=-1.3, 9), 287 | make(~times=1, ~incline=-1.2, Straight), 288 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(-0.2)}, Straight), 289 | make(~times=8, ~incline=-2.4, Left(ec4)), 290 | make(~times=12, ~incline=-3.6, Straight), 291 | make(~times=8, ~incline=-2.4, Straight), 292 | make(~times=8, ~incline=-1.2, Straight), 293 | make(~times=4, ~incline=0., Straight), 294 | make(~times=4, ~incline=1., Straight), 295 | make(~times=4, ~incline=4., Straight), 296 | make(~times=12, ~incline=5., Straight), 297 | make(~times=4, ~incline=5.4, Straight), 298 | make(~times=4, ~incline=3.2, Straight), 299 | make(~times=4, ~incline=1.1, Straight), 300 | make(~times=8, ~incline=0.2, ~objects=list{makeSignRight}, Right(mc3)), 301 | make(~times=8, ~incline=-2.2, Right(ec4)), 302 | make(~times=8, ~incline=-0.2, Straight), 303 | make(~times=4, ~incline=1.2, Straight), 304 | make(~times=4, ~incline=0.2, Straight), 305 | make(~times=4, ~incline=-1.2, Straight), 306 | make(~times=4, ~incline=-0.2, Straight), 307 | make(~times=6, ~incline=1.2, Left(ec1)), 308 | make(~times=14, ~incline=3.2, Left(ec4)), 309 | make(~times=10, ~incline=5.2, Left(ec2)), 310 | make(~times=8, ~incline=3.5, Left(ec4)), 311 | make(~times=4, ~incline=2.1, Left(ec1)), 312 | make(~times=4, ~incline=1.1, Left(ec1)), 313 | make(~times=4, ~incline=0.5, Left(ec1)), 314 | make(~times=4, Straight), 315 | makeCheckpoint(6), 316 | make(~times=4, Left(ec2)), 317 | make(~times=1, ~objects=list{makeStone(-0.9)}, Left(ec2)), 318 | make(~times=8, Left(ec2)), 319 | make(~times=1, ~incline=0.4, ~objects=list{makeStone(-0.8)}, Left(ec2)), 320 | make(~times=1, ~incline=-0.8, ~objects=list{makeStone(-0.85), makeStone(-0.65)}, Left(ec2)), 321 | make(~times=5, ~incline=0.3, Left(ec2)), 322 | make(~times=1, ~objects=list{makeStone(0.95)}, Left(ec2)), 323 | make(~times=4, Left(ec2)), 324 | make(~times=1, ~objects=list{makeStone(-0.75), makeStone(-0.5)}, Left(ec2)), 325 | make(~times=1, ~incline=-0.6, ~objects=list{makeStone(0.0), makeStone(-0.35)}, Left(ec2)), 326 | make(~times=5, ~incline=-1.2, Left(ec2)), 327 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(0.2), makeStone(0.35)}, Left(ec2)), 328 | make(~times=6, Left(ec2)), 329 | make(~times=1, ~objects=list{makeStone(0.8), makeStone(-0.35)}, Left(ec2)), 330 | make(~times=1, ~objects=list{makeStone(-0.8), makeStone(0.6), makeStone(0.9)}, Left(ec2)), 331 | make(~times=16, Left(ec2)), 332 | make(~times=4, Left(ec2)), 333 | make(~times=9, ~objects=list{makeSignRight}, Right(ec2)), 334 | make(~times=4, ~incline=1.1, Left(ec1)), 335 | make(~times=4, ~incline=0.5, Left(ec1)), 336 | } |> List.concat 337 | 338 | let make = ( 339 | ~times=1, 340 | ~objects=list{}, 341 | ~incline=0., 342 | ~roadSurface=Dirt, 343 | ~groundSurface=Gravel, 344 | direction, 345 | ) => make(~times, ~objects, ~incline, ~roadSurface, ~groundSurface, direction) 346 | let track2 = 347 | list{ 348 | makeStart(~groundSurface=Gravel, 29), 349 | make(~times=8, ~incline=-1.5, Straight), 350 | make(~times=10, ~incline=-1.3, Left(ec2)), 351 | make( 352 | ~times=1, 353 | ~roadSurface=Dirt, 354 | ~groundSurface=Gravel, 355 | ~incline=-1.4, 356 | ~objects=list{makeStone(0.72), makeStone(0.9)}, 357 | Left(ec2), 358 | ), 359 | make(~times=6, ~incline=-1.3, Left(ec2)), 360 | make(~times=1, Left(ec1)), 361 | make(~times=22, ~incline=-2.3, Right(ec3)), 362 | make(~times=4, ~incline=-1., Straight), 363 | make(~times=4, ~incline=-0.5, Straight), 364 | make(~times=12, ~incline=-0.2, Right(hc3)), 365 | make(~times=6, Straight), 366 | make(~times=11, Left(mc1)), 367 | make(~times=1, ~objects=list{makeStone(0.8)}, Left(mc1)), 368 | make(~times=10, Left(mc1)), 369 | make(~times=4, ~incline=0.5, Straight), 370 | make(~times=4, ~incline=1.5, Straight), 371 | make(~times=4, ~incline=2.3, Straight), 372 | make(~times=4, ~incline=3.5, Straight), 373 | make(~times=10, ~incline=4.2, Straight), 374 | make(~times=1, ~objects=list{makeStone(0.5), makeStone(0.8)}, ~incline=4.7, Straight), 375 | make(~times=10, ~incline=4.9, Straight), 376 | make(~times=1, ~objects=list{makeStone(-0.9), makeStone(-0.55)}, ~incline=4.8, Straight), 377 | make(~times=4, ~incline=5.2, Straight), 378 | make(~times=2, ~incline=5.3, Straight), 379 | make(~times=4, ~incline=5.6, Straight), 380 | makeCheckpoint(~incline=5.4, ~groundSurface=Gravel, 16), 381 | make(~times=10, ~incline=5.2, ~objects=edgePosts, Straight), 382 | make(~times=6, ~incline=5.0, ~objects=edgePosts, Right(ec3)), 383 | make(~times=14, ~incline=5.4, ~objects=edgePosts, Right(mc1)), 384 | make(~times=6, ~incline=5.2, ~objects=edgePosts, Right(ec3)), 385 | make(~times=8, ~incline=4.2, ~groundSurface=Gravel, Straight), 386 | make(~times=3, ~incline=3.2, ~groundSurface=Gravel, Straight), 387 | make(~times=4, ~incline=2.2, ~objects=edgePosts, Left(ec4)), 388 | make(~times=12, ~incline=1.2, ~objects=edgePosts, Left(mc4)), 389 | make(~times=4, ~incline=1., ~objects=edgePosts, Left(ec2)), 390 | make(~times=16, ~incline=0.6, ~objects=edgePosts, Left(mc4)), 391 | make(~times=12, ~incline=0.2, ~objects=edgePosts, Right(hc1)), 392 | make(~times=4, ~incline=-0.2, ~objects=edgePosts, Right(ec2)), 393 | make(~times=4, ~incline=-0.4, ~objects=edgePosts, Straight), 394 | make(~times=4, ~incline=-0.2, Straight), 395 | make(~times=8, Straight), 396 | make(~times=1, ~objects=list{makeStone(-0.9)}, Straight), 397 | make(~times=1, ~incline=-0.3, ~objects=list{makeStone(-0.7)}, Straight), 398 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(-0.5)}, Straight), 399 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(-0.8), makeStone(-0.7)}, Straight), 400 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(-0.3)}, Straight), 401 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(-0.), makeStone(0.9)}, Straight), 402 | make(~times=1, ~incline=-0.4, ~objects=list{makeStone(0.3), makeStone(-0.7)}, Straight), 403 | make(~times=4, ~incline=-0.6, Straight), 404 | make(~times=12, ~incline=-1.2, Straight), 405 | make(~times=4, ~incline=-0.6, Straight), 406 | make(~times=4, ~incline=-0.2, Straight), 407 | make(~times=6, Straight), 408 | make(~times=4, ~incline=0.6, Straight), 409 | make(~times=6, ~incline=1.6, Straight), 410 | make(~times=4, ~incline=3.1, Right(hc1)), 411 | make(~times=12, ~incline=4.6, Right(hc2)), 412 | make(~times=8, ~incline=3.6, Right(mc2)), 413 | make(~times=4, ~incline=2.6, Straight), 414 | make(~times=4, ~incline=1., Straight), 415 | make(~times=4, ~incline=0.2, Straight), 416 | make(~times=4, Straight), 417 | make(~times=8, ~incline=-0.6, Straight), 418 | make(~times=8, ~incline=-1.6, Straight), 419 | make(~times=8, ~incline=-0.6, Straight), 420 | make(~times=4, Straight), 421 | make(~times=8, Left(ec4)), 422 | make(~times=6, ~incline=1., Left(ec1)), 423 | make(~times=6, ~incline=0.2, Straight), 424 | make(~times=12, ~incline=0.8, Right(ec4)), 425 | make(~times=14, ~incline=2.2, ~objects=list{makeSignRight}, Right(mc3)), 426 | make(~times=6, ~incline=3.4, Right(ec3)), 427 | make(~times=2, ~incline=4.2, Straight), 428 | make(~times=8, ~incline=5.2, Straight), 429 | make(~times=6, ~incline=6.1, Straight), 430 | make(~times=8, ~incline=5.8, ~objects=edgePosts, Left(mc1)), 431 | make(~times=14, ~incline=6.5, ~objects=edgePosts, Left(hc1)), 432 | make(~times=8, ~incline=7.5, ~objects=list{makeSignLeft}, Left(mc3)), 433 | make(~times=4, ~incline=7.8, ~objects=list{makeSignLeft}, Left(ec2)), 434 | make(~times=2, ~incline=8.8, Straight), 435 | makeCheckpoint(~incline=9.2, ~groundSurface=Gravel, 18), 436 | make(~times=12, ~incline=9.9, Left(ec4)), 437 | make(~times=2, ~incline=10.1, Straight), 438 | make(~times=16, ~incline=10.9, Right(mc1)), 439 | make(~times=10, ~incline=12.4, ~objects=list{makeSignRight}, Right(hc2)), 440 | make(~times=10, ~incline=11.4, Right(ec2)), 441 | make(~times=4, ~incline=9.4, Right(mc2)), 442 | make(~times=8, ~incline=8.4, Left(ec1)), 443 | make(~times=12, ~incline=6.2, Straight), 444 | make(~times=6, ~incline=4.5, Left(ec3)), 445 | make(~times=18, ~incline=4.2, Left(mc3)), 446 | make(~times=24, ~incline=4.3, Left(hc1)), 447 | make(~times=28, ~incline=4.1, ~objects=list{makeSignLeft}, Left(hc3)), 448 | make(~times=12, ~incline=4.0, Right(mc1)), 449 | make(~times=12, ~incline=3.0, Right(ec4)), 450 | make(~times=12, ~incline=2.0, Straight), 451 | make(~times=1, ~incline=1.8, ~objects=list{makeStone(0.8)}, Straight), 452 | make(~times=1, ~incline=1.5, ~objects=list{makeStone(0.6), makeStone(0.9)}, Straight), 453 | make(~times=6, ~incline=0.1, Right(ec4)), 454 | make(~times=1, ~incline=0.3, ~objects=list{makeStone(-0.8)}, Right(ec4)), 455 | make(~times=1, ~incline=0.6, ~objects=list{makeStone(-0.4)}, Right(ec4)), 456 | make(~times=12, ~incline=0.8, Right(ec4)), 457 | make(~times=4, ~incline=0.6, ~objects=list{makeSignRight},Right(hp1)), 458 | make(~times=18, ~incline=0.4, Right(mc2)), 459 | make(~times=6, ~incline=0.2, Right(mc1)), 460 | make(~times=1, ~incline=0.3, ~objects=list{makeStone(0.)}, Straight), 461 | makeCheckpoint(~incline=0.4, ~groundSurface=Gravel, 9), 462 | make(~times=8, ~incline=0., Straight), 463 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(-0.8)}, Straight), 464 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(-0.6), makeStone(-0.9)}, Straight), 465 | make(~times=12, ~incline=0., Straight), 466 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(0.)}, Straight), 467 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(-0.2), makeStone(0.2)}, Straight), 468 | make(~times=20, ~incline=0., ~objects=edgePosts, Right(mc3)), 469 | makeCheckpoint(~incline=1.2, ~groundSurface=Gravel, 9), 470 | make(~times=2, ~incline=0.5, Right(ec1)), 471 | make(~times=8, ~incline=1.1, Right(ec2)), 472 | make(~times=4, ~incline=0.6, Right(ec3)), 473 | make(~times=4, ~incline=0.1, Right(ec4)), 474 | make(~times=16, ~incline=-0.6, Right(mc2)), 475 | make(~times=8, ~incline=-0.2, Straight), 476 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.8), makeStone(-0.5), makeStone(-0.1), makeStone(0.2)}, Straight), 477 | make(~times=7, ~incline=-0., Straight), 478 | make(~times=1, ~incline=-0., ~objects=list{makeStone(0.8), makeStone(0.5), makeStone(0.2)}, Straight), 479 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.1), makeStone(-0.7)}, Straight), 480 | makeCheckpoint(~incline=0.2, ~groundSurface=Gravel, 9), 481 | make(~times=1, ~incline=0.5, ~objects=list{makeStone(0.8)}, Straight), 482 | make(~times=8, ~incline=1., Straight), 483 | make(~times=8, ~incline=0., Left(mc2)), 484 | make(~times=16, ~incline=0., Left(mc4)), 485 | make(~times=8, ~incline=0., Left(mc1)), 486 | make(~times=16, ~incline=0., Left(hc1)), 487 | make(~times=4, ~incline=0., Left(ec3)), 488 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.1), makeStone(-0.7)}, Straight), 489 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.5), makeStone(-1.1)}, Straight), 490 | make(~times=16, ~incline=0.3, Right(mc1)), 491 | make(~times=16, ~incline=-0.3, Right(mc2)), 492 | make(~times=16, ~incline=0.2, Right(mc1)), 493 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.1), makeStone(-0.7)}, Straight), 494 | make(~times=1, ~incline=-0., ~objects=list{makeStone(-0.5), makeStone(-1.1)}, Straight), 495 | make(~times=12, Left(mc1)), 496 | make(~times=1, ~objects=list{makeStone(-0.8), makeStone(-0.5), makeStone(-0.2), makeStone(0.15)}, Left(mc1)), 497 | make(~times=1, ~objects=list{makeStone(-0.7), makeStone(0.25)}, Left(mc1)), 498 | make(~times=12, Left(mc2)), 499 | make(~times=24, Left(ec3)), 500 | make(~times=1, ~objects=list{makeStone(0.8), makeStone(0.5), makeStone(0.15), makeStone(-0.15)}, Left(mc1)), 501 | make(~times=1, ~objects=list{makeStone(0.7), makeStone(-0.25)}, Left(mc1)), 502 | make(~times=8, ~incline=1., Straight), 503 | makeCheckpoint(~incline=0.6, ~groundSurface=Gravel, 9), 504 | make(~times=16, ~incline=-0.3, Right(mc2)), 505 | make(~times=1, ~incline=-0.6, ~objects=list{makeStone(-1.1)}, Right(mc1)), 506 | make(~times=1, ~incline=-1.2, ~objects=list{makeStone(0.)}, Right(mc1)), 507 | make(~times=12, ~incline=-2.2, Right(mc2)), 508 | make(~times=18, ~incline=-2.4, Right(hc1)), 509 | make(~times=12, ~incline=-1.5, Right(mc3)), 510 | make(~times=12, ~incline=-1.2, Left(mc1)), 511 | make(~times=24, ~incline=-0.5, Left(mc4)), 512 | make(~times=12, ~incline=-0.2, Left(mc2)), 513 | make(~times=12, ~incline=0., Straight), 514 | make(~times=1, ~incline=0.6, ~objects=list{makeStone(0.9)}, Straight), 515 | make(~times=1, ~incline=0.6, ~objects=list{makeStone(0.7)}, Straight), 516 | make(~times=4, ~incline=0., Straight), 517 | make(~times=8, ~incline=1.0, Straight), 518 | makeCheckpoint(~incline=0.6, ~groundSurface=Gravel, 9), 519 | make(~times=1, ~incline=0.4, ~objects=list{makeStone(0.9)}, ~groundSurface=Gravel, Straight), 520 | make(~times=4, ~incline=0., Straight), 521 | make(~times=12, ~incline=-2., Straight), 522 | make(~times=12, ~incline=-2., Left(ec4)), 523 | make(~times=12, ~incline=-2., Left(mc2)), 524 | make(~times=8, ~incline=-2., Left(hc2)), 525 | make(~times=8, ~incline=-2., Left(hc4)), 526 | make(~times=8, ~incline=-1.5, Left(hc1)), 527 | make(~times=8, ~incline=-1., Left(mc1)), 528 | make(~times=4, ~incline=-0.5, Straight), 529 | make(~times=4, ~incline=-0.2, Straight), 530 | make(~times=1, ~objects=list{makeStone(0.9)}, Straight), 531 | make(~times=1, ~objects=list{makeStone(0.7)}, Straight), 532 | make(~times=12, Straight), 533 | make(~times=1, ~objects=list{makeStone(0.9), makeStone(0.7), makeStone(0.3), makeStone(-0.8)}, Straight), 534 | make(~times=1, ~objects=list{makeStone(0.5)}, Straight), 535 | make(~times=12, Straight), 536 | make(~times=1, ~objects=list{makeStone(0.2), makeStone(-0.3), makeStone(0.3), makeStone(-0.8)}, Straight), 537 | make(~times=1, ~objects=list{makeStone(0.4), makeStone(-0.5), makeStone(0.6), makeStone(-0.2)}, Straight), 538 | make(~times=2, Straight), 539 | } |> List.concat 540 | 541 | let make = ( 542 | ~times=1, 543 | ~objects=list{}, 544 | ~incline=0., 545 | ~roadSurface=Dirt, 546 | ~groundSurface=Grass, 547 | direction, 548 | ) => make(~times, ~objects, ~incline, ~roadSurface, ~groundSurface, direction) 549 | let track3 = 550 | list{ 551 | makeStart(~groundSurface=Grass, 29), 552 | make(~times=8, ~incline=-1.5, Straight), 553 | make(~times=8, ~incline=-2.5, Straight), 554 | make(~times=8, ~incline=-3.5, Straight), 555 | make(~times=8, ~incline=-3.2, Straight), 556 | make(~times=16, ~incline=-1.5, Straight), 557 | make(~times=16, ~incline=-0.6, Straight), 558 | make(~times=8, ~incline=-0.3, Left(mc2)), 559 | make(~times=24, ~incline=-0.4, Left(mc4)), 560 | make(~times=8, ~incline=-0.6, Left(mc4)), 561 | make(~times=8, ~incline=-0.0, Left(ec3)), 562 | make(~times=16, ~incline=0.2, Straight), 563 | make(~times=8, ~incline=-0.1, Straight), 564 | make(~times=16, ~incline=-1.1, Right(hc1)), 565 | make(~times=16, ~incline=-1.6, Left(hc1)), 566 | make(~times=16, ~incline=-1.9, Right(hc1)), 567 | make(~times=16, ~incline=-0.9, Right(ec3)), 568 | make(~times=16, ~incline=0., Straight), 569 | makeCheckpoint(~incline=0.6, 6), 570 | make(~times=16, ~incline=0., Straight), 571 | make(~times=16, ~incline=0.1, Right(mc3)), 572 | make(~times=8, ~incline=-0.3, Left(mc3)), 573 | make(~times=24, ~incline=-0.6, Left(hc2)), 574 | make(~times=8, ~incline=-0.2, Left(mc2)), 575 | make(~times=7, ~incline=0., ~groundSurface=Water, Straight), 576 | makeCheckpoint(~incline=0.6, ~groundSurface=Water, 9), 577 | make(~times=8, ~incline=0., ~groundSurface=Water, Straight), 578 | make(~times=2, ~incline=0.4, Straight), 579 | make(~times=2, ~incline=1.4, Straight), 580 | make(~times=16, ~incline=3.4, Straight), 581 | make(~times=24, ~incline=3.1, Right(hc3)), 582 | make(~times=12, ~incline=2.4, Right(mc2)), 583 | make(~times=12, ~incline=1., Right(ec2)), 584 | make(~times=24, ~incline=0.3, Left(ec4)), 585 | make(~times=8, ~incline=0., Straight), 586 | } 587 | |> List.concat; 588 | 589 | track->List.append(track2)->List.append(track3) 590 | } 591 | 592 | Random.init(69) 593 | let roll = ref(Random.int(9) + 1) 594 | let reroll = () => roll.contents = Random.int(9) + 1 595 | let positions = [-1.9, -1.8, -1.7, -1.6, -1.5, 1.5, 1.6, 1.7, 1.8, 1.9] 596 | let track = demoTrack |> List.mapi((i, road) => { 597 | reroll() 598 | let t = mod(i, 10) 599 | roll.contents >= t 600 | ? { 601 | reroll() 602 | if (road.groundSurface!=Water) { 603 | { 604 | ...road, 605 | objects: road.objects |> List.append(list{ 606 | Object.Prefabs.makeTree(positions[roll.contents - 1]), 607 | }), 608 | } 609 | } else { 610 | road 611 | } 612 | 613 | } 614 | : road 615 | }) 616 | 617 | let init = {track: track} 618 | 619 | let isCheckpoint = t => 620 | switch t.direction { 621 | | Checkpoint(_) => true 622 | | _ => false 623 | } 624 | 625 | let lastTrack = ref(track) 626 | let progress = state => 627 | List.length(state.track) > 106 628 | ? {track: List.tl(state.track)} 629 | : { 630 | lastTrack := 631 | lastTrack.contents->List.rev |> List.map(t => {...t, incline: t.incline *. 1.1}) 632 | {track: List.tl(List.append(state.track, lastTrack.contents))} 633 | } 634 | 635 | let head = state => List.hd(state.track) 636 | let tail = state => List.tl(state.track) 637 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@bsansouci/reasongl-web@github:RawToast/reasongl-web": 6 | version "1.0.1" 7 | resolved "https://codeload.github.com/RawToast/reasongl-web/tar.gz/fde813f9af0338b17a665b41d13418c9f7d09076" 8 | dependencies: 9 | gl-matrix "*" 10 | 11 | "@esbuild/aix-ppc64@0.19.12": 12 | version "0.19.12" 13 | resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" 14 | integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== 15 | 16 | "@esbuild/android-arm64@0.19.12": 17 | version "0.19.12" 18 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" 19 | integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== 20 | 21 | "@esbuild/android-arm@0.19.12": 22 | version "0.19.12" 23 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" 24 | integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== 25 | 26 | "@esbuild/android-x64@0.19.12": 27 | version "0.19.12" 28 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" 29 | integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== 30 | 31 | "@esbuild/darwin-arm64@0.19.12": 32 | version "0.19.12" 33 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" 34 | integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== 35 | 36 | "@esbuild/darwin-x64@0.19.12": 37 | version "0.19.12" 38 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" 39 | integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== 40 | 41 | "@esbuild/freebsd-arm64@0.19.12": 42 | version "0.19.12" 43 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" 44 | integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== 45 | 46 | "@esbuild/freebsd-x64@0.19.12": 47 | version "0.19.12" 48 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" 49 | integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== 50 | 51 | "@esbuild/linux-arm64@0.19.12": 52 | version "0.19.12" 53 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" 54 | integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== 55 | 56 | "@esbuild/linux-arm@0.19.12": 57 | version "0.19.12" 58 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" 59 | integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== 60 | 61 | "@esbuild/linux-ia32@0.19.12": 62 | version "0.19.12" 63 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" 64 | integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== 65 | 66 | "@esbuild/linux-loong64@0.19.12": 67 | version "0.19.12" 68 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" 69 | integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== 70 | 71 | "@esbuild/linux-mips64el@0.19.12": 72 | version "0.19.12" 73 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" 74 | integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== 75 | 76 | "@esbuild/linux-ppc64@0.19.12": 77 | version "0.19.12" 78 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" 79 | integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== 80 | 81 | "@esbuild/linux-riscv64@0.19.12": 82 | version "0.19.12" 83 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" 84 | integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== 85 | 86 | "@esbuild/linux-s390x@0.19.12": 87 | version "0.19.12" 88 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" 89 | integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== 90 | 91 | "@esbuild/linux-x64@0.19.12": 92 | version "0.19.12" 93 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" 94 | integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== 95 | 96 | "@esbuild/netbsd-x64@0.19.12": 97 | version "0.19.12" 98 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" 99 | integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== 100 | 101 | "@esbuild/openbsd-x64@0.19.12": 102 | version "0.19.12" 103 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" 104 | integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== 105 | 106 | "@esbuild/sunos-x64@0.19.12": 107 | version "0.19.12" 108 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" 109 | integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== 110 | 111 | "@esbuild/win32-arm64@0.19.12": 112 | version "0.19.12" 113 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" 114 | integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== 115 | 116 | "@esbuild/win32-ia32@0.19.12": 117 | version "0.19.12" 118 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" 119 | integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== 120 | 121 | "@esbuild/win32-x64@0.19.12": 122 | version "0.19.12" 123 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" 124 | integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== 125 | 126 | "@rollup/rollup-android-arm-eabi@4.13.0": 127 | version "4.13.0" 128 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz#b98786c1304b4ff8db3a873180b778649b5dff2b" 129 | integrity sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg== 130 | 131 | "@rollup/rollup-android-arm64@4.13.0": 132 | version "4.13.0" 133 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz#8833679af11172b1bf1ab7cb3bad84df4caf0c9e" 134 | integrity sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q== 135 | 136 | "@rollup/rollup-darwin-arm64@4.13.0": 137 | version "4.13.0" 138 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz#ef02d73e0a95d406e0eb4fd61a53d5d17775659b" 139 | integrity sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g== 140 | 141 | "@rollup/rollup-darwin-x64@4.13.0": 142 | version "4.13.0" 143 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz#3ce5b9bcf92b3341a5c1c58a3e6bcce0ea9e7455" 144 | integrity sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg== 145 | 146 | "@rollup/rollup-linux-arm-gnueabihf@4.13.0": 147 | version "4.13.0" 148 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz#3d3d2c018bdd8e037c6bfedd52acfff1c97e4be4" 149 | integrity sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ== 150 | 151 | "@rollup/rollup-linux-arm64-gnu@4.13.0": 152 | version "4.13.0" 153 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz#5fc8cc978ff396eaa136d7bfe05b5b9138064143" 154 | integrity sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w== 155 | 156 | "@rollup/rollup-linux-arm64-musl@4.13.0": 157 | version "4.13.0" 158 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz#f2ae7d7bed416ffa26d6b948ac5772b520700eef" 159 | integrity sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw== 160 | 161 | "@rollup/rollup-linux-riscv64-gnu@4.13.0": 162 | version "4.13.0" 163 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz#303d57a328ee9a50c85385936f31cf62306d30b6" 164 | integrity sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA== 165 | 166 | "@rollup/rollup-linux-x64-gnu@4.13.0": 167 | version "4.13.0" 168 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz#f672f6508f090fc73f08ba40ff76c20b57424778" 169 | integrity sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA== 170 | 171 | "@rollup/rollup-linux-x64-musl@4.13.0": 172 | version "4.13.0" 173 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz#d2f34b1b157f3e7f13925bca3288192a66755a89" 174 | integrity sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw== 175 | 176 | "@rollup/rollup-win32-arm64-msvc@4.13.0": 177 | version "4.13.0" 178 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz#8ffecc980ae4d9899eb2f9c4ae471a8d58d2da6b" 179 | integrity sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA== 180 | 181 | "@rollup/rollup-win32-ia32-msvc@4.13.0": 182 | version "4.13.0" 183 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz#a7505884f415662e088365b9218b2b03a88fc6f2" 184 | integrity sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw== 185 | 186 | "@rollup/rollup-win32-x64-msvc@4.13.0": 187 | version "4.13.0" 188 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz#6abd79db7ff8d01a58865ba20a63cfd23d9e2a10" 189 | integrity sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw== 190 | 191 | "@types/estree@1.0.5": 192 | version "1.0.5" 193 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" 194 | integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== 195 | 196 | balanced-match@^1.0.0: 197 | version "1.0.2" 198 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 199 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 200 | 201 | brace-expansion@^1.1.7: 202 | version "1.1.11" 203 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 204 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 205 | dependencies: 206 | balanced-match "^1.0.0" 207 | concat-map "0.0.1" 208 | 209 | concat-map@0.0.1: 210 | version "0.0.1" 211 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 212 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 213 | 214 | esbuild@^0.19.3: 215 | version "0.19.12" 216 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" 217 | integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== 218 | optionalDependencies: 219 | "@esbuild/aix-ppc64" "0.19.12" 220 | "@esbuild/android-arm" "0.19.12" 221 | "@esbuild/android-arm64" "0.19.12" 222 | "@esbuild/android-x64" "0.19.12" 223 | "@esbuild/darwin-arm64" "0.19.12" 224 | "@esbuild/darwin-x64" "0.19.12" 225 | "@esbuild/freebsd-arm64" "0.19.12" 226 | "@esbuild/freebsd-x64" "0.19.12" 227 | "@esbuild/linux-arm" "0.19.12" 228 | "@esbuild/linux-arm64" "0.19.12" 229 | "@esbuild/linux-ia32" "0.19.12" 230 | "@esbuild/linux-loong64" "0.19.12" 231 | "@esbuild/linux-mips64el" "0.19.12" 232 | "@esbuild/linux-ppc64" "0.19.12" 233 | "@esbuild/linux-riscv64" "0.19.12" 234 | "@esbuild/linux-s390x" "0.19.12" 235 | "@esbuild/linux-x64" "0.19.12" 236 | "@esbuild/netbsd-x64" "0.19.12" 237 | "@esbuild/openbsd-x64" "0.19.12" 238 | "@esbuild/sunos-x64" "0.19.12" 239 | "@esbuild/win32-arm64" "0.19.12" 240 | "@esbuild/win32-ia32" "0.19.12" 241 | "@esbuild/win32-x64" "0.19.12" 242 | 243 | fs.realpath@^1.0.0: 244 | version "1.0.0" 245 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 246 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 247 | 248 | fsevents@~2.3.2, fsevents@~2.3.3: 249 | version "2.3.3" 250 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 251 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 252 | 253 | gl-matrix@*: 254 | version "3.4.3" 255 | resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.3.tgz#fc1191e8320009fd4d20e9339595c6041ddc22c9" 256 | integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA== 257 | 258 | glob@^7.1.3: 259 | version "7.2.3" 260 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 261 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 262 | dependencies: 263 | fs.realpath "^1.0.0" 264 | inflight "^1.0.4" 265 | inherits "2" 266 | minimatch "^3.1.1" 267 | once "^1.3.0" 268 | path-is-absolute "^1.0.0" 269 | 270 | inflight@^1.0.4: 271 | version "1.0.6" 272 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 273 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 274 | dependencies: 275 | once "^1.3.0" 276 | wrappy "1" 277 | 278 | inherits@2: 279 | version "2.0.4" 280 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 281 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 282 | 283 | minimatch@^3.1.1: 284 | version "3.1.2" 285 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 286 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 287 | dependencies: 288 | brace-expansion "^1.1.7" 289 | 290 | nanoid@^3.3.7: 291 | version "3.3.7" 292 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" 293 | integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== 294 | 295 | once@^1.3.0: 296 | version "1.4.0" 297 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 298 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 299 | dependencies: 300 | wrappy "1" 301 | 302 | path-is-absolute@^1.0.0: 303 | version "1.0.1" 304 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 305 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 306 | 307 | picocolors@^1.0.0: 308 | version "1.0.0" 309 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 310 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 311 | 312 | postcss@^8.4.35: 313 | version "8.4.36" 314 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.36.tgz#dba513c3c3733c44e0288a712894f8910bbaabc6" 315 | integrity sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw== 316 | dependencies: 317 | nanoid "^3.3.7" 318 | picocolors "^1.0.0" 319 | source-map-js "^1.1.0" 320 | 321 | "reprocessing@github:RawToast/reprocessing#ml": 322 | version "1.0.0" 323 | resolved "https://codeload.github.com/RawToast/reprocessing/tar.gz/b094e495865d20e4728fe25b4abf0b0c52b14e85" 324 | dependencies: 325 | "@bsansouci/reasongl-web" "github:RawToast/reasongl-web" 326 | 327 | rescript@^10.1.3: 328 | version "10.1.4" 329 | resolved "https://registry.yarnpkg.com/rescript/-/rescript-10.1.4.tgz#0f37710d371f32a704f17b4e804f66ce3c79a305" 330 | integrity sha512-FFKlS9AG/XrLepWsyw7B+A9DtQBPWEPDPDKghV831Y2KGbie+eeFBOS0xtRHp0xbt7S0N2Dm6hhX+kTZQ/3Ybg== 331 | 332 | rimraf@^3.0.0: 333 | version "3.0.2" 334 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 335 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 336 | dependencies: 337 | glob "^7.1.3" 338 | 339 | rollup@^4.2.0: 340 | version "4.13.0" 341 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a" 342 | integrity sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg== 343 | dependencies: 344 | "@types/estree" "1.0.5" 345 | optionalDependencies: 346 | "@rollup/rollup-android-arm-eabi" "4.13.0" 347 | "@rollup/rollup-android-arm64" "4.13.0" 348 | "@rollup/rollup-darwin-arm64" "4.13.0" 349 | "@rollup/rollup-darwin-x64" "4.13.0" 350 | "@rollup/rollup-linux-arm-gnueabihf" "4.13.0" 351 | "@rollup/rollup-linux-arm64-gnu" "4.13.0" 352 | "@rollup/rollup-linux-arm64-musl" "4.13.0" 353 | "@rollup/rollup-linux-riscv64-gnu" "4.13.0" 354 | "@rollup/rollup-linux-x64-gnu" "4.13.0" 355 | "@rollup/rollup-linux-x64-musl" "4.13.0" 356 | "@rollup/rollup-win32-arm64-msvc" "4.13.0" 357 | "@rollup/rollup-win32-ia32-msvc" "4.13.0" 358 | "@rollup/rollup-win32-x64-msvc" "4.13.0" 359 | fsevents "~2.3.2" 360 | 361 | source-map-js@^1.1.0: 362 | version "1.1.0" 363 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.1.0.tgz#9e7d5cb46f0689fb6691b30f226937558d0fa94b" 364 | integrity sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw== 365 | 366 | vite@^5.1.6: 367 | version "5.1.6" 368 | resolved "https://registry.yarnpkg.com/vite/-/vite-5.1.6.tgz#706dae5fab9e97f57578469eef1405fc483943e4" 369 | integrity sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA== 370 | dependencies: 371 | esbuild "^0.19.3" 372 | postcss "^8.4.35" 373 | rollup "^4.2.0" 374 | optionalDependencies: 375 | fsevents "~2.3.3" 376 | 377 | wrappy@1: 378 | version "1.0.2" 379 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 380 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 381 | --------------------------------------------------------------------------------