diff --git a/src/index.html b/src/index.html index 10d94f5..ed9b4a4 100644 --- a/src/index.html +++ b/src/index.html @@ -32,6 +32,7 @@ +
diff --git a/src/index.ts b/src/index.ts index 497a1f7..7abbbcf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,36 @@ import GameLoop from './game-loop/game-loop'; import './styles/index.scss'; +import { applyArrayPlugins } from './utils/array'; + +declare global { + interface Array { + x: T; + y: T; + } + + interface ReadonlyArray { + x: T; + y: T; + } + + interface Float32Array { + x: number; + y: number; + } +} + +applyArrayPlugins(); + +const errorContainer = document.querySelector('.errors'); const main = () => { - const canvas = document.querySelector('canvas'); - const game = new GameLoop(canvas); - game.start(); + try { + const canvas = document.querySelector('canvas'); + const game = new GameLoop(canvas); + game.start(); + } catch (e) { + errorContainer.innerHTML = e.message; + } }; main(); diff --git a/src/styles/index.scss b/src/styles/index.scss index cf543a5..3a6e755 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -25,3 +25,10 @@ canvas { height: 100%; width: 100%; } + +.errors { + color: red; + position: absolute; + top: 0; + left: 0; +} diff --git a/src/utils/array.ts b/src/utils/array.ts new file mode 100644 index 0000000..05b416b --- /dev/null +++ b/src/utils/array.ts @@ -0,0 +1,21 @@ +/** @internal */ +const setIndexAlias = (name: string, index: number, type: any) => { + if (!Object.prototype.hasOwnProperty.call(type.prototype, name)) { + Object.defineProperty(type.prototype, name, { + get() { + return this[index]; + }, + set(value) { + this[index] = value; + }, + }); + } +}; + +/** @internal */ +export const applyArrayPlugins = () => { + setIndexAlias('x', 0, Array); + setIndexAlias('y', 1, Array); + setIndexAlias('x', 0, Float32Array); + setIndexAlias('y', 1, Float32Array); +}; diff --git a/src/utils/colors/hex.ts b/src/utils/colors/hex.ts new file mode 100644 index 0000000..eefc66f --- /dev/null +++ b/src/utils/colors/hex.ts @@ -0,0 +1,16 @@ +import { rgb255 } from './rgb255'; + +import { vec3 } from 'gl-matrix'; + +export const hex = (hex: string): vec3 => { + if (hex[0] === '#') { + hex = hex.slice(1); + } + + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + + return rgb255(r, g, b); +}; diff --git a/src/utils/colors/hsl.ts b/src/utils/colors/hsl.ts new file mode 100644 index 0000000..06367a1 --- /dev/null +++ b/src/utils/colors/hsl.ts @@ -0,0 +1,35 @@ +import { rgb } from './rgb'; + +import { vec3 } from 'gl-matrix'; + +export const hsl = (hue: number, saturation: number, lightness: number): vec3 => { + hue /= 360; + saturation /= 100; + lightness /= 100; + let r, g, b; + + if (saturation == 0) { + r = g = b = lightness; + } else { + const hue2rgb = (p: number, q: number, t: number) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + const q = + lightness < 0.5 + ? lightness * (1 + saturation) + : lightness + saturation - lightness * saturation; + const p = 2 * lightness - q; + + r = hue2rgb(p, q, hue + 1 / 3); + g = hue2rgb(p, q, hue); + b = hue2rgb(p, q, hue - 1 / 3); + } + + return rgb(r, g, b); +}; diff --git a/src/utils/colors/rgb.ts b/src/utils/colors/rgb.ts new file mode 100644 index 0000000..a6ef20a --- /dev/null +++ b/src/utils/colors/rgb.ts @@ -0,0 +1,3 @@ +import { vec3 } from 'gl-matrix'; + +export const rgb = (r: number, g: number, b: number): vec3 => vec3.fromValues(r, g, b); diff --git a/src/utils/colors/rgb255.ts b/src/utils/colors/rgb255.ts new file mode 100644 index 0000000..56c47ff --- /dev/null +++ b/src/utils/colors/rgb255.ts @@ -0,0 +1,4 @@ +import { vec3 } from 'gl-matrix'; + +export const rgb255 = (r: number, g: number, b: number): vec3 => + vec3.fromValues(r / 255, g / 255, b / 255); diff --git a/src/utils/colors/rgba.ts b/src/utils/colors/rgba.ts new file mode 100644 index 0000000..39aae1e --- /dev/null +++ b/src/utils/colors/rgba.ts @@ -0,0 +1,4 @@ +import { vec4 } from 'gl-matrix'; + +export const rgba = (r: number, g: number, b: number, a: number): vec4 => + vec4.fromValues(r, g, b, a); diff --git a/src/utils/colors/rgba255.ts b/src/utils/colors/rgba255.ts new file mode 100644 index 0000000..00b7f5a --- /dev/null +++ b/src/utils/colors/rgba255.ts @@ -0,0 +1,4 @@ +import { vec4 } from 'gl-matrix'; + +export const rgba255 = (r: number, g: number, b: number, a: number): vec4 => + vec4.fromValues(r / 255, g / 255, b / 255, a / 255); diff --git a/src/utils/mix.ts b/src/utils/mix.ts new file mode 100644 index 0000000..16a76ed --- /dev/null +++ b/src/utils/mix.ts @@ -0,0 +1 @@ +export const mix = (from: number, to: number, q: number) => from + (to - from) * q; diff --git a/static/maximize.svg b/static/maximize.svg new file mode 100644 index 0000000..7118488 --- /dev/null +++ b/static/maximize.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/static/minimize.svg b/static/minimize.svg new file mode 100644 index 0000000..93a212a --- /dev/null +++ b/static/minimize.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/static/no-change/robots.txt b/static/no-change/robots.txt new file mode 100644 index 0000000..c2a49f4 --- /dev/null +++ b/static/no-change/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: /