commit 49e814d1bc0143ebfb0fefd47571e63683db204f Author: Paul Mathieu Date: Wed Dec 8 09:24:19 2021 -0800 A few things - webgl boilerplate - shader ambiant + diffuse lighting - fractal perlin noise chunk generation - super primitive world generation (stone, dirt, grass blocks) - WASD controls + mouse pointer capture On the menu: - collisions - gravity - mine & place - more stuff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/geometry.js b/geometry.js new file mode 100644 index 0000000..ac1d8de --- /dev/null +++ b/geometry.js @@ -0,0 +1,127 @@ +import * as se3 from './se3'; + +/** Makes a square with constant z = 0. + * + * Face is oriented towards z+. + */ +function makeSquare() { + const vertices = [ + // triangle 0 + 0.5, 0.5 , 0.0, + -0.5, 0.5, 0.0, + -0.5, -0.5, 0.0, + + // triangle 1 + 0.5, 0.5, 0.0, + -0.5, -0.5, 0.0, + 0.5, -0.5, 0.0, + ]; + + // normals toward z+ + const normals = [].concat(...Array(6).fill([0.0, 0.0, 1.0])); + + const textures = [ + 0.99, 0.99, + 0.01, 0.99, + 0.01, 0.01, + + 0.99, 0.99, + 0.01, 0.01, + 0.99, 0.01, + ]; + + return { + vertices, + normals, + textures, + }; +} + +function makeZFace(normal, texture, transform) { + const textMul = 0.0625; + const textOff = texture.map(x => x * textMul); + + const vertices = []; + const textures = []; + + const sq = makeSquare(); + + for (let i = 0; i < 6; i++) { + vertices.push( + se3.product( + transform, + sq.vertices.slice(3 * i, 3 * (i + 1)).concat([1.0]) + ).slice(0, 3)); + textures.push(sq.textures.slice(2 * i, 2 * (i + 1)).map((v, j) => textMul * v + textOff[j])); + } + + const normals = [].concat(...Array(6).fill(normal)); + + return { + vertices: [].concat(...vertices), + normals, + textures: [].concat(...textures), + }; + +} + +export function makeFace(which, texture, centerPos) { + const rot = { + '-x': se3.roty(-Math.PI / 2), + '+x': se3.roty(Math.PI / 2), + '-y': se3.rotx(Math.PI / 2), + '+y': se3.rotx(-Math.PI / 2), + '-z': se3.roty(Math.PI), + '+z': se3.identity(), + }[which]; + + const normal = { + '+x': [1.0, 0.0, 0.0], + '-x': [-1.0, 0.0, 0.0], + '+y': [0.0, 1.0, 0.0], + '-y': [0.0, -1.0, 0.0], + '+z': [0.0, 0.0, 1.0], + '-z': [0.0, 0.0, -1.0], + }[which]; + + const tf = se3.product(se3.translation(...centerPos), rot); + return makeZFace(normal, texture, tf); +} + +export function makeBuffersFromFraces(gl, faces) { + vertices = [].concat(...faces.map(f => f.vertices)); + normals = [].concat(...faces.map(f => f.normals)); + textures = [].concat(...faces.map(f => f.textures)); + + const vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); + + const normalBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW); + + const textureBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textures), gl.STATIC_DRAW); + + return { + vertexBuffer, + normalBuffer, + textureBuffer, + numVertices: vertices.length / 3, + }; +} + +export function makeGrassCube(gl) { + faces = [ + makeFace('+y', [0, 15], [0.0, 0.5, 0.0]), + makeFace('-y', [2, 15], [0.0, -0.5, 0.0]), + makeFace('-x', [1, 15], [-0.5, 0.0, 0.0]), + makeFace('+x', [1, 15], [0.5, 0.0, 0.0]), + makeFace('-z', [1, 15], [0.0, 0.0, -0.5]), + makeFace('+z', [1, 15], [0.0, 0.0, 0.5]), + ]; + + return makeBuffersFromFraces(gl, faces); +} \ No newline at end of file diff --git a/gl.js b/gl.js new file mode 100644 index 0000000..e09dcba --- /dev/null +++ b/gl.js @@ -0,0 +1,49 @@ +function makeShader(gl, type, source) { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + throw Error(`Shader compiler error: ${gl.getShaderInfoLog(shader)}`); + } + + return shader; +} + +export function makeProgram(gl, vertexShader, fragmentShader) { + const vshader = makeShader(gl, gl.VERTEX_SHADER, vertexShader); + const fshader = makeShader(gl, gl.FRAGMENT_SHADER, fragmentShader); + + const shaderProg = gl.createProgram(); + gl.attachShader(shaderProg, vshader); + gl.attachShader(shaderProg, fshader); + gl.linkProgram(shaderProg); + + if (!gl.getProgramParameter(shaderProg, gl.LINK_STATUS)) { + throw Error(`Shader linker error: ${gl.getProgramInfoLog(shaderProg)}`); + } + + return shaderProg; +} + +function getImage(url) { + return new Promise(resolve => { + const image = new Image(); + image.onload = () => resolve(image); + image.src = url; + }); +} + +export async function loadTexture(gl, url) { + const image = await getImage(url); + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); +// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); +// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.generateMipmap(gl.TEXTURE_2D); + + return texture; +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..a104c76 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + WebMinecraft + + + + + +
+ + + \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..cad921b --- /dev/null +++ b/index.js @@ -0,0 +1,420 @@ +import { makeBuffersFromFraces, makeFace, makeGrassCube } from "./geometry"; +import { loadTexture, makeProgram } from "./gl"; +import * as se3 from './se3'; + +const TEST_VSHADER = ` +attribute vec3 aPosition; +attribute vec3 aNormal; +attribute vec2 aTextureCoord; + +uniform mat4 uProjection; +uniform mat4 uModel; +uniform mat4 uView; + +varying highp vec2 vTextureCoord; +varying lowp vec3 vLighting; +varying lowp float vDistance; + +void main() { + highp mat4 modelview = uView * uModel; + + gl_Position = uProjection * modelview * vec4(aPosition, 1.0); + + lowp vec3 normal = mat3(modelview) * aNormal; + lowp vec3 lightDirection = - normalize(mat3(uView) * vec3(1.0, -0.3, -0.8)); + lowp float diffuseAmount = max(dot(lightDirection, normal), 0.0); + lowp vec3 ambiant = vec3(0.7, 0.7, 0.2); + vLighting = ambiant + vec3(1.0, 1.0, 1.0) * diffuseAmount; + + vTextureCoord = aTextureCoord; + + vDistance = length(modelview * vec4(aPosition, 1.0)); +} +`; + +const TEST_FSHADER = ` +uniform sampler2D uSampler; +uniform lowp vec3 uFogColor; + +varying highp vec2 vTextureCoord; +varying lowp vec3 vLighting; +varying lowp float vDistance; + +void main() { + highp vec4 color = texture2D(uSampler, vTextureCoord); + lowp float fogamount = smoothstep(30.0, 90.0, vDistance); + gl_FragColor = vec4(mix(vLighting * color.rgb, uFogColor, fogamount), color.a); +} +`; + +/** Draw. + * + * @param {WebGLRenderingContext} gl + */ +function draw(gl, params, objects) { + gl.clearColor(0.6, 0.8, 1.0, 1.0); + gl.clearDepth(1.0); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + + gl.enable(gl.CULL_FACE); + gl.cullFace(gl.BACK); + + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + const camrot = params.camera.orientation; + const campos = params.camera.position; + const viewMat = se3.product( + se3.rotxyz(-camrot[0], -camrot[1], -camrot[2]), + se3.translation(-campos[0], -campos[1], -campos[2]) + ); + + for (const {program, texture, position, orientation, geometry} of objects) { + const viewLoc = gl.getUniformLocation(program, 'uView'); + const modelLoc = gl.getUniformLocation(program, 'uModel'); + const projLoc = gl.getUniformLocation(program, 'uProjection'); + const samplerLoc = gl.getUniformLocation(program, 'uSampler'); + const fogColorLoc = gl.getUniformLocation(program, 'uFogColor'); + + const positionLoc = gl.getAttribLocation(program, 'aPosition'); + const normalLoc = gl.getAttribLocation(program, 'aNormal'); + const textureLoc = gl.getAttribLocation(program, 'aTextureCoord'); + + const mvMatrix = se3.product(se3.translation(...position), se3.rotxyz(...orientation)); + + gl.useProgram(program); + + gl.uniformMatrix4fv(viewLoc, false, new Float32Array(viewMat)); + gl.uniformMatrix4fv(modelLoc, false, new Float32Array(mvMatrix)); + gl.uniformMatrix4fv(projLoc, false, new Float32Array(params.projMatrix)); + gl.uniform3f(fogColorLoc, 0.6, 0.8, 1.0); + + gl.bindBuffer(gl.ARRAY_BUFFER, geometry.vertexBuffer); + gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(positionLoc); + + gl.bindBuffer(gl.ARRAY_BUFFER, geometry.normalBuffer); + gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(normalLoc); + + gl.bindBuffer(gl.ARRAY_BUFFER, geometry.textureBuffer); + gl.vertexAttribPointer(textureLoc, 2, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(textureLoc); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.uniform1i(samplerLoc, 0); + + gl.drawArrays(gl.TRIANGLES, 0, geometry.numVertices); + } +} + +const stuff = { + lastFrameTime: 0, +}; + +function handleKeys(params) { + const move = (forward, right) => { + const dir = [right, 0, -forward, 1.0]; + const camori = params.camera.orientation; + const ori = se3.rotxyz(...camori); + const tf = se3.apply(ori, dir); + + params.camera.position[0] += tf[0]; + params.camera.position[2] += tf[2]; + }; + + params.keys.forEach(key => { + switch (key) { + case 'KeyW': + move(0.1, 0.0); + return; + case 'KeyA': + move(0.0, -0.1); + return; + case 'KeyS': + move(-0.1, 0.0); + return; + case 'KeyD': + move(0.0, 0.1); + return; + + case 'Space': + params.camera.position[1] += 0.1; + return; + case 'ControlLeft': + params.camera.position[1] -= 0.1; + return; + } + }); +} + +function tick(time, gl, params, objects) { + draw(gl, params, objects); + + handleKeys(params); + + const dt = (time - stuff.lastFrameTime) * 0.001; + stuff.lastFrameTime = time; + + document.querySelector('#fps').textContent = `${1.0 / dt} fps`; + + requestAnimationFrame(time => tick(time, gl, params, objects)); +} + +const BlockType = { + AIR: 1, + DIRT: 2, + GRASS: 3, + STONE: 4, +}; + +function ghettoPerlinNoise(seed, x, y, gridSize = 16) { + const dot = (vx, vy) => vx[0] * vy[0] + vx[1] * vy[1]; + // super ghetto random + const xorshift = (x) => { + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + return x; + }; + + const randGrad = (x0, y0) => { + const rand = xorshift(1337 * x0 + seed + 80085 * y0); + return [Math.sin(rand), Math.cos(rand)]; + }; + + const interpol = (a, b, x) => a + (x*x*(3 - 2*x)) * (b - a); + + const x0 = Math.floor(x / gridSize); + const y0 = Math.floor(y / gridSize); + const sx = x / gridSize - x0; + const sy = y / gridSize - y0; + + const n0 = dot(randGrad(x0, y0), [sx, sy]); + const n1 = dot(randGrad(x0 + 1, y0), [sx - 1, sy]); + const n2 = dot(randGrad(x0, y0 + 1), [sx, sy - 1]); + const n3 = dot(randGrad(x0 + 1, y0 + 1), [sx - 1, sy - 1]); + + return interpol(interpol(n0, n1, sx), interpol(n2, n3, sx), sy); +} + +function makeTerrain(x, y) { + const seed = 1337; + + const fractalNoise = (x, y) => ( + ghettoPerlinNoise(seed, x, y, 8) * 0.06 + + ghettoPerlinNoise(seed, x, y, 16) * 0.125 + + ghettoPerlinNoise(seed, x, y, 32) * 0.25 + + ghettoPerlinNoise(seed, x, y, 64) * 0.5 + ); + + const terrain = Array(16); + + for (let i = 0; i < 16; i++) { + for (let j = 0; j < 16; j++) { + terrain[i * 16 + j] = fractalNoise(x + i, y + j); + } + } + + return terrain; +} + +function makeChunk(x, y) { + const terrain = makeTerrain(x, y); + + const chunk = new Uint8Array(16 * 16 * 256); + + for (let i = 0; i < 16; i++) { + for (let j = 0; j < 16; j++) { + const height = Math.floor(64 + 64 * terrain[i * 16 + j]); + // everything above is air + // that block is grass + // everything below is dirt + const offset = i * (16 * 256) + j * 256; + const stoneHeight = Math.min(62, height); + chunk.set(Array(stoneHeight).fill(BlockType.STONE), offset); + if (stoneHeight < height) { + chunk.set(Array(height - 1 - stoneHeight).fill(BlockType.DIRT), offset + stoneHeight); + chunk[offset + height - 1] = BlockType.GRASS; + } + chunk.set(Array(256 - height).fill(BlockType.AIR), offset + height); + } + } + + return chunk; +} + +function makeChunkMesh(chunk, z0, x0) { + const blockPos = i => { + const x = Math.floor(i / (16 * 256)); + const y = Math.floor((i - 16 * 258 * x) / 256); + const z = i - 256 * (16*x + y); + + return [x, y, z]; + }; + + const blockIndex = (i, j, k) => 256 * (i*16 +j) + k; + + const sideNeighbors = (i, j) => { + return [ + {pos: [i - 1, j], dir: '-z'}, + {pos: [i + 1, j], dir: '+z'}, + {pos: [i, j - 1], dir: '-x'}, + {pos: [i, j + 1], dir: '+x'}, + ].filter(v => v.pos.every(i => i >= 0 && i < 16)); + }; + + const faceDir = (dir, x, y, z) => { + return { + '-x': [x - 0.5, y, z], + '+x': [x + 0.5, y, z], + '-z': [x, y, z - 0.5], + '+z': [x, y, z + 0.5], + }[dir]; + }; + + const faces = []; + + for (let i = 0; i < 16; i++) { + for (let j = 0; j < 16; j++) { + for (let k = 0; k < 256; k++) { + const bi = blockIndex(i, j, k); + + const upTexture = (() => { + switch (chunk[bi - 1]) { + case BlockType.GRASS: return [0, 15]; + case BlockType.DIRT: return [2, 15]; + case BlockType.STONE: return [3, 15]; + } + })(); + + if (chunk[bi] == BlockType.AIR) { + faces.push(makeFace('+y', upTexture, [x0 + j, k - 0.5, z0 + i])); + break; + } + + const sideTexture = (() => { + switch (chunk[bi]) { + case BlockType.GRASS: return [1, 15]; + case BlockType.DIRT: return [2, 15]; + case BlockType.STONE: return [3, 15]; + } + })(); + + for ({ pos, dir } of sideNeighbors(i, j)) { + if (chunk[blockIndex(...pos, k)] == BlockType.AIR) { + faces.push(makeFace(dir, sideTexture, faceDir(dir, x0 + j, k, z0 + i))); + } + } + if (i == 0) { + faces.push(makeFace('-z', sideTexture, faceDir('-z', x0 + j, k, z0 + i))); + } + if (i == 15) { + faces.push(makeFace('+z', sideTexture, faceDir('+z', x0 + j, k, z0 + i))); + } + if (j == 0) { + faces.push(makeFace('-x', sideTexture, faceDir('-x', x0 + j, k, z0 + i))); + } + if (j == 15) { + faces.push(makeFace('+x', sideTexture, faceDir('+x', x0 + j, k, z0 + i))); + } + } + } + } + + return faces; +} + +function makeWorldBuffers(gl) { + const chunkFaces = [].concat( + makeChunkMesh(makeChunk(0, -16), 0, -16), + makeChunkMesh(makeChunk(16, -16), 16, -16), + makeChunkMesh(makeChunk(0, 0), 0, 0), + makeChunkMesh(makeChunk(16, 0), 16, 0), + makeChunkMesh(makeChunk(16, 16), 16, 16), + makeChunkMesh(makeChunk(0, 16), 0, 16), + ); + + + return makeBuffersFromFraces(gl, chunkFaces); +} + +// Stuff I need to do: +// [x] a skybox +// [x] a movable camera +// [ ] some kind of gravity +// [ ] collision detection +// [x] more blocks +// [ ] ability to mine & place +// [ ] generating & loading of more chunks +// [x] distance fog +// [ ] different biomes (with different noise stats) +// [ ] non-flowy water +// [ ] flowy water +// [ ] ALIGN CHUNK WITH WORLD COORDS +// [x] better controls + +async function main() { + const canvas = document.querySelector('#game'); + const gl = canvas.getContext('webgl'); + + if (gl === null) { + console.error('webgl not available') + return; + } + + const program = makeProgram(gl, TEST_VSHADER, TEST_FSHADER); + + const params = { + projMatrix: se3.perspective(Math.PI / 3, canvas.clientWidth / canvas.clientHeight, 0.1, 100.0), + camera: { + position: [0.0, 70.5, 0.0], + orientation: [0.0, Math.PI, 0.0], + }, + keys: new Set() + } + + const texture = await loadTexture(gl, 'texture.png'); + + const objects = [ + { + program, + position: [0.0, 0.0, 0.0], + orientation: [0.0, 0.0, 0.0], + geometry: makeWorldBuffers(gl), + texture, + }, + ]; + + canvas.onclick = e => { + canvas.requestPointerLock(); + const keyListener = e => { + if (e.type === 'keydown') { + params.keys.add(e.code); + } else { + params.keys.delete(e.code); + } + }; + const moveListener = e => { + params.camera.orientation[1] -= e.movementX / 500; + params.camera.orientation[0] -= e.movementY / 500; + }; + const changeListener = () => { + if (document.pointerLockElement === canvas) { + return; + } + document.removeEventListener('pointerlockchange', changeListener); + document.removeEventListener('pointermove', moveListener); + document.removeEventListener('keydown', keyListener); + document.removeEventListener('keyup', keyListener); + }; + document.addEventListener('pointerlockchange', changeListener); + document.addEventListener('pointermove', moveListener); + document.addEventListener('keydown', keyListener); + document.addEventListener('keyup', keyListener); + }; + requestAnimationFrame(time => tick(time, gl, params, objects)); +} + +window.onload = main; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..694e5d6 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "wmc", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "esbuild": "^0.14.2" + }, + "scripts": { + "serve": "esbuild --outfile=app.js index.js --bundle --servedir=." + } +} diff --git a/se3.js b/se3.js new file mode 100644 index 0000000..3b88fae --- /dev/null +++ b/se3.js @@ -0,0 +1,102 @@ +// all column-major, *sigh* +export function identity() { + return [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ]; +} + +export function rotx(rad) { + const s = Math.sin(rad); + const c = Math.cos(rad); + + return [ + 1.0, 0.0, 0.0, 0.0, + 0.0, c, s, 0.0, + 0.0, -s, c, 0.0, + 0.0, 0.0, 0.0, 1.0, + ]; +} + +export function roty(rad) { + const s = Math.sin(rad); + const c = Math.cos(rad); + + return [ + c, 0.0, -s, 0.0, + 0.0, 1.0, 0.0, 0.0, + s, 0.0, c, 0.0, + 0.0, 0.0, 0.0, 1.0, + ]; +} + +export function rotz(rad) { + const s = Math.sin(rad); + const c = Math.cos(rad); + + return [ + c, s, 0.0, 0.0, + -s, c, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + ]; +} + +export function apply(mat, vect) { + const indices = [0, 1, 2, 3]; + const sum = v => v.reduce((a, b) => a + b); + return [ + sum(indices.map(i => mat[4*i + 0] * vect[i])), + sum(indices.map(i => mat[4*i + 1] * vect[i])), + sum(indices.map(i => mat[4*i + 2] * vect[i])), + sum(indices.map(i => mat[4*i + 3] * vect[i])), + ]; +} + +export function rotxyz(x, y, z) { + return [rotx(x), roty(y), rotz(z)].reduce(product); +} + +export function translation(x, y, z) { + return [ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + x, y, z, 1.0, + ]; +} + +export function product(a, b) { + const c = (i, j) => ( + a[4 * 0 + i] * b[4 * j + 0] + + a[4 * 1 + i] * b[4 * j + 1] + + a[4 * 2 + i] * b[4 * j + 2] + + a[4 * 3 + i] * b[4 * j + 3] + ); + return [ + c(0, 0), c(1, 0), c(2, 0), c(3, 0), + c(0, 1), c(1, 1), c(2, 1), c(3, 1), + c(0, 2), c(1, 2), c(2, 2), c(3, 2), + c(0, 3), c(1, 3), c(2, 3), c(3, 3), + ]; +} + +export function ortho(aspectRatio) { + const out = identity(); + out[0] = 1 / aspectRatio; + return out; +} + +export function perspective(fov, aspectRatio, near, far) { + const f = 1 / Math.tan(fov / 2); + const rangeInv = 1 / (near - far); + + return [ + f / aspectRatio, 0.0, 0.0, 0.0, + 0.0, f, 0.0, 0.0, + 0.0, 0.0, (near + far) * rangeInv, -1, + 0.0, 0.0, near * far * rangeInv * 2, 0, + ]; +}; \ No newline at end of file diff --git a/texture.png b/texture.png new file mode 100644 index 0000000..aab2d7b Binary files /dev/null and b/texture.png differ diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..f6c43f3 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,111 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +esbuild-android-arm64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz#256b7cf2f9d382a2a92a4ff4e13187587c9b7c6a" + integrity sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw== + +esbuild-darwin-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz#891a59ce6bc3aded0265f982469b3eb9571b92f8" + integrity sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA== + +esbuild-darwin-arm64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz#ab834fffa9c612b2901ca1e77e4695d4d8aa63a2" + integrity sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A== + +esbuild-freebsd-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz#f7fc87a83f02de27d5a48472571efa1a432ae86d" + integrity sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ== + +esbuild-freebsd-arm64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz#bc8758420431106751f3180293cac0b5bc4ce2ee" + integrity sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ== + +esbuild-linux-32@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz#0cc2dcd816d6d66e255bc7aeac139b1d04246812" + integrity sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ== + +esbuild-linux-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz#c790f739aa75b15c153609ea3457153fbe4db93d" + integrity sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg== + +esbuild-linux-arm64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz#96858a1f89ad30274dec780d0e3dd8b5691c6b0c" + integrity sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww== + +esbuild-linux-arm@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz#03e193225afa9b1215d2ec6efe8edf0c03eeed6f" + integrity sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ== + +esbuild-linux-mips64le@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz#972f218d2cb5125237376d40ad60a6e5356a782c" + integrity sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ== + +esbuild-linux-ppc64le@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz#20b71622ac09142b0e523f633af0829def7fed6b" + integrity sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA== + +esbuild-netbsd-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz#dbd6a25117902ef67aa11d8779dd9c6bca7fbe82" + integrity sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw== + +esbuild-openbsd-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz#3c5f199eed459b2f88865548394c0b77383d9ca4" + integrity sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q== + +esbuild-sunos-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz#900a681db6b76c6a7f60fc28d2bfe5b11698641c" + integrity sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow== + +esbuild-windows-32@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz#61e0ba5bd95b277a55d2b997ac4c04dfe2559220" + integrity sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ== + +esbuild-windows-64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz#6ab59ef721ff75c682a1c8ae0570dabb637abddb" + integrity sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg== + +esbuild-windows-arm64@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz#aca2a4f83d2f0d1592ad4be832ed0045fc888cda" + integrity sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA== + +esbuild@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.2.tgz#9c1e1a652549cc33e44885eea42ea2cc6267edc2" + integrity sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg== + optionalDependencies: + esbuild-android-arm64 "0.14.2" + esbuild-darwin-64 "0.14.2" + esbuild-darwin-arm64 "0.14.2" + esbuild-freebsd-64 "0.14.2" + esbuild-freebsd-arm64 "0.14.2" + esbuild-linux-32 "0.14.2" + esbuild-linux-64 "0.14.2" + esbuild-linux-arm "0.14.2" + esbuild-linux-arm64 "0.14.2" + esbuild-linux-mips64le "0.14.2" + esbuild-linux-ppc64le "0.14.2" + esbuild-netbsd-64 "0.14.2" + esbuild-openbsd-64 "0.14.2" + esbuild-sunos-64 "0.14.2" + esbuild-windows-32 "0.14.2" + esbuild-windows-64 "0.14.2" + esbuild-windows-arm64 "0.14.2"