diff --git a/skycraft/index.html b/skycraft/index.html
new file mode 100644
index 0000000..48cf3c1
--- /dev/null
+++ b/skycraft/index.html
@@ -0,0 +1,93 @@
+
+
+
+ WebMinecraft
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Light
+
Direction
+
+ x:
+
+
+
+ y:
+
+
+
+ z:
+
+
+
+
+
+
Ambiant light amount
+
+
+
+
Sky color
+
+ r:
+
+
+
+ g:
+
+
+
+ b:
+
+
+
+
+
+
+
Physics
+
+ Gravity:
+
+
+ Jump force:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/skycraft/index.js b/skycraft/index.js
new file mode 100644
index 0000000..2e83be0
--- /dev/null
+++ b/skycraft/index.js
@@ -0,0 +1,695 @@
+//import { initUiListeners, setupParamPanel, tick } from './game';
+//import { initWorldGl, makeWorld } from './world';
+import * as se3 from '../se3';
+import {loadTexture, makeProgram} from '../gl';
+import {makeFace, makeBufferFromFaces} from '../geometry';
+
+const VSHADER = `
+attribute vec3 aPosition;
+attribute vec3 aNormal;
+attribute vec2 aTextureCoord;
+
+uniform mat4 uProjection;
+uniform mat4 uModel;
+uniform mat4 uView;
+uniform vec3 uLightDirection;
+uniform float uAmbiantLight;
+
+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(uModel) * aNormal;
+ lowp float diffuseAmount = max(dot(-uLightDirection, normal), 0.0);
+ lowp vec3 ambiant = uAmbiantLight * vec3(1.0, 1.0, 0.9);
+ vLighting = ambiant + vec3(1.0, 1.0, 1.0) * diffuseAmount;
+
+ vTextureCoord = aTextureCoord;
+
+ vDistance = length(modelview * vec4(aPosition, 1.0));
+}
+`;
+
+const 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);
+ if (color.a < 0.1) {
+ discard;
+ }
+ lowp float fogamount = smoothstep(80.0, 100.0, vDistance);
+ gl_FragColor = mix(vec4(vLighting * color.rgb, color.a), vec4(uFogColor, 1.0), fogamount);
+}
+`;
+
+const kEpoch = 0;
+
+async function initWorldGl(gl) {
+ const program = makeProgram(gl, VSHADER, FSHADER);
+ const texture = await loadTexture(gl, 'texture.png');
+
+ // load those ahead of time
+ 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 lightDirectionLoc = gl.getUniformLocation(program, 'uLightDirection');
+ const ambiantLoc = gl.getUniformLocation(program, 'uAmbiantLight');
+
+ const positionLoc = gl.getAttribLocation(program, 'aPosition');
+ const normalLoc = gl.getAttribLocation(program, 'aNormal');
+ const textureLoc = gl.getAttribLocation(program, 'aTextureCoord');
+
+ const setupScene = (sceneParams) => {
+ const {
+ projectionMatrix,
+ viewMatrix,
+ fogColor,
+ lightDirection,
+ ambiantLightAmount,
+ } = sceneParams;
+
+ gl.useProgram(program);
+
+ gl.uniformMatrix4fv(projLoc, false, new Float32Array(projectionMatrix));
+ gl.uniformMatrix4fv(viewLoc, false, new Float32Array(viewMatrix));
+ gl.uniform3fv(fogColorLoc, fogColor);
+ gl.uniform3fv(lightDirectionLoc, lightDirection);
+ gl.uniform1f(ambiantLoc, ambiantLightAmount);
+
+ // doing this here because it's the same for all world stuff
+ gl.uniformMatrix4fv(modelLoc, false, new Float32Array(se3.identity()));
+ gl.uniform1i(samplerLoc, 0);
+
+ gl.enableVertexAttribArray(positionLoc);
+ gl.enableVertexAttribArray(normalLoc);
+ gl.enableVertexAttribArray(textureLoc);
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ };
+
+ const drawObject = (objectParams) => {
+ const {
+ position,
+ orientation,
+ glBuffer,
+ numVertices,
+ } = objectParams;
+
+ gl.uniformMatrix4fv(modelLoc, false, new Float32Array(se3.product(
+ se3.translation(...position), orientation)));
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer);
+
+ gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(normalLoc, 3, gl.BYTE, true, 20, 12);
+ gl.vertexAttribPointer(textureLoc, 2, gl.UNSIGNED_SHORT, true, 20, 16);
+
+ gl.drawArrays(gl.TRIANGLES, 0, numVertices);
+ };
+
+ return {
+ setupScene,
+ drawObject,
+ };
+}
+
+const ORBIT_VSHADER = `
+attribute vec3 aPosition;
+attribute vec2 aValue;
+
+uniform mat4 uProjection;
+uniform mat4 uModel;
+uniform mat4 uView;
+
+varying lowp vec2 vCoords;
+
+void main() {
+ highp mat4 modelview = uView * uModel;
+ gl_Position = uProjection * modelview * vec4(aPosition, 1.0);
+
+ vCoords = aValue;
+}
+`;
+
+const ORBIT_FSHADER = `
+varying lowp vec2 vCoords;
+
+void main() {
+ lowp float x = vCoords.x;
+ lowp float y = vCoords.y;
+
+ lowp float f = sqrt(x * x + y * y);
+
+ if (f > 1.00) {
+ discard;
+ } else if (f < 0.98) {
+ discard;
+ }
+ gl_FragColor = vec4(1, .5, 0, 1);
+}
+`;
+
+function getOrbitDrawContext(gl) {
+ const program = makeProgram(gl, ORBIT_VSHADER, ORBIT_FSHADER);
+
+ // load those ahead of time
+ const viewLoc = gl.getUniformLocation(program, 'uView');
+ const modelLoc = gl.getUniformLocation(program, 'uModel');
+ const projLoc = gl.getUniformLocation(program, 'uProjection');
+
+ const positionLoc = gl.getAttribLocation(program, 'aPosition');
+ const valueLoc = gl.getAttribLocation(program, 'aValue');
+
+ const setupScene = (sceneParams) => {
+ const {
+ projectionMatrix,
+ viewMatrix,
+ } = sceneParams;
+
+ gl.useProgram(program);
+
+ gl.uniformMatrix4fv(projLoc, false, new Float32Array(projectionMatrix));
+ gl.uniformMatrix4fv(viewLoc, false, new Float32Array(viewMatrix));
+
+ // doing this here because it's the same for all world stuff
+ gl.uniformMatrix4fv(modelLoc, false, new Float32Array(se3.identity()));
+
+ gl.enableVertexAttribArray(positionLoc);
+ gl.enableVertexAttribArray(valueLoc);
+ };
+
+ const drawObject = (objectParams) => {
+ const {
+ position,
+ orientation,
+ value,
+ glBuffer,
+ } = objectParams;
+
+ gl.uniformMatrix4fv(modelLoc, false, new Float32Array(se3.product(
+ se3.translation(...position), orientation)));
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer);
+
+ gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(valueLoc, 2, gl.FLOAT, false, 20, 12);
+
+ gl.disable(gl.CULL_FACE);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ gl.enable(gl.CULL_FACE);
+ };
+
+ return {
+ setupScene,
+ drawObject,
+ };
+}
+
+function initUiListeners(canvas, context) {
+ const canvasClickHandler = () => {
+ canvas.requestPointerLock();
+ canvas.onclick = null;
+// const clickListener = e => {
+// switch(e.button) {
+// case 0: // left click
+// destroySelectedBlock(context);
+// break;
+// case 2: // right click
+// makeDirBlock(context);
+// break;
+// }
+// };
+ const clickListener = e => {};
+ const keyListener = e => {
+ if (e.type === 'keydown') {
+ if (e.repeat) return;
+ context.keys.add(e.code);
+
+ switch (e.code) {
+ case 'KeyF':
+// context.flying = !context.flying;
+ return false;
+ case 'Space':
+ if (!context.flying) {
+ if (context.jumpAmount > 0) {
+ const amount = context.jumpForce;
+ context.camera.velocity[1] = amount;
+ context.jumpAmount -= 1;
+ }
+ }
+ return false;
+ }
+ } else {
+ context.keys.delete(e.code);
+ }
+ };
+ const moveListener = e => {
+ context.camera.orientation[1] -= e.movementX / 500;
+ context.camera.orientation[0] -= e.movementY / 500;
+
+ context.camera.orientation[0] = Math.min(Math.max(
+ context.camera.orientation[0], -Math.PI / 2
+ ), Math.PI / 2);
+ };
+ const changeListener = () => {
+ if (document.pointerLockElement === canvas) {
+ return;
+ }
+ document.removeEventListener('pointerdown', clickListener);
+ document.removeEventListener('pointerlockchange', changeListener);
+ document.removeEventListener('pointermove', moveListener);
+ document.removeEventListener('keydown', keyListener);
+ document.removeEventListener('keyup', keyListener);
+ canvas.onclick = canvasClickHandler;
+ };
+ document.addEventListener('pointerdown', clickListener);
+ document.addEventListener('pointerlockchange', changeListener);
+ document.addEventListener('pointermove', moveListener);
+ document.addEventListener('keydown', keyListener);
+ document.addEventListener('keyup', keyListener);
+ };
+ canvas.onclick = canvasClickHandler;
+ document.addEventListener('keydown', e => {
+ if (e.repeat) return;
+ switch (e.code) {
+ case 'F11':
+ canvas.requestFullscreen();
+ break;
+ }
+ });
+}
+
+function handleInput(context) {
+ const move = (forward, right) => {
+ const dir = [right, 0, -forward, 1.0];
+ const ori = se3.roty(context.camera.orientation[1]);
+ const tf = se3.apply(ori, dir);
+ const maxSpeed = 8;
+ const airMovement = 0.08;
+
+ if (context.flying) {
+ context.camera.position[0] += tf[0] / 60;
+ context.camera.position[2] += tf[2] / 60;
+ }
+ if (context.isOnGround) {
+ context.camera.velocity[0] = tf[0];
+ context.camera.velocity[2] = tf[2];
+ } else {
+ const vel = context.camera.velocity;
+
+ vel[0] += tf[0] * airMovement;
+ vel[2] += tf[2] * airMovement;
+
+ const curVel = Math.sqrt(vel[0] * vel[0] + vel[2] * vel[2]);
+
+ if (curVel > maxSpeed) {
+ vel[0] *= maxSpeed / curVel;
+ vel[2] *= maxSpeed / curVel;
+ }
+ }
+ };
+
+ context.keys.forEach(key => {
+ switch (key) {
+ case 'KeyW':
+ move(8, 0.0);
+ return;
+ case 'KeyA':
+ move(0.0, -8);
+ return;
+ case 'KeyS':
+ move(-8, 0.0);
+ return;
+ case 'KeyD':
+ move(0.0, 8);
+ return;
+
+ case 'Space':
+ if (context.flying) {
+ context.camera.position[1] += 8 / 60;
+ }
+ return;
+
+ case 'ShiftLeft':
+ context.camera.position[1] -= 8 / 60;
+ return;
+ }
+ });
+}
+
+function updatePhysics(time, context) {
+}
+
+function updateGeometry(context, timeout_ms = 10) {
+}
+
+function normalizeAngle(theta) {
+ const twopi = 2 * Math.PI;
+ return theta - twopi * Math.floor((theta + twopi) / twopi);
+}
+
+/** Let's be honest I should clean this up.
+ * Right now it mostly only works with elliptical orbits (e < 1),
+ * which is fine for planets & stuff, but not for my spacecraft (or comets)
+ *
+ * This is the part that solves Kepler's equation using Newton's method.
+ * For circular-ish orbits, one or two iterations are usually enough.
+ * More excentric orbits can take more (6 or 7?).
+ */
+function getCartesianPosition(orbit, mu, time) {
+ const {
+ excentricity: e,
+ semimajorAxis: a,
+ inclination: i,
+ ascendingNodeLongitude: Om,
+ periapsisArgument: w,
+ } = orbit;
+ const n = Math.sqrt(mu/(a**3)); // mean motion
+ const M = n * time; // mean anomaly
+// const nu = (
+// M
+// + (2 * e - e**3 / 4) * Math.sin(M)
+// + 5/4 * e**2 * Math.sin(2*M)
+// + 13/12 * e**3 * Math.sin(3*M)
+// ); // true anomaly, doesn't work :(
+
+ // Newton's method
+ var E2;
+ var E = M;
+ for (var j = 1; j < 20; ++j) {
+ if (e < 0.001) {
+ break;
+ }
+ if (e < 1) {
+ E2 = E - (E - e * Math.sin(E) - M) / (1 - e * Math.cos(E));
+ } else if (e > 1) {
+ E2 = E - (-E + e * sinh(E) - M) / (e * cosh(E) - 1);
+ } else {
+ E2 = E - (E + E*E*E/3 - M) / (1 + E*E);
+ }
+ if (Math.abs(E - E2) < 1e-10) {
+ break;
+ }
+ E = E2;
+ }
+ const nu = 2 * Math.atan(Math.sqrt((1+e) / (1-e)) * Math.tan(E/2));
+ const r = a * (1 - e**2) / (1 + e * Math.cos(nu));
+
+ const cOm = Math.cos(Om);
+ const sOm = Math.sin(Om);
+ const cwnu = Math.cos(w + nu);
+ const swnu = Math.sin(w + nu);
+
+ const x = r * Math.cos(i) * (cOm * cwnu - sOm * swnu);
+ const y = r * (sOm * cwnu + cOm * swnu);
+ const z = r * Math.sin(i) * cwnu;
+
+ return [x, y, z];
+}
+
+function getOrientation(body, time) {
+ return se3.rotxyz(
+ body.spin[0] * time,
+ body.spin[1] * time,
+ body.spin[2] * time,
+ );
+}
+
+function makeOrbitObject(context, orbit, parentPosition) {
+ const {gl} = context;
+ const position = parentPosition;
+ const glContext = context.orbitGlContext;
+ const orientation = [
+ se3.rotz(orbit.ascendingNodeLongitude),
+ se3.roty(-orbit.inclination),
+ se3.rotz(orbit.periapsisArgument),
+ ].reduce(se3.product);
+
+ const buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+ const a = orbit.semimajorAxis;
+ const b = a * Math.sqrt(1 - orbit.excentricity**2);
+
+ const x = - orbit.semimajorAxis * orbit.excentricity;
+
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ x-a, -b, 0, -1, -1,
+ x-a, +b, 0, -1, +1,
+ x+a, -b, 0, +1, -1,
+ x+a, +b, 0, +1, +1,
+ ]), gl.STATIC_DRAW);
+
+ const geometry = {
+ glBuffer: buffer,
+ numVertices: 4,
+ delete: () => gl.deleteBuffer(buffer),
+ };
+
+ return {
+ geometry,
+ orientation,
+ position,
+ glContext,
+ };
+}
+
+function getObjects(context, body, time, parentBody, parentPosition) {
+ const kGravitationalConstant = 6.674e-11;
+ const objects = [];
+ const {gl, glContext} = context;
+ let position = [0, 0, 0];
+ if (parentBody !== undefined) {
+// const mu = kGravitationalConstant * parentBody.mass;
+ const mu = 10;
+ const coord = getCartesianPosition(body.orbit, mu, time);
+ position = [
+ parentPosition[0] + coord[0],
+ parentPosition[1] + coord[1],
+ parentPosition[2] + coord[2],
+ ];
+
+ objects.push(makeOrbitObject(context, body.orbit, parentPosition));
+ }
+
+ objects.push({
+ geometry: makeBufferFromFaces(gl, body.geometry),
+ orientation: getOrientation(body, time),
+ position,
+ glContext,
+ });
+
+ if (body.children !== undefined) {
+ for (const child of body.children) {
+ objects.push(...getObjects(context, child, time, body, position));
+ }
+ }
+
+ return objects;
+}
+
+function draw(context, time) {
+ const {gl, camera, universe} = context;
+ const objects = getObjects(context, universe, time * 0.001);
+
+ gl.clearColor(...context.skyColor, 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.enable(gl.BLEND);
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ const camrot = camera.orientation;
+ const campos = camera.position;
+ const viewMatrix = se3.product(
+ se3.rotxyz(-camrot[0], -camrot[1], -camrot[2]),
+ se3.translation(-campos[0], -campos[1], -campos[2])
+ );
+
+ let lastGlContext;
+
+ for (const {position, orientation, geometry, glContext} of objects) {
+ if (glContext !== lastGlContext) {
+ glContext.setupScene({
+ projectionMatrix: context.projMatrix,
+ viewMatrix,
+ fogColor: context.skyColor,
+ lightDirection: context.lightDirection,
+ ambiantLightAmount: context.ambiantLight,
+ });
+ }
+
+ lastGlContext = glContext;
+
+ glContext.drawObject({
+ position,
+ orientation,
+ glBuffer: geometry.glBuffer,
+ numVertices: geometry.numVertices,
+ });
+ }
+}
+
+function tick(time, context) {
+ handleInput(context);
+ updatePhysics(time, context);
+
+ const campos = context.camera.position;
+
+ // world generation / geometry update
+ {
+ // frame time is typically 16.7ms, so this may lag a bit
+ let timeLeft = 10;
+ const start = performance.now();
+ updateGeometry(context, timeLeft);
+ }
+
+ draw(context, time);
+
+ const dt = (time - context.lastFrameTime) * 0.001;
+ context.lastFrameTime = time;
+
+ document.querySelector('#fps').textContent = `${1.0 / dt} fps`;
+
+ requestAnimationFrame(time => tick(time, context));
+}
+
+function makeCube(texture) {
+ return [
+ makeFace('-x', texture, [-0.5, 0, 0]),
+ makeFace('+x', texture, [+0.5, 0, 0]),
+ makeFace('-y', texture, [0, -0.5, 0]),
+ makeFace('+y', texture, [0, +0.5, 0]),
+ makeFace('-z', texture, [0, 0, -0.5]),
+ makeFace('+z', texture, [0, 0, +0.5]),
+ ];
+}
+
+function makeObjects(gl) {
+ const texture = [0, 4];
+ const faces = [
+ makeFace('-x', texture, [-0.5, 0, 0]),
+ makeFace('+x', texture, [+0.5, 0, 0]),
+ makeFace('-y', texture, [0, -0.5, 0]),
+ makeFace('+y', texture, [0, +0.5, 0]),
+ makeFace('-z', texture, [0, 0, -0.5]),
+ makeFace('+z', texture, [0, 0, +0.5]),
+ ];
+ return [
+ {
+ geometry: makeBufferFromFaces(gl, faces),
+ orientation: [0, 0, 0],
+ position: [0, 0, 0],
+ },
+ ];
+}
+
+function makeSolarSystem(gl) {
+ return {
+ mass: 1.0,
+ spin: [0, 1.0, 0],
+ geometry: makeCube([0, 4]),
+ children: [
+ {
+ mass: 0.1,
+ spin: [0.2, 0.0, 0.0],
+ geometry: makeCube([0, 8]),
+ orbit: {
+ excentricity: 0,
+ semimajorAxis: 3,
+ inclination: 0,
+ ascendingNodeLongitude: 0,
+ periapsisArgument: 0,
+ trueAnomaly: 0,
+ },
+ },
+ {
+ mass: 0.1,
+ spin: [0.2, 0.0, 0.0],
+ geometry: makeCube([0, 1]),
+ orbit: {
+ excentricity: 0.8,
+ semimajorAxis: 5,
+ inclination: 0,
+ ascendingNodeLongitude: 0,
+ periapsisArgument: 0,
+ trueAnomaly: 0,
+ },
+ },
+ {
+ mass: 0.1,
+ spin: [0.0, 0.0, 1.0],
+ geometry: makeCube([9, 9]),
+ orbit: {
+ excentricity: 0.3,
+ semimajorAxis: 5,
+ inclination: 1.0,
+ ascendingNodeLongitude: 0,
+ periapsisArgument: 0,
+ trueAnomaly: 0,
+ },
+ },
+ ],
+ }
+}
+
+async function main() {
+ const canvas = document.querySelector('#game');
+ // adjust canvas aspect ratio to that of the screen
+ canvas.height = screen.height / screen.width * canvas.width;
+ const gl = canvas.getContext('webgl');
+
+ if (gl === null) {
+ console.error('webgl not available')
+ return;
+ }
+
+ const context = {
+ gl,
+ projMatrix: se3.perspective(Math.PI / 3, canvas.clientWidth / canvas.clientHeight, 0.1, 100.0),
+ camera: {
+ position: [0.0, 0.0, 2.0],
+ orientation: [0.0, 0.0, 0.0],
+ velocity: [0, 0, 0],
+ },
+ keys: new Set(),
+ lightDirection: [-0.2, -0.5, 0.4],
+ skyColor: [0.10, 0.15, 0.2],
+ ambiantLight: 0.7,
+ blockSelectDistance: 8,
+ flying: true,
+ isOnGround: false,
+ gravity: -17,
+ jumpForce: 6.5,
+// objects: makeObjects(gl),
+ universe: makeSolarSystem(gl),
+ };
+
+ context.glContext = await initWorldGl(gl);
+ context.orbitGlContext = getOrbitDrawContext(gl);
+ initUiListeners(canvas, context);
+
+// setupParamPanel(context);
+
+ requestAnimationFrame(time => tick(time, context));
+}
+
+window.onload = main;
diff --git a/skycraft/package.json b/skycraft/package.json
new file mode 100644
index 0000000..7325199
--- /dev/null
+++ b/skycraft/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "skycraft",
+ "version": "1.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.14.2"
+ },
+ "scripts": {
+ "watch": "esbuild --outfile=app.js index.js --bundle --sourcemap=inline --watch",
+ "serve": "esbuild --outfile=app.js index.js --bundle --sourcemap=inline --servedir=.",
+ "build": "esbuild --outfile=app.js index.js --bundle --minify"
+ }
+}
diff --git a/skycraft/texture.png b/skycraft/texture.png
new file mode 120000
index 0000000..71e5e58
--- /dev/null
+++ b/skycraft/texture.png
@@ -0,0 +1 @@
+../texture.png
\ No newline at end of file
diff --git a/skycraft/yarn.lock b/skycraft/yarn.lock
new file mode 100644
index 0000000..646c141
--- /dev/null
+++ b/skycraft/yarn.lock
@@ -0,0 +1,135 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@esbuild/linux-loong64@0.14.54":
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
+ integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
+
+esbuild-android-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
+ integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
+
+esbuild-android-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
+ integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
+
+esbuild-darwin-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
+ integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
+
+esbuild-darwin-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
+ integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
+
+esbuild-freebsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
+ integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
+
+esbuild-freebsd-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
+ integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
+
+esbuild-linux-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
+ integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
+
+esbuild-linux-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
+ integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
+
+esbuild-linux-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
+ integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
+
+esbuild-linux-arm@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
+ integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
+
+esbuild-linux-mips64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
+ integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
+
+esbuild-linux-ppc64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
+ integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
+
+esbuild-linux-riscv64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
+ integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
+
+esbuild-linux-s390x@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
+ integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
+
+esbuild-netbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
+ integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
+
+esbuild-openbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
+ integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
+
+esbuild-sunos-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
+ integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
+
+esbuild-windows-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
+ integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
+
+esbuild-windows-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
+ integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
+
+esbuild-windows-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
+ integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
+
+esbuild@^0.14.2:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
+ integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
+ optionalDependencies:
+ "@esbuild/linux-loong64" "0.14.54"
+ esbuild-android-64 "0.14.54"
+ esbuild-android-arm64 "0.14.54"
+ esbuild-darwin-64 "0.14.54"
+ esbuild-darwin-arm64 "0.14.54"
+ esbuild-freebsd-64 "0.14.54"
+ esbuild-freebsd-arm64 "0.14.54"
+ esbuild-linux-32 "0.14.54"
+ esbuild-linux-64 "0.14.54"
+ esbuild-linux-arm "0.14.54"
+ esbuild-linux-arm64 "0.14.54"
+ esbuild-linux-mips64le "0.14.54"
+ esbuild-linux-ppc64le "0.14.54"
+ esbuild-linux-riscv64 "0.14.54"
+ esbuild-linux-s390x "0.14.54"
+ esbuild-netbsd-64 "0.14.54"
+ esbuild-openbsd-64 "0.14.54"
+ esbuild-sunos-64 "0.14.54"
+ esbuild-windows-32 "0.14.54"
+ esbuild-windows-64 "0.14.54"
+ esbuild-windows-arm64 "0.14.54"