├── .gitignore ├── LICENSE ├── README.md ├── build.mjs ├── package-lock.json ├── package.json ├── public ├── assets │ └── fonts │ │ └── opensans │ │ ├── OpenSans-Bold.woff2 │ │ ├── OpenSans-BoldItalic.woff2 │ │ ├── OpenSans-ExtraBold.woff2 │ │ ├── OpenSans-ExtraBoldItalic.woff2 │ │ ├── OpenSans-Italic.woff2 │ │ ├── OpenSans-Light.woff2 │ │ ├── OpenSans-LightItalic.woff2 │ │ ├── OpenSans-Regular.woff2 │ │ └── OpenSans-SemiBold.woff2 ├── favicon.ico └── index.html ├── src ├── doomGlareApp.ts ├── scss │ └── global.scss ├── types │ ├── Attributes.ts │ └── modules │ │ └── shaders.d.ts ├── utils │ ├── libs │ │ └── drawable │ │ │ ├── Drawable.ts │ │ │ ├── DrawableGeometry.ts │ │ │ ├── DrawableMaterial.ts │ │ │ ├── Plane.ts │ │ │ ├── README.md │ │ │ └── types.ts │ ├── math │ │ └── math.ts │ └── misc │ │ └── misc.ts └── webgl │ ├── WebGLController.ts │ ├── components │ └── GlarePlane.ts │ ├── materials │ └── GlarePlaneMaterial.ts │ └── scenes │ └── GlareScene.ts ├── tsconfig.json └── watch.mjs /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # MacOS garbage 107 | *.DS_Store 108 | 109 | public/built/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Michael de Laborde 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebGL Doom Glare 2 | 3 | Original inspiration: http://yzergame.com/doomGlare.html and http://simonschreibt.de/gat/doom-3-volumetric-glow/ 4 | 5 | Basic implementation of Doom 3's "Glare". It fakes a simple bloom effect by extruding vertices and interpolating their vertex colors. 6 | 7 | *Looking for help in improving it!* 8 | 9 | Deploy: https://webgl-doom-glare.vercel.app 10 | 11 | ## hunter-gatherer boilerplate 12 | 13 | As barebones I'm willing to go. You probably don't want to use this. 14 | 15 | Featuring: 16 | 17 | - Only 3 dependencies 18 | - Fast build times 19 | - Typescript, GLSL and SASS support 20 | 21 | ## How to develop : 22 | 23 | ``` 24 | npm i && npm run dev 25 | ``` 26 | 27 | This will serve `public/index.html` using bundled `public/built/app.js` and `public/built/scss/` from `/src/app.ts` on `localhost:1234`. 28 | 29 | Assets need to be fetched from the `public` folder. 30 | 31 | It does not output the bundle to disk. 32 | 33 | ## How to deploy 34 | ``` 35 | npm run build 36 | ``` 37 | 38 | to minify files, then deploy the `public` folder. 39 | 40 | This essentially uses the same script as the `dev` command, but runs it just once and outputs the minified bundle to `public/built`. 41 | -------------------------------------------------------------------------------- /build.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild" 2 | import { sassPlugin } from 'esbuild-sass-plugin' 3 | import { glsl } from "esbuild-plugin-glsl"; 4 | 5 | esbuild.build({ 6 | plugins: [ 7 | sassPlugin({ type: "style" }), 8 | glsl({ minify: true }) 9 | ], 10 | minify: true, 11 | entryPoints: ["src/doomGlareApp.ts", "src/scss/global.scss"], 12 | outdir: "public/built", 13 | bundle: true 14 | }) 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hunter-gatherer-boilerplate", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "hunter-gatherer-boilerplate", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@tweakpane/core": "^1.0.9", 13 | "esbuild": "^0.12.22", 14 | "esbuild-plugin-glsl": "^1.1.0", 15 | "esbuild-sass-plugin": "^2.2.6", 16 | "ogl-typescript": "^0.1.40", 17 | "tweakpane": "^3.0.8" 18 | } 19 | }, 20 | "node_modules/@tweakpane/core": { 21 | "version": "1.0.9", 22 | "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-1.0.9.tgz", 23 | "integrity": "sha512-vvS0IGhJ9Wq37vgldgF9Ohh5BA0RKapffhzyTN84170nt/0SCreXB9zIMLlbL4ZxvCKAKJ0080wJHS5aVhf20Q==" 24 | }, 25 | "node_modules/anymatch": { 26 | "version": "3.1.2", 27 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 28 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 29 | "dependencies": { 30 | "normalize-path": "^3.0.0", 31 | "picomatch": "^2.0.4" 32 | }, 33 | "engines": { 34 | "node": ">= 8" 35 | } 36 | }, 37 | "node_modules/binary-extensions": { 38 | "version": "2.2.0", 39 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 40 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 41 | "engines": { 42 | "node": ">=8" 43 | } 44 | }, 45 | "node_modules/braces": { 46 | "version": "3.0.2", 47 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 48 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 49 | "dependencies": { 50 | "fill-range": "^7.0.1" 51 | }, 52 | "engines": { 53 | "node": ">=8" 54 | } 55 | }, 56 | "node_modules/chokidar": { 57 | "version": "3.5.3", 58 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 59 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 60 | "funding": [ 61 | { 62 | "type": "individual", 63 | "url": "https://paulmillr.com/funding/" 64 | } 65 | ], 66 | "dependencies": { 67 | "anymatch": "~3.1.2", 68 | "braces": "~3.0.2", 69 | "glob-parent": "~5.1.2", 70 | "is-binary-path": "~2.1.0", 71 | "is-glob": "~4.0.1", 72 | "normalize-path": "~3.0.0", 73 | "readdirp": "~3.6.0" 74 | }, 75 | "engines": { 76 | "node": ">= 8.10.0" 77 | }, 78 | "optionalDependencies": { 79 | "fsevents": "~2.3.2" 80 | } 81 | }, 82 | "node_modules/esbuild": { 83 | "version": "0.12.29", 84 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", 85 | "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==", 86 | "hasInstallScript": true, 87 | "bin": { 88 | "esbuild": "bin/esbuild" 89 | } 90 | }, 91 | "node_modules/esbuild-android-64": { 92 | "version": "0.14.36", 93 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz", 94 | "integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==", 95 | "cpu": [ 96 | "x64" 97 | ], 98 | "optional": true, 99 | "os": [ 100 | "android" 101 | ], 102 | "engines": { 103 | "node": ">=12" 104 | } 105 | }, 106 | "node_modules/esbuild-android-arm64": { 107 | "version": "0.14.36", 108 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz", 109 | "integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==", 110 | "cpu": [ 111 | "arm64" 112 | ], 113 | "optional": true, 114 | "os": [ 115 | "android" 116 | ], 117 | "engines": { 118 | "node": ">=12" 119 | } 120 | }, 121 | "node_modules/esbuild-darwin-64": { 122 | "version": "0.14.36", 123 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz", 124 | "integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==", 125 | "cpu": [ 126 | "x64" 127 | ], 128 | "optional": true, 129 | "os": [ 130 | "darwin" 131 | ], 132 | "engines": { 133 | "node": ">=12" 134 | } 135 | }, 136 | "node_modules/esbuild-darwin-arm64": { 137 | "version": "0.14.36", 138 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz", 139 | "integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==", 140 | "cpu": [ 141 | "arm64" 142 | ], 143 | "optional": true, 144 | "os": [ 145 | "darwin" 146 | ], 147 | "engines": { 148 | "node": ">=12" 149 | } 150 | }, 151 | "node_modules/esbuild-freebsd-64": { 152 | "version": "0.14.36", 153 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz", 154 | "integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==", 155 | "cpu": [ 156 | "x64" 157 | ], 158 | "optional": true, 159 | "os": [ 160 | "freebsd" 161 | ], 162 | "engines": { 163 | "node": ">=12" 164 | } 165 | }, 166 | "node_modules/esbuild-freebsd-arm64": { 167 | "version": "0.14.36", 168 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz", 169 | "integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==", 170 | "cpu": [ 171 | "arm64" 172 | ], 173 | "optional": true, 174 | "os": [ 175 | "freebsd" 176 | ], 177 | "engines": { 178 | "node": ">=12" 179 | } 180 | }, 181 | "node_modules/esbuild-linux-32": { 182 | "version": "0.14.36", 183 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz", 184 | "integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==", 185 | "cpu": [ 186 | "ia32" 187 | ], 188 | "optional": true, 189 | "os": [ 190 | "linux" 191 | ], 192 | "engines": { 193 | "node": ">=12" 194 | } 195 | }, 196 | "node_modules/esbuild-linux-64": { 197 | "version": "0.14.36", 198 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz", 199 | "integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==", 200 | "cpu": [ 201 | "x64" 202 | ], 203 | "optional": true, 204 | "os": [ 205 | "linux" 206 | ], 207 | "engines": { 208 | "node": ">=12" 209 | } 210 | }, 211 | "node_modules/esbuild-linux-arm": { 212 | "version": "0.14.36", 213 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz", 214 | "integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==", 215 | "cpu": [ 216 | "arm" 217 | ], 218 | "optional": true, 219 | "os": [ 220 | "linux" 221 | ], 222 | "engines": { 223 | "node": ">=12" 224 | } 225 | }, 226 | "node_modules/esbuild-linux-arm64": { 227 | "version": "0.14.36", 228 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz", 229 | "integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==", 230 | "cpu": [ 231 | "arm64" 232 | ], 233 | "optional": true, 234 | "os": [ 235 | "linux" 236 | ], 237 | "engines": { 238 | "node": ">=12" 239 | } 240 | }, 241 | "node_modules/esbuild-linux-mips64le": { 242 | "version": "0.14.36", 243 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz", 244 | "integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==", 245 | "cpu": [ 246 | "mips64el" 247 | ], 248 | "optional": true, 249 | "os": [ 250 | "linux" 251 | ], 252 | "engines": { 253 | "node": ">=12" 254 | } 255 | }, 256 | "node_modules/esbuild-linux-ppc64le": { 257 | "version": "0.14.36", 258 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz", 259 | "integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==", 260 | "cpu": [ 261 | "ppc64" 262 | ], 263 | "optional": true, 264 | "os": [ 265 | "linux" 266 | ], 267 | "engines": { 268 | "node": ">=12" 269 | } 270 | }, 271 | "node_modules/esbuild-linux-riscv64": { 272 | "version": "0.14.36", 273 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz", 274 | "integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==", 275 | "cpu": [ 276 | "riscv64" 277 | ], 278 | "optional": true, 279 | "os": [ 280 | "linux" 281 | ], 282 | "engines": { 283 | "node": ">=12" 284 | } 285 | }, 286 | "node_modules/esbuild-linux-s390x": { 287 | "version": "0.14.36", 288 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz", 289 | "integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==", 290 | "cpu": [ 291 | "s390x" 292 | ], 293 | "optional": true, 294 | "os": [ 295 | "linux" 296 | ], 297 | "engines": { 298 | "node": ">=12" 299 | } 300 | }, 301 | "node_modules/esbuild-netbsd-64": { 302 | "version": "0.14.36", 303 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz", 304 | "integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==", 305 | "cpu": [ 306 | "x64" 307 | ], 308 | "optional": true, 309 | "os": [ 310 | "netbsd" 311 | ], 312 | "engines": { 313 | "node": ">=12" 314 | } 315 | }, 316 | "node_modules/esbuild-openbsd-64": { 317 | "version": "0.14.36", 318 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz", 319 | "integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==", 320 | "cpu": [ 321 | "x64" 322 | ], 323 | "optional": true, 324 | "os": [ 325 | "openbsd" 326 | ], 327 | "engines": { 328 | "node": ">=12" 329 | } 330 | }, 331 | "node_modules/esbuild-plugin-glsl": { 332 | "version": "1.1.0", 333 | "resolved": "https://registry.npmjs.org/esbuild-plugin-glsl/-/esbuild-plugin-glsl-1.1.0.tgz", 334 | "integrity": "sha512-OBzCa/nRy/Vbm62DBzBnV25p1BfTpvFf2SP2Vv9Ls38sdEEuHzhYT5xTOh3Ghu+77VI4iZsOam19cmjwq5RcJQ==", 335 | "engines": { 336 | "node": ">= 0.10.18" 337 | }, 338 | "peerDependencies": { 339 | "esbuild": "0.x.x" 340 | } 341 | }, 342 | "node_modules/esbuild-sass-plugin": { 343 | "version": "2.2.6", 344 | "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.2.6.tgz", 345 | "integrity": "sha512-WVREJhOS6UlZNoS2FhkOA5980VVKjS6ocUK7YFghJt/94rWDNXxPI+XfkOKlSMbJF/n5wAotr37P8/9KhgkgPQ==", 346 | "dependencies": { 347 | "esbuild": "^0.14.13", 348 | "sass": "^1.49.0" 349 | } 350 | }, 351 | "node_modules/esbuild-sass-plugin/node_modules/esbuild": { 352 | "version": "0.14.36", 353 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz", 354 | "integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==", 355 | "hasInstallScript": true, 356 | "bin": { 357 | "esbuild": "bin/esbuild" 358 | }, 359 | "engines": { 360 | "node": ">=12" 361 | }, 362 | "optionalDependencies": { 363 | "esbuild-android-64": "0.14.36", 364 | "esbuild-android-arm64": "0.14.36", 365 | "esbuild-darwin-64": "0.14.36", 366 | "esbuild-darwin-arm64": "0.14.36", 367 | "esbuild-freebsd-64": "0.14.36", 368 | "esbuild-freebsd-arm64": "0.14.36", 369 | "esbuild-linux-32": "0.14.36", 370 | "esbuild-linux-64": "0.14.36", 371 | "esbuild-linux-arm": "0.14.36", 372 | "esbuild-linux-arm64": "0.14.36", 373 | "esbuild-linux-mips64le": "0.14.36", 374 | "esbuild-linux-ppc64le": "0.14.36", 375 | "esbuild-linux-riscv64": "0.14.36", 376 | "esbuild-linux-s390x": "0.14.36", 377 | "esbuild-netbsd-64": "0.14.36", 378 | "esbuild-openbsd-64": "0.14.36", 379 | "esbuild-sunos-64": "0.14.36", 380 | "esbuild-windows-32": "0.14.36", 381 | "esbuild-windows-64": "0.14.36", 382 | "esbuild-windows-arm64": "0.14.36" 383 | } 384 | }, 385 | "node_modules/esbuild-sunos-64": { 386 | "version": "0.14.36", 387 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz", 388 | "integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==", 389 | "cpu": [ 390 | "x64" 391 | ], 392 | "optional": true, 393 | "os": [ 394 | "sunos" 395 | ], 396 | "engines": { 397 | "node": ">=12" 398 | } 399 | }, 400 | "node_modules/esbuild-windows-32": { 401 | "version": "0.14.36", 402 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz", 403 | "integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==", 404 | "cpu": [ 405 | "ia32" 406 | ], 407 | "optional": true, 408 | "os": [ 409 | "win32" 410 | ], 411 | "engines": { 412 | "node": ">=12" 413 | } 414 | }, 415 | "node_modules/esbuild-windows-64": { 416 | "version": "0.14.36", 417 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz", 418 | "integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==", 419 | "cpu": [ 420 | "x64" 421 | ], 422 | "optional": true, 423 | "os": [ 424 | "win32" 425 | ], 426 | "engines": { 427 | "node": ">=12" 428 | } 429 | }, 430 | "node_modules/esbuild-windows-arm64": { 431 | "version": "0.14.36", 432 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz", 433 | "integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==", 434 | "cpu": [ 435 | "arm64" 436 | ], 437 | "optional": true, 438 | "os": [ 439 | "win32" 440 | ], 441 | "engines": { 442 | "node": ">=12" 443 | } 444 | }, 445 | "node_modules/fill-range": { 446 | "version": "7.0.1", 447 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 448 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 449 | "dependencies": { 450 | "to-regex-range": "^5.0.1" 451 | }, 452 | "engines": { 453 | "node": ">=8" 454 | } 455 | }, 456 | "node_modules/fsevents": { 457 | "version": "2.3.2", 458 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 459 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 460 | "hasInstallScript": true, 461 | "optional": true, 462 | "os": [ 463 | "darwin" 464 | ], 465 | "engines": { 466 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 467 | } 468 | }, 469 | "node_modules/glob-parent": { 470 | "version": "5.1.2", 471 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 472 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 473 | "dependencies": { 474 | "is-glob": "^4.0.1" 475 | }, 476 | "engines": { 477 | "node": ">= 6" 478 | } 479 | }, 480 | "node_modules/immutable": { 481 | "version": "4.0.0", 482 | "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", 483 | "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==" 484 | }, 485 | "node_modules/is-binary-path": { 486 | "version": "2.1.0", 487 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 488 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 489 | "dependencies": { 490 | "binary-extensions": "^2.0.0" 491 | }, 492 | "engines": { 493 | "node": ">=8" 494 | } 495 | }, 496 | "node_modules/is-extglob": { 497 | "version": "2.1.1", 498 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 499 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 500 | "engines": { 501 | "node": ">=0.10.0" 502 | } 503 | }, 504 | "node_modules/is-glob": { 505 | "version": "4.0.3", 506 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 507 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 508 | "dependencies": { 509 | "is-extglob": "^2.1.1" 510 | }, 511 | "engines": { 512 | "node": ">=0.10.0" 513 | } 514 | }, 515 | "node_modules/is-number": { 516 | "version": "7.0.0", 517 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 518 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 519 | "engines": { 520 | "node": ">=0.12.0" 521 | } 522 | }, 523 | "node_modules/normalize-path": { 524 | "version": "3.0.0", 525 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 526 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 527 | "engines": { 528 | "node": ">=0.10.0" 529 | } 530 | }, 531 | "node_modules/ogl-typescript": { 532 | "version": "0.1.40", 533 | "resolved": "https://registry.npmjs.org/ogl-typescript/-/ogl-typescript-0.1.40.tgz", 534 | "integrity": "sha512-7lpT8u35jd9W7Q48enrcCEL4H0x4co6pn5t6rXZgQN7UT39mcdzRsSr4ucZDOvfwKkUT+UvH2zw83/9mT59bFQ==" 535 | }, 536 | "node_modules/picomatch": { 537 | "version": "2.3.1", 538 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 539 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 540 | "engines": { 541 | "node": ">=8.6" 542 | }, 543 | "funding": { 544 | "url": "https://github.com/sponsors/jonschlinkert" 545 | } 546 | }, 547 | "node_modules/readdirp": { 548 | "version": "3.6.0", 549 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 550 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 551 | "dependencies": { 552 | "picomatch": "^2.2.1" 553 | }, 554 | "engines": { 555 | "node": ">=8.10.0" 556 | } 557 | }, 558 | "node_modules/sass": { 559 | "version": "1.50.0", 560 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", 561 | "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", 562 | "dependencies": { 563 | "chokidar": ">=3.0.0 <4.0.0", 564 | "immutable": "^4.0.0", 565 | "source-map-js": ">=0.6.2 <2.0.0" 566 | }, 567 | "bin": { 568 | "sass": "sass.js" 569 | }, 570 | "engines": { 571 | "node": ">=12.0.0" 572 | } 573 | }, 574 | "node_modules/source-map-js": { 575 | "version": "1.0.2", 576 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 577 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 578 | "engines": { 579 | "node": ">=0.10.0" 580 | } 581 | }, 582 | "node_modules/to-regex-range": { 583 | "version": "5.0.1", 584 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 585 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 586 | "dependencies": { 587 | "is-number": "^7.0.0" 588 | }, 589 | "engines": { 590 | "node": ">=8.0" 591 | } 592 | }, 593 | "node_modules/tweakpane": { 594 | "version": "3.0.8", 595 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.0.8.tgz", 596 | "integrity": "sha512-vJuB0346B6gMpxnFDJyy2wcEshkvcTpQ74TCqJTeFaDvzq9FL29h5KszT1+YUTLlP+26OQI8PFGN8WbtOQStnQ==", 597 | "funding": { 598 | "url": "https://github.com/sponsors/cocopon" 599 | } 600 | } 601 | }, 602 | "dependencies": { 603 | "@tweakpane/core": { 604 | "version": "1.0.9", 605 | "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-1.0.9.tgz", 606 | "integrity": "sha512-vvS0IGhJ9Wq37vgldgF9Ohh5BA0RKapffhzyTN84170nt/0SCreXB9zIMLlbL4ZxvCKAKJ0080wJHS5aVhf20Q==" 607 | }, 608 | "anymatch": { 609 | "version": "3.1.2", 610 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 611 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 612 | "requires": { 613 | "normalize-path": "^3.0.0", 614 | "picomatch": "^2.0.4" 615 | } 616 | }, 617 | "binary-extensions": { 618 | "version": "2.2.0", 619 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 620 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" 621 | }, 622 | "braces": { 623 | "version": "3.0.2", 624 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 625 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 626 | "requires": { 627 | "fill-range": "^7.0.1" 628 | } 629 | }, 630 | "chokidar": { 631 | "version": "3.5.3", 632 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 633 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 634 | "requires": { 635 | "anymatch": "~3.1.2", 636 | "braces": "~3.0.2", 637 | "fsevents": "~2.3.2", 638 | "glob-parent": "~5.1.2", 639 | "is-binary-path": "~2.1.0", 640 | "is-glob": "~4.0.1", 641 | "normalize-path": "~3.0.0", 642 | "readdirp": "~3.6.0" 643 | } 644 | }, 645 | "esbuild": { 646 | "version": "0.12.29", 647 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz", 648 | "integrity": "sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==" 649 | }, 650 | "esbuild-android-64": { 651 | "version": "0.14.36", 652 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz", 653 | "integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==", 654 | "optional": true 655 | }, 656 | "esbuild-android-arm64": { 657 | "version": "0.14.36", 658 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz", 659 | "integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==", 660 | "optional": true 661 | }, 662 | "esbuild-darwin-64": { 663 | "version": "0.14.36", 664 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz", 665 | "integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==", 666 | "optional": true 667 | }, 668 | "esbuild-darwin-arm64": { 669 | "version": "0.14.36", 670 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz", 671 | "integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==", 672 | "optional": true 673 | }, 674 | "esbuild-freebsd-64": { 675 | "version": "0.14.36", 676 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz", 677 | "integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==", 678 | "optional": true 679 | }, 680 | "esbuild-freebsd-arm64": { 681 | "version": "0.14.36", 682 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz", 683 | "integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==", 684 | "optional": true 685 | }, 686 | "esbuild-linux-32": { 687 | "version": "0.14.36", 688 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz", 689 | "integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==", 690 | "optional": true 691 | }, 692 | "esbuild-linux-64": { 693 | "version": "0.14.36", 694 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz", 695 | "integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==", 696 | "optional": true 697 | }, 698 | "esbuild-linux-arm": { 699 | "version": "0.14.36", 700 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz", 701 | "integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==", 702 | "optional": true 703 | }, 704 | "esbuild-linux-arm64": { 705 | "version": "0.14.36", 706 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz", 707 | "integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==", 708 | "optional": true 709 | }, 710 | "esbuild-linux-mips64le": { 711 | "version": "0.14.36", 712 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz", 713 | "integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==", 714 | "optional": true 715 | }, 716 | "esbuild-linux-ppc64le": { 717 | "version": "0.14.36", 718 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz", 719 | "integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==", 720 | "optional": true 721 | }, 722 | "esbuild-linux-riscv64": { 723 | "version": "0.14.36", 724 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz", 725 | "integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==", 726 | "optional": true 727 | }, 728 | "esbuild-linux-s390x": { 729 | "version": "0.14.36", 730 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz", 731 | "integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==", 732 | "optional": true 733 | }, 734 | "esbuild-netbsd-64": { 735 | "version": "0.14.36", 736 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz", 737 | "integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==", 738 | "optional": true 739 | }, 740 | "esbuild-openbsd-64": { 741 | "version": "0.14.36", 742 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz", 743 | "integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==", 744 | "optional": true 745 | }, 746 | "esbuild-plugin-glsl": { 747 | "version": "1.1.0", 748 | "resolved": "https://registry.npmjs.org/esbuild-plugin-glsl/-/esbuild-plugin-glsl-1.1.0.tgz", 749 | "integrity": "sha512-OBzCa/nRy/Vbm62DBzBnV25p1BfTpvFf2SP2Vv9Ls38sdEEuHzhYT5xTOh3Ghu+77VI4iZsOam19cmjwq5RcJQ==", 750 | "requires": {} 751 | }, 752 | "esbuild-sass-plugin": { 753 | "version": "2.2.6", 754 | "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.2.6.tgz", 755 | "integrity": "sha512-WVREJhOS6UlZNoS2FhkOA5980VVKjS6ocUK7YFghJt/94rWDNXxPI+XfkOKlSMbJF/n5wAotr37P8/9KhgkgPQ==", 756 | "requires": { 757 | "esbuild": "^0.14.13", 758 | "sass": "^1.49.0" 759 | }, 760 | "dependencies": { 761 | "esbuild": { 762 | "version": "0.14.36", 763 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz", 764 | "integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==", 765 | "requires": { 766 | "esbuild-android-64": "0.14.36", 767 | "esbuild-android-arm64": "0.14.36", 768 | "esbuild-darwin-64": "0.14.36", 769 | "esbuild-darwin-arm64": "0.14.36", 770 | "esbuild-freebsd-64": "0.14.36", 771 | "esbuild-freebsd-arm64": "0.14.36", 772 | "esbuild-linux-32": "0.14.36", 773 | "esbuild-linux-64": "0.14.36", 774 | "esbuild-linux-arm": "0.14.36", 775 | "esbuild-linux-arm64": "0.14.36", 776 | "esbuild-linux-mips64le": "0.14.36", 777 | "esbuild-linux-ppc64le": "0.14.36", 778 | "esbuild-linux-riscv64": "0.14.36", 779 | "esbuild-linux-s390x": "0.14.36", 780 | "esbuild-netbsd-64": "0.14.36", 781 | "esbuild-openbsd-64": "0.14.36", 782 | "esbuild-sunos-64": "0.14.36", 783 | "esbuild-windows-32": "0.14.36", 784 | "esbuild-windows-64": "0.14.36", 785 | "esbuild-windows-arm64": "0.14.36" 786 | } 787 | } 788 | } 789 | }, 790 | "esbuild-sunos-64": { 791 | "version": "0.14.36", 792 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz", 793 | "integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==", 794 | "optional": true 795 | }, 796 | "esbuild-windows-32": { 797 | "version": "0.14.36", 798 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz", 799 | "integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==", 800 | "optional": true 801 | }, 802 | "esbuild-windows-64": { 803 | "version": "0.14.36", 804 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz", 805 | "integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==", 806 | "optional": true 807 | }, 808 | "esbuild-windows-arm64": { 809 | "version": "0.14.36", 810 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz", 811 | "integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==", 812 | "optional": true 813 | }, 814 | "fill-range": { 815 | "version": "7.0.1", 816 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 817 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 818 | "requires": { 819 | "to-regex-range": "^5.0.1" 820 | } 821 | }, 822 | "fsevents": { 823 | "version": "2.3.2", 824 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 825 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 826 | "optional": true 827 | }, 828 | "glob-parent": { 829 | "version": "5.1.2", 830 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 831 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 832 | "requires": { 833 | "is-glob": "^4.0.1" 834 | } 835 | }, 836 | "immutable": { 837 | "version": "4.0.0", 838 | "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", 839 | "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==" 840 | }, 841 | "is-binary-path": { 842 | "version": "2.1.0", 843 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 844 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 845 | "requires": { 846 | "binary-extensions": "^2.0.0" 847 | } 848 | }, 849 | "is-extglob": { 850 | "version": "2.1.1", 851 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 852 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" 853 | }, 854 | "is-glob": { 855 | "version": "4.0.3", 856 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 857 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 858 | "requires": { 859 | "is-extglob": "^2.1.1" 860 | } 861 | }, 862 | "is-number": { 863 | "version": "7.0.0", 864 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 865 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 866 | }, 867 | "normalize-path": { 868 | "version": "3.0.0", 869 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 870 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" 871 | }, 872 | "ogl-typescript": { 873 | "version": "0.1.40", 874 | "resolved": "https://registry.npmjs.org/ogl-typescript/-/ogl-typescript-0.1.40.tgz", 875 | "integrity": "sha512-7lpT8u35jd9W7Q48enrcCEL4H0x4co6pn5t6rXZgQN7UT39mcdzRsSr4ucZDOvfwKkUT+UvH2zw83/9mT59bFQ==" 876 | }, 877 | "picomatch": { 878 | "version": "2.3.1", 879 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 880 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" 881 | }, 882 | "readdirp": { 883 | "version": "3.6.0", 884 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 885 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 886 | "requires": { 887 | "picomatch": "^2.2.1" 888 | } 889 | }, 890 | "sass": { 891 | "version": "1.50.0", 892 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", 893 | "integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", 894 | "requires": { 895 | "chokidar": ">=3.0.0 <4.0.0", 896 | "immutable": "^4.0.0", 897 | "source-map-js": ">=0.6.2 <2.0.0" 898 | } 899 | }, 900 | "source-map-js": { 901 | "version": "1.0.2", 902 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 903 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" 904 | }, 905 | "to-regex-range": { 906 | "version": "5.0.1", 907 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 908 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 909 | "requires": { 910 | "is-number": "^7.0.0" 911 | } 912 | }, 913 | "tweakpane": { 914 | "version": "3.0.8", 915 | "resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.0.8.tgz", 916 | "integrity": "sha512-vJuB0346B6gMpxnFDJyy2wcEshkvcTpQ74TCqJTeFaDvzq9FL29h5KszT1+YUTLlP+26OQI8PFGN8WbtOQStnQ==" 917 | } 918 | } 919 | } 920 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hunter-gatherer-boilerplate", 3 | "version": "1.0.0", 4 | "description": "my boilerplate", 5 | "main": "./src/app.ts", 6 | "scripts": { 7 | "build": "node build.mjs", 8 | "dev": "node watch.mjs" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/michaeldll/hunter-gatherer-boilerplate.git" 13 | }, 14 | "author": "michael.dll", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/michaeldll/hunter-gatherer-boilerplate/issues" 18 | }, 19 | "homepage": "https://github.com/michaeldll/hunter-gatherer-boilerplate#readme", 20 | "dependencies": { 21 | "esbuild": "^0.12.22", 22 | "esbuild-plugin-glsl": "^1.1.0", 23 | "esbuild-sass-plugin": "^2.2.6", 24 | "ogl-typescript": "^0.1.40", 25 | "@tweakpane/core": "^1.0.9", 26 | "tweakpane": "^3.0.8" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-Bold.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-BoldItalic.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-ExtraBold.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-Italic.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-Light.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-LightItalic.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-Regular.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/opensans/OpenSans-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/assets/fonts/opensans/OpenSans-SemiBold.woff2 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldll/webgl-doom-glare/a2914424f4fdb5388282131d6b966b113e202ffc/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | hunter-gatherer boilerplate 🧗‍♂️ 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/doomGlareApp.ts: -------------------------------------------------------------------------------- 1 | import "./scss/global.scss"; 2 | import WebGLController from "./webgl/WebGLController"; 3 | 4 | const init = () => { 5 | 6 | const controller = new WebGLController(document.querySelector(".canvas-gl")) 7 | 8 | let raf: number 9 | const tick = () => { 10 | controller.tick() 11 | raf = requestAnimationFrame(tick) 12 | } 13 | 14 | tick() 15 | }; 16 | 17 | init() -------------------------------------------------------------------------------- /src/scss/global.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Open Sans"; 3 | src: url("assets/fonts/opensans/OpenSans-Regular.woff2") format("woff2"); 4 | font-weight: 400; 5 | font-display: swap; 6 | } 7 | 8 | body { 9 | font-family: "Open Sans", sans-serif; 10 | margin: 0; 11 | overflow: hidden; 12 | } 13 | 14 | 15 | main { 16 | background: black; 17 | 18 | // Only when OGL 19 | .canvas-gl{ 20 | width: 100%!important; 21 | height: 100vh!important; 22 | } 23 | } 24 | 25 | .tp-dfwv { 26 | // display: none; 27 | } -------------------------------------------------------------------------------- /src/types/Attributes.ts: -------------------------------------------------------------------------------- 1 | export type TypedArray = 2 | | Int8Array 3 | | Uint8Array 4 | | Uint8ClampedArray 5 | | Int16Array 6 | | Uint16Array 7 | | Int32Array 8 | | Uint32Array 9 | | Float32Array 10 | | Float64Array; 11 | 12 | export type Attribute = { 13 | value: TypedArray, 14 | size: number 15 | } 16 | 17 | export type Attributes = { [name: string]: Attribute } -------------------------------------------------------------------------------- /src/types/modules/shaders.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.wgsl" { 2 | const value: string; 3 | export default value; 4 | } 5 | 6 | declare module "*.glsl" { 7 | const value: string; 8 | export default value; 9 | } 10 | 11 | declare module "*.frag" { 12 | const value: string; 13 | export default value; 14 | } 15 | 16 | declare module "*.vert" { 17 | const value: string; 18 | export default value; 19 | } -------------------------------------------------------------------------------- /src/utils/libs/drawable/Drawable.ts: -------------------------------------------------------------------------------- 1 | import { Camera, OGLRenderingContext, Transform } from 'ogl-typescript' 2 | import { DrawableMaterial } from './DrawableMaterial' 3 | import { DrawableGeometry } from './DrawableGeometry' 4 | 5 | export type Context = WebGLRenderingContext & { createVertexArray, bindVertexArray } | OGLRenderingContext & { createVertexArray, bindVertexArray } 6 | 7 | /** 8 | * A barebones WebGL entity that also works with OGL's renderer and Scene Graph 9 | * @author @michael.dll 10 | */ 11 | export abstract class Drawable extends Transform { 12 | public gl: Context 13 | public material: DrawableMaterial 14 | public geometry: DrawableGeometry 15 | public name: string 16 | public mode: number // e.g.: WebGLRenderingContext["TRIANGLES"] 17 | 18 | constructor(gl: WebGLRenderingContext | OGLRenderingContext, { material, geometry, name = "Drawable" }) { 19 | super() 20 | 21 | this.gl = gl as Context 22 | this.mode = gl.TRIANGLES 23 | this.material = material 24 | this.geometry = geometry 25 | this.name = name 26 | } 27 | 28 | onBeforeDraw = ({ camera }: { camera: Camera }) => { } 29 | 30 | onPostDraw = ({ camera }: { camera: Camera }) => { } 31 | 32 | draw = ({ camera }: { camera: Camera }) => { 33 | if (!this.visible) return 34 | 35 | this.gl.useProgram(this.material.program); 36 | 37 | if(this.geometry.dynamic === false) this.gl.bindVertexArray(this.geometry.vao) 38 | else this.geometry.setAttributes() 39 | 40 | this.onBeforeDraw({ camera }) 41 | 42 | if (this.geometry.attributes.index) { 43 | const vertexCount = this.geometry.attributes.index.value.length 44 | const type = this.gl.UNSIGNED_SHORT; 45 | const offset = 0; 46 | this.gl.drawElements(this.mode, vertexCount, type, offset); 47 | } 48 | 49 | else this.gl.drawArrays(this.mode, 0, this.geometry.attributes.position.value.length / 3); 50 | 51 | if(this.geometry.dynamic === false) this.gl.bindVertexArray(this.geometry.vao) 52 | 53 | this.onPostDraw({ camera }) 54 | } 55 | } -------------------------------------------------------------------------------- /src/utils/libs/drawable/DrawableGeometry.ts: -------------------------------------------------------------------------------- 1 | import { Attributes } from "@/types/Attributes" 2 | import { OGLRenderingContext } from "ogl-typescript" 3 | import { Context } from "./Drawable" 4 | import { Locations } from "./types" 5 | 6 | type Buffers = { [name: string]: WebGLBuffer } 7 | 8 | export class DrawableGeometry { 9 | public vao : ReturnType 10 | public attributes: Attributes 11 | public dynamic : boolean 12 | public buffers: Buffers = {} 13 | 14 | private gl: Context 15 | private locations: Locations 16 | 17 | /** 18 | * Only sets buffers by default 19 | * setAttributes() and setVAO() should be set by the user depending on wheter the attributes are dynamic or not, respectively 20 | */ 21 | constructor(gl: WebGLRenderingContext | OGLRenderingContext, locations: Locations, attributes: Attributes, dynamic = false) { 22 | this.gl = gl as Context 23 | this.locations = locations 24 | this.attributes = attributes; 25 | this.dynamic = dynamic 26 | 27 | this.setBuffers() 28 | } 29 | 30 | setBuffers = (usage : number = this.gl.STATIC_DRAW) => { 31 | for (const [prop, data] of Object.entries(this.attributes)) { 32 | this.buffers[prop] = this.getBuffer(prop, data.value, usage) 33 | } 34 | } 35 | 36 | getBuffer = (prop: string, array: BufferSource, usage: number) => { 37 | const buffer = this.gl.createBuffer(); 38 | 39 | if (prop === "index") { 40 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, buffer); 41 | this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, array, usage); 42 | } else { 43 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer); 44 | this.gl.bufferData(this.gl.ARRAY_BUFFER, array, usage); 45 | } 46 | 47 | return buffer 48 | } 49 | 50 | setAttributes = () => { 51 | // Position 52 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.position) 53 | 54 | const positionLocation = this.locations.attributes.position 55 | if(typeof positionLocation === "undefined") throw new Error(`No attribute location provided`) 56 | const numComponents = this.attributes.position.size; 57 | this.gl.enableVertexAttribArray(positionLocation); 58 | this.gl.vertexAttribPointer(positionLocation, numComponents, this.gl.FLOAT, false, 0, 0); 59 | 60 | // Normal 61 | if (this.attributes.normal) { 62 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.normal) 63 | 64 | const normalLocation = this.locations.attributes.normal 65 | const numComponents = this.attributes.normal.size 66 | this.gl.enableVertexAttribArray(normalLocation); 67 | this.gl.vertexAttribPointer(normalLocation, numComponents, this.gl.FLOAT, false, 0, 0); 68 | } 69 | 70 | // UV 71 | if (this.attributes.uv) { 72 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.uv) 73 | 74 | const uvLocation = this.locations.attributes.uv 75 | const numComponents = this.attributes.uv.size; 76 | this.gl.enableVertexAttribArray(uvLocation); 77 | this.gl.vertexAttribPointer(uvLocation, numComponents, this.gl.FLOAT, false, 0, 0); 78 | } 79 | 80 | // Color 81 | if (this.attributes.color) { 82 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffers.color) 83 | 84 | const colorLocation = this.locations.attributes.color 85 | const numComponents = this.attributes.color.size; 86 | this.gl.enableVertexAttribArray(colorLocation); 87 | this.gl.vertexAttribPointer(colorLocation, numComponents, this.gl.FLOAT, false, 0, 0); 88 | } 89 | 90 | if (this.attributes.index) { 91 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.buffers.index); 92 | } 93 | } 94 | 95 | setVAO = () => { 96 | this.vao = this.gl.createVertexArray() 97 | this.gl.bindVertexArray(this.vao) 98 | 99 | this.setAttributes() 100 | 101 | this.gl.bindVertexArray(null) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/utils/libs/drawable/DrawableMaterial.ts: -------------------------------------------------------------------------------- 1 | import { OGLRenderingContext } from "ogl-typescript" 2 | import { Locations } from "./types" 3 | 4 | 5 | type Props = { vertex: string, fragment: string, attributes: string[], uniforms: string[] } 6 | export class DrawableMaterial { 7 | public program : WebGLProgram 8 | public locations : Locations 9 | private gl : WebGLRenderingContext | OGLRenderingContext 10 | 11 | /** 12 | * Associates attribute and uniform locations w/ a program 13 | */ 14 | constructor(gl : WebGLRenderingContext | OGLRenderingContext, { 15 | vertex, 16 | fragment, 17 | attributes, 18 | uniforms 19 | }: Props) { 20 | this.gl = gl 21 | this.program = this.getProgram(vertex, fragment) 22 | this.locations = this.getLocations(attributes, uniforms) 23 | } 24 | 25 | /** 26 | * Fetch attribute locations from program 27 | */ 28 | getLocations = (attributes: string[], uniforms: string[]) => { 29 | const locations = { 30 | attributes: {}, 31 | uniforms: {} 32 | } 33 | 34 | for (const attribute of attributes) { 35 | locations.attributes[attribute] = this.gl.getAttribLocation(this.program, attribute) 36 | } 37 | 38 | for (const uniform of uniforms) { 39 | locations.uniforms[uniform] = this.gl.getUniformLocation(this.program, uniform) 40 | } 41 | 42 | return locations 43 | } 44 | 45 | /** 46 | * Create and compile shader 47 | * @returns WebGLShader, or null if not compiled 48 | */ 49 | getShader = (type: number, source: string) => { 50 | const shader = this.gl.createShader(type); 51 | 52 | // Send the source to the shader object 53 | this.gl.shaderSource(shader, source); 54 | 55 | this.gl.compileShader(shader); 56 | 57 | // Check if it compiled successfully 58 | if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { 59 | console.error('An error occurred compiling the shaders: ' + this.gl.getShaderInfoLog(shader)); 60 | console.error(source) 61 | this.gl.deleteShader(shader); 62 | return null; 63 | } 64 | 65 | return shader; 66 | } 67 | 68 | /** 69 | * Create and link program 70 | * @returns WebGLProgram, or null if not linked. 71 | */ 72 | getProgram = (vertex: string, fragment: string) => { 73 | const vertexShader = this.getShader(this.gl.VERTEX_SHADER, vertex); 74 | const fragmentShader = this.getShader(this.gl.FRAGMENT_SHADER, fragment); 75 | 76 | const program = this.gl.createProgram(); 77 | this.gl.attachShader(program, vertexShader); 78 | this.gl.attachShader(program, fragmentShader); 79 | this.gl.linkProgram(program); 80 | 81 | // Check if it linked successfully 82 | if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) { 83 | console.error('Unable to initialize the shader program: ' + this.gl.getProgramInfoLog(program)); 84 | return null; 85 | } 86 | 87 | return program; 88 | } 89 | } -------------------------------------------------------------------------------- /src/utils/libs/drawable/Plane.ts: -------------------------------------------------------------------------------- 1 | import loadImage from "@/utils/misc/misc"; 2 | import { Camera, Mat4 } from "ogl-typescript"; 3 | import { Drawable } from "./Drawable"; 4 | import { DrawableGeometry } from "./DrawableGeometry"; 5 | import { DrawableMaterial } from "./DrawableMaterial"; 6 | 7 | export const PlaneAttributes = { 8 | position: { 9 | value: new Float32Array([ 10 | -1.0, -1.0, 0.0, 11 | 1.0, -1.0, 0.0, 12 | 1.0, 1.0, 0.0, 13 | -1.0, 1.0, 0.0, 14 | ]), 15 | size: 3 16 | }, 17 | normal: { 18 | value: new Float32Array([ 19 | 0.0, 0.0, 1.0, 20 | 0.0, 0.0, 1.0, 21 | 0.0, 0.0, 1.0, 22 | 0.0, 0.0, 1.0, 23 | ]), 24 | size: 3 25 | }, 26 | uv: { 27 | value: new Float32Array([ 28 | 0.0, 0.0, 29 | 1.0, 0.0, 30 | 1.0, 1.0, 31 | 0.0, 1.0, 32 | ]), 33 | size: 2 34 | }, 35 | index: { 36 | value: new Uint16Array([ 37 | 0, 1, 2, 0, 2, 3, 38 | ]), 39 | size: 1 40 | }, 41 | } 42 | 43 | export default class Plane extends Drawable { 44 | texture : WebGLTexture 45 | modelViewMatrix : Mat4 46 | worldMatrix: Mat4 47 | 48 | constructor(gl) { 49 | const vertex = /* glsl */ ` 50 | attribute vec3 position; 51 | attribute vec2 uv; 52 | attribute vec3 normal; 53 | 54 | uniform mat4 uWorldMatrix; 55 | // uniform mat4 modelViewMatrix; 56 | // uniform mat4 projectionMatrix; 57 | 58 | varying vec2 vUv; 59 | varying vec3 vNormal; 60 | 61 | void main() { 62 | vUv = uv; 63 | vNormal = normal; 64 | 65 | gl_Position = uWorldMatrix * vec4(position, 1.0); 66 | } 67 | `; 68 | 69 | const fragment = /* glsl */ ` 70 | precision mediump float; 71 | 72 | uniform sampler2D uTexture; 73 | 74 | varying vec2 vUv; 75 | varying vec3 vNormal; 76 | 77 | void main() { 78 | gl_FragColor = texture2D(uTexture, vUv); 79 | 80 | // Debug : 81 | // gl_FragColor = vec4(vUv.x, vUv.y, 0., 1.); 82 | // gl_FragColor = vec4(1., 0., 0., 1.); 83 | } 84 | `; 85 | 86 | // Attributes need to be active in the program for location fetching to work ! 87 | const material = new DrawableMaterial(gl, { 88 | vertex, 89 | fragment, 90 | attributes: ['position', 'uv', 'normal'], 91 | uniforms: ['uWorldMatrix', 'uTexture'] 92 | }) 93 | 94 | // Plane 95 | const geometry = new DrawableGeometry(gl, material.locations, PlaneAttributes) 96 | 97 | super(gl, { 98 | material, 99 | geometry 100 | }) 101 | 102 | this.gl = gl 103 | 104 | // Create texture containing a 1x1 blue pixel. 105 | this.texture = gl.createTexture(); 106 | 107 | // Enable texture 0 108 | gl.activeTexture(gl.TEXTURE0); 109 | 110 | // Set the texture's target (2D or cubemap) 111 | gl.bindTexture(gl.TEXTURE_2D, this.texture); 112 | 113 | // Fill the texture with a 1x1 blue pixel. 114 | const width = 1 115 | const height = 1 116 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255])); 117 | 118 | // Pass texture 0 to the sampler 119 | gl.useProgram(this.material.program); 120 | gl.uniform1i(this.material.locations.uniforms.uTexture, 0); 121 | } 122 | 123 | load = () => { 124 | loadImage(`UV_Grid.png`).then((image) => { 125 | // console.log(image); 126 | 127 | // Flip the image's y axis 128 | this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1); 129 | 130 | // Enable texture 0 131 | this.gl.activeTexture(this.gl.TEXTURE0); 132 | 133 | // Set the texture's target (2D or cubemap) 134 | this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture); 135 | 136 | // Stretch/wrap options 137 | this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl["LINEAR"]); 138 | 139 | // Bind image to texture 0 140 | this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.gl.RGB, this.gl.UNSIGNED_BYTE, image); 141 | 142 | // Mipmaps 143 | this.gl.generateMipmap(this.gl.TEXTURE_2D); 144 | 145 | // Pass texture 0 to the sampler 146 | this.gl.useProgram(this.material.program); 147 | this.gl.uniform1i(this.material.locations.uniforms.uTexture, 0); 148 | 149 | this.gl.activeTexture(this.gl.TEXTURE0); 150 | }) 151 | } 152 | 153 | onBeforeDraw = ({ camera }: { camera: Camera }) => { 154 | this.gl.activeTexture(this.gl.TEXTURE0) 155 | this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture) 156 | this.gl.uniform1i(this.material.locations.uniforms.uTexture, 0); 157 | 158 | // World Matrix 159 | this.updateMatrix() 160 | this.gl.uniformMatrix4fv(this.material.locations.uniforms.uWorldMatrix, false, this.matrix) 161 | 162 | if (!camera) return 163 | // this.gl.uniformMatrix4fv(this.material.locations.uniforms.cameraWorldPosition, false, camera.worldPosition) 164 | // this.gl.uniformMatrix4fv(this.material.locations.uniforms.viewMatrix, false, camera.viewMatrix) 165 | 166 | // this.gl.uniformMatrix4fv(this.material.locations.uniforms.projectionMatrix, false, camera.projectionMatrix) 167 | // this.modelViewMatrix.multiply(camera.viewMatrix, this.matrix); 168 | // this.gl.uniformMatrix4fv(this.material.locations.uniforms.modelViewMatrix, false, this.modelViewMatrix) 169 | } 170 | } -------------------------------------------------------------------------------- /src/utils/libs/drawable/README.md: -------------------------------------------------------------------------------- 1 | A micro framework to make native WebGL work within OGL's scene graph and renderer, by michael.dll -------------------------------------------------------------------------------- /src/utils/libs/drawable/types.ts: -------------------------------------------------------------------------------- 1 | export type Buffers = { 2 | [bufferName: string]: WebGLBuffer | null 3 | } 4 | 5 | export type Locations = { 6 | attributes: { 7 | [attributeName: string]:number 8 | }, 9 | uniforms: { 10 | [uniformName: string]: number 11 | } 12 | } 13 | 14 | export type Geometry = { 15 | positions?: Float32Array // For easier super() behavior in meshes/ 16 | normals?: Float32Array 17 | indices?: Uint16Array 18 | colors?: Float32Array 19 | uvs?: Float32Array 20 | } 21 | 22 | export type Vector3 = { 23 | x: number, 24 | y: number, 25 | z: number 26 | } 27 | 28 | export type MeshParameters = { 29 | position?: Vector3, 30 | rotation?: Vector3, 31 | scale?: Vector3 32 | } 33 | 34 | export type MeshConstructor = { 35 | shaders: [string, string], 36 | locationNames: { 37 | attributes: string[] 38 | uniforms: string[] 39 | } 40 | gl: WebGLRenderingContext 41 | parameters?: MeshParameters 42 | name?: string 43 | } -------------------------------------------------------------------------------- /src/utils/math/math.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns A number in the range [min, max] 3 | */ 4 | export function clamp(value: number, min: number, max: number) { 5 | return Math.min(max, Math.max(min, value)); 6 | } 7 | 8 | /** 9 | * @returns Value mapped to the range [out_min, out_max] 10 | */ 11 | export function map( 12 | value: number, 13 | in_min: number, 14 | in_max: number, 15 | out_min: number, 16 | out_max: number 17 | ) { 18 | return ((value - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min; 19 | } 20 | 21 | /** 22 | * @description Linearly interpolate 23 | */ 24 | export function lerp(start: number, end: number, alpha: number) { 25 | return (1 - alpha) * start + alpha * end; 26 | } 27 | 28 | /** 29 | * @returns Average of an array 30 | */ 31 | export function getAverage(arr: Array) { 32 | let sum = 0; 33 | 34 | for (let index = 0; index < arr.length; index++) { 35 | sum = sum + arr[index]; 36 | } 37 | 38 | const avg = sum / arr.length; 39 | 40 | return avg !== Infinity ? avg : 0; 41 | } 42 | 43 | // Warning: might be slow as it parses string 44 | export function round(value: number, significantNumbers: number) { 45 | return Number.parseFloat(value.toFixed(significantNumbers)); 46 | } 47 | 48 | /** 49 | * @returns Normalized value 50 | */ 51 | export function normalize(val: number, max: number, min: number) { 52 | return (val - min) / (max - min); 53 | } 54 | 55 | /** 56 | * @returns Distance between two points w/ pythagoras 57 | */ 58 | export function distance(x1: any, y1: any, x2: any, y2: any) { 59 | return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) 60 | } 61 | 62 | export const polarToCartesian = (radius: number, theta: number) => { 63 | return [radius * Math.cos(theta), radius * Math.sin(theta)] as [number, number] 64 | } -------------------------------------------------------------------------------- /src/utils/misc/misc.ts: -------------------------------------------------------------------------------- 1 | export function ready(cb: Function) { 2 | if (document.readyState != 'loading') { 3 | cb(); 4 | } else { 5 | document.addEventListener('DOMContentLoaded', (e) => cb()); 6 | } 7 | } 8 | 9 | export default function loadImage(path: string): Promise { 10 | return new Promise((resolve) => { 11 | const image = new Image(); 12 | image.src = path; 13 | image.onload = () => { 14 | resolve(image) 15 | } 16 | }) 17 | } -------------------------------------------------------------------------------- /src/webgl/WebGLController.ts: -------------------------------------------------------------------------------- 1 | import { Pane } from "tweakpane"; 2 | import GlareScene from "./scenes/GlareScene"; 3 | import { Renderer } from "ogl-typescript"; 4 | 5 | export default class WebGLController { 6 | public glareScene: GlareScene 7 | 8 | private canvas: HTMLCanvasElement; 9 | private renderer: Renderer; 10 | private pane = new Pane() 11 | 12 | constructor(canvas: HTMLCanvasElement) { 13 | this.canvas = canvas; 14 | 15 | this.setRenderer(true); 16 | 17 | this.glareScene = new GlareScene({ 18 | renderer: this.renderer, 19 | pane: this.pane, 20 | }) 21 | 22 | this.tweaks() 23 | } 24 | 25 | public setRenderer = (antialias = false) => { 26 | this.renderer = new Renderer({ 27 | canvas: this.canvas, 28 | powerPreference: "high-performance", 29 | antialias, 30 | dpr: Math.min(window.devicePixelRatio, 2), 31 | stencil: false 32 | }); 33 | 34 | // (this.renderer.gl as any).clearColor(...new Color("#504f7d"), 1); 35 | }; 36 | 37 | private tweaks = () => { 38 | } 39 | 40 | public tick = () => { 41 | if (this.glareScene) { 42 | this.glareScene.tick(); 43 | 44 | this.renderer.render({ 45 | scene: this.glareScene.scene, 46 | camera: this.glareScene.camera 47 | }) 48 | } 49 | 50 | if (!this.pane.hidden) this.pane.refresh() 51 | }; 52 | 53 | public unmount = () => { 54 | this.glareScene.scene.traverse((transform) => { 55 | const casted = transform as any 56 | if (casted.geometry) { 57 | casted.geometry.remove() 58 | } 59 | if (casted.program) { 60 | casted.program.remove() 61 | } 62 | }) 63 | 64 | this.glareScene.removeEvents() 65 | 66 | this.pane.dispose() 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /src/webgl/components/GlarePlane.ts: -------------------------------------------------------------------------------- 1 | import { Camera, Mat4, OGLRenderingContext, Vec3 } from "ogl-typescript"; 2 | import { Context, Drawable } from "@/utils/libs/drawable/Drawable"; 3 | import { DrawableGeometry } from "@/utils/libs/drawable/DrawableGeometry"; 4 | import { clamp, map } from "@/utils/math/math"; 5 | import GlarePlaneMaterial from "@/webgl/materials/GlarePlaneMaterial"; 6 | 7 | export default class GlarePlane extends Drawable { 8 | public quadColor = [1, 1, 1, .95] 9 | public edgeColor = [0, 0, 0, 0] 10 | public program = { transparent: true, depthTest: false } // For OGL 11 | public wireframe = false 12 | 13 | private modelViewMatrix = new Mat4() 14 | private vertices : Vec3[] = [] 15 | 16 | constructor(gl: WebGLRenderingContext | OGLRenderingContext) { 17 | const material = new GlarePlaneMaterial(gl) 18 | 19 | const attributes = { 20 | position: { 21 | value: new Float32Array([ 22 | -1.0, -1.0, 0.0, 23 | 1.0, -1.0, 0.0, 24 | 1.0, 1.0, 0.0, 25 | -1.0, 1.0, 0.0, 26 | 27 | -1.0, -1.0, 0.0, 28 | 1.0, -1.0, 0.0, 29 | 1.0, 1.0, 0.0, 30 | -1.0, 1.0, 0.0, 31 | 32 | -1.0, -1.0, 0.0, 33 | 1.0, -1.0, 0.0, 34 | 1.0, 1.0, 0.0, 35 | -1.0, 1.0, 0.0, 36 | 37 | -1.0, -1.0, 0.0, 38 | 1.0, -1.0, 0.0, 39 | 1.0, 1.0, 0.0, 40 | -1.0, 1.0, 0.0, 41 | ]), 42 | size: 3 43 | }, 44 | uv: { 45 | value: new Float32Array([ 46 | 0.0, 0.0, 47 | 1.0, 0.0, 48 | 1.0, 1.0, 49 | 0.0, 1.0, 50 | 51 | 1.0, 0.0, 52 | 1.0, 0.0, 53 | 1.0, 0.0, 54 | 1.0, 0.0, 55 | 56 | 1.0, 0.0, 57 | 1.0, 0.0, 58 | 1.0, 0.0, 59 | 1.0, 0.0, 60 | 61 | 1.0, 0.0, 62 | 1.0, 0.0, 63 | 1.0, 0.0, 64 | 1.0, 0.0, 65 | ]), 66 | size: 2 67 | }, 68 | color: { 69 | value: new Float32Array([ 70 | 1.0, 1.0, 1.0, 1.0, 71 | 1.0, 1.0, 1.0, 1.0, 72 | 1.0, 1.0, 1.0, 1.0, 73 | 1.0, 1.0, 1.0, 1.0, 74 | 75 | 1.0, 1.0, 1.0, 1.0, 76 | 1.0, 1.0, 1.0, 1.0, 77 | 1.0, 1.0, 1.0, 1.0, 78 | 1.0, 1.0, 1.0, 1.0, 79 | 80 | 1.0, 1.0, 1.0, 1.0, 81 | 1.0, 1.0, 1.0, 1.0, 82 | 1.0, 1.0, 1.0, 1.0, 83 | 1.0, 1.0, 1.0, 1.0, 84 | 85 | 1.0, 1.0, 1.0, 1.0, 86 | 1.0, 1.0, 1.0, 1.0, 87 | 1.0, 1.0, 1.0, 1.0, 88 | 1.0, 1.0, 1.0, 1.0 89 | ]), 90 | size: 4 91 | }, 92 | index: { 93 | value: new Uint16Array([ 94 | 0,1,2, 0,2,3, // Quad 95 | 0,5,7, 0,7,1, 1,8,10, 1,10,2, 2,11,13, 2,13,3, 3,14,4, 3,4,0, // Flaps 96 | 0,4,6, 0,6,5, 1,7,9, 1,9,8, 2,10,12, 2,12,11, 3,13,15, 3,15,14 // Connections 97 | ]), 98 | size: 1 99 | }, 100 | } 101 | 102 | const geometry = new DrawableGeometry(gl, material.locations, attributes, true) 103 | 104 | super(gl, { 105 | material, 106 | geometry 107 | }) 108 | 109 | this.gl = gl as Context 110 | 111 | // Create this.vertices from position attribute 112 | const position = this.geometry.attributes.position.value 113 | for (let index = 0; index < position.length; index += 3) { 114 | const vertex = new Vec3(position[index], position[index + 1], position[index + 2]) 115 | this.vertices.push(vertex) 116 | } 117 | } 118 | 119 | extrude(camera: Camera, pushDistance = .5){ 120 | const cameraLocalPosition = camera.position 121 | const directionToCenter = new Vec3().sub(this.position, camera.worldPosition).normalize(); 122 | const quadNormal = new Vec3(0, 0, 1); 123 | 124 | const dot = directionToCenter.dot(quadNormal) 125 | 126 | // Set colors from dot 127 | const alpha = clamp(map(Math.abs(dot), 0.001, 0.1, 0.0, 1.0), 0, 1); 128 | // Quad 129 | for (let index = 0; index < 16; index += 4) { 130 | this.geometry.attributes.color.value[index] = this.quadColor[0] // r 131 | this.geometry.attributes.color.value[index + 1] = this.quadColor[1] // g 132 | this.geometry.attributes.color.value[index + 2] = this.quadColor[2] // b 133 | this.geometry.attributes.color.value[index + 3] = this.quadColor[3] * alpha // a 134 | } 135 | 136 | // Flaps and connections 137 | for (let index = 16; index < this.geometry.attributes.color.value.length; index += 4) { 138 | this.geometry.attributes.color.value[index] = this.edgeColor[0] // r 139 | this.geometry.attributes.color.value[index + 1] = this.edgeColor[1] // g 140 | this.geometry.attributes.color.value[index + 2] = this.edgeColor[2] // b 141 | this.geometry.attributes.color.value[index + 3] = this.edgeColor[3] // a 142 | } 143 | 144 | // Get worldspace eye to original 4 vertices 145 | const eyeToVerticesWorldSpace = [ 146 | new Vec3(), 147 | new Vec3(), 148 | new Vec3(), 149 | new Vec3() 150 | ] 151 | for (let index = 0; index < 4; index++) { 152 | eyeToVerticesWorldSpace[index] = this.vertices[index].clone().sub(cameraLocalPosition).normalize() 153 | } 154 | 155 | // Extrude quad vertices 156 | const sign = Math.sign(dot) 157 | const pushDirectionsWorldSpace = [new Vec3(), new Vec3(), new Vec3()] 158 | for (let i = 0; i < 4; i++) { 159 | pushDirectionsWorldSpace[0] = eyeToVerticesWorldSpace[i].clone().cross(eyeToVerticesWorldSpace[(i + 3) % 4]).scale(sign).normalize(); 160 | 161 | pushDirectionsWorldSpace[1] = eyeToVerticesWorldSpace[(i + 1) % 4].clone().cross(eyeToVerticesWorldSpace[i]).scale(sign).normalize(); 162 | 163 | pushDirectionsWorldSpace[2] = pushDirectionsWorldSpace[0].clone().add(pushDirectionsWorldSpace[1]).normalize(); 164 | 165 | for (let j = 0; j < 3; j++) { 166 | const offset = pushDirectionsWorldSpace[j].clone().scale(pushDistance); 167 | this.vertices[4 + j + 3 * i] = this.vertices[i].clone().add(offset); 168 | } 169 | } 170 | } 171 | 172 | onBeforeDraw = ({ camera }: { camera: Camera }) => { 173 | if (!camera) return 174 | 175 | if(this.wireframe) { 176 | this.mode = this.gl.LINE_LOOP 177 | console.log(this.material.locations.uniforms); 178 | 179 | this.gl.uniform1f(this.material.locations.uniforms.uWireframeFactor, 1) 180 | } 181 | else { 182 | this.mode = this.gl.TRIANGLES 183 | this.gl.uniform1f(this.material.locations.uniforms.uWireframeFactor, 0) 184 | } 185 | 186 | this.extrude(camera) 187 | 188 | // Update World Matrix 189 | this.updateMatrix() 190 | this.updateMatrixWorld() 191 | 192 | // Set the matrix uniforms 193 | this.modelViewMatrix.multiply(camera.viewMatrix, this.worldMatrix); 194 | this.gl.uniformMatrix4fv(this.material.locations.uniforms.modelViewMatrix, false, this.modelViewMatrix) 195 | this.gl.uniformMatrix4fv(this.material.locations.uniforms.projectionMatrix, false, camera.projectionMatrix) 196 | 197 | // Set buffers from this.vertices 198 | let vertexIndex = 0 199 | for (let index = 0; index < this.geometry.attributes.position.value.length; index += 3) { 200 | const vertex = this.vertices[vertexIndex] 201 | 202 | this.geometry.attributes.position.value[index] = vertex[0] // x 203 | this.geometry.attributes.position.value[index + 1] = vertex[1] // y 204 | this.geometry.attributes.position.value[index + 2] = vertex[2] // z 205 | 206 | vertexIndex++ 207 | } 208 | this.geometry.setBuffers(this.gl.DYNAMIC_DRAW) 209 | 210 | // Transparent, so needs to disable depth testing 211 | this.gl.disable(this.gl.DEPTH_TEST) 212 | 213 | // Enable alpha blending 214 | this.gl.enable(this.gl.BLEND); 215 | // Specify how alpha must blend: fragment color * alpha + clear color * (1 - alpha) 216 | this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA) 217 | } 218 | 219 | onPostDraw = () =>{ 220 | this.gl.enable(this.gl.DEPTH_TEST) 221 | } 222 | } -------------------------------------------------------------------------------- /src/webgl/materials/GlarePlaneMaterial.ts: -------------------------------------------------------------------------------- 1 | import { DrawableMaterial } from "@/utils/libs/drawable/DrawableMaterial"; 2 | 3 | export default class GlarePlaneMaterial extends DrawableMaterial{ 4 | constructor(gl: WebGLRenderingContext){ 5 | const vertex = /* glsl */ ` 6 | attribute vec3 position; 7 | attribute vec2 uv; 8 | attribute vec3 normal; 9 | attribute vec4 color; 10 | 11 | uniform mat4 modelViewMatrix; 12 | uniform mat4 projectionMatrix; 13 | 14 | varying vec2 vUv; 15 | varying vec3 vNormal; 16 | varying vec4 vColor; 17 | 18 | void main() { 19 | vUv = uv; 20 | vNormal = normal; 21 | vColor = color; 22 | 23 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 24 | } 25 | `; 26 | 27 | const fragment = /* glsl */ ` 28 | precision mediump float; 29 | 30 | uniform float uWireframeFactor; 31 | 32 | varying vec2 vUv; 33 | varying vec3 vNormal; 34 | varying vec4 vColor; 35 | 36 | void main() { 37 | gl_FragColor = mix(vColor, vec4(vec3(1.), 1.), uWireframeFactor); 38 | 39 | // Debug : 40 | // gl_FragColor = vec4(1., 0., 0., 1.); 41 | } 42 | `; 43 | 44 | // Attributes and uniforms need to be active in the program for location fetching to work ! 45 | super(gl, { 46 | vertex, 47 | fragment, 48 | attributes: ['position', 'uv', 'normal', 'color'], 49 | uniforms: ['projectionMatrix', 'modelViewMatrix', 'uWireframeFactor'] 50 | }) 51 | } 52 | } -------------------------------------------------------------------------------- /src/webgl/scenes/GlareScene.ts: -------------------------------------------------------------------------------- 1 | import { Camera, OGLRenderingContext, Orbit, Renderer, Transform, Vec3 } from "ogl-typescript"; 2 | import { FolderApi } from "tweakpane"; 3 | import GlarePlane from "../components/GlarePlane"; 4 | 5 | export default class GlareScene { 6 | public scene: Transform 7 | public camera: Camera 8 | 9 | private gl: OGLRenderingContext 10 | private pane: FolderApi 11 | private renderer: Renderer 12 | 13 | private plane : GlarePlane 14 | private controls : any 15 | 16 | constructor({renderer, pane}: {renderer: Renderer, pane: FolderApi}) { 17 | this.gl = renderer.gl as OGLRenderingContext 18 | this.pane = pane 19 | this.renderer = renderer 20 | 21 | this.scene = new Transform() 22 | 23 | this.setCamera() 24 | this.onResize(); 25 | this.setObjects(); 26 | this.setEvents(); 27 | 28 | this.tweaks() 29 | } 30 | 31 | protected setCamera() { 32 | this.camera = new Camera(this.gl, { 33 | fov: 21, 34 | near: 0.1, 35 | far: 1000 36 | }) 37 | this.camera.position.set(0, 0, 5.3) 38 | 39 | this.controls = new Orbit(this.camera, { 40 | }); 41 | } 42 | 43 | private setObjects() { 44 | this.plane = new GlarePlane(this.gl) 45 | 46 | this.plane.scale.set(.5) 47 | 48 | this.plane.setParent(this.scene) 49 | } 50 | 51 | private onResize = () => { 52 | const canvas = this.gl.canvas as HTMLCanvasElement 53 | const rect = canvas.getBoundingClientRect() 54 | this.renderer.setSize(rect.width, rect.height); 55 | this.camera.perspective({ 56 | aspect: rect.width / rect.height, 57 | }); 58 | 59 | this.renderer.dpr = Math.min(2, window.devicePixelRatio); 60 | }; 61 | 62 | private setEvents = () => { 63 | window.addEventListener("resize", this.onResize); 64 | }; 65 | 66 | public removeEvents = () => { 67 | window.removeEventListener("resize", this.onResize); 68 | } 69 | 70 | private tweaks = () => { 71 | const folder: FolderApi = this.pane.addFolder({ 72 | title: "Glare Scene", 73 | }); 74 | 75 | folder.addInput(this.plane, "wireframe", { label: "Toggle wireframe" }); 76 | } 77 | 78 | public tick() { 79 | this.controls.update() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": false, 4 | "strictPropertyInitialization": false, 5 | "lib": [ 6 | "ESNext", 7 | "DOM.Iterable", 8 | "DOM" 9 | ], 10 | "target": "es6", 11 | "moduleResolution": "node", 12 | "esModuleInterop": true, 13 | "paths": { 14 | "@/*": [ 15 | "./src/*" 16 | ] 17 | }, 18 | "typeRoots": [ "./node_modules/@webgpu/types", "./node_modules/@types"] 19 | } 20 | } -------------------------------------------------------------------------------- /watch.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild" 2 | import { sassPlugin } from 'esbuild-sass-plugin' 3 | import { glsl } from "esbuild-plugin-glsl"; 4 | 5 | const port = 1234 6 | 7 | console.log(`running on http://localhost:${port}`) 8 | 9 | esbuild.serve({ 10 | port, 11 | servedir: "public", 12 | }, { 13 | plugins: [ 14 | sassPlugin({ type: "style" }), 15 | glsl({ minify: false }) 16 | ], 17 | entryPoints: ["src/doomGlareApp.ts", "src/scss/global.scss"], 18 | outdir: "public/built", 19 | bundle: true, 20 | }) 21 | --------------------------------------------------------------------------------