From d9623a3274603a8514f114000cb59ce7eed8cc08 Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Sun, 20 Sep 2020 11:25:33 +0200 Subject: [PATCH] Dockerize --- .dockerignore | 5 ++ Dockerfile | 28 ++++++ nginx-config/nginx.conf | 53 +++++++++++ package.json | 18 ++-- src/helper/remove-unnecessary-outlines.ts | 4 + src/index.html | 44 ++++++--- src/index.scss | 103 ---------------------- src/index.ts | 37 +++++--- src/scenes/blob-scene.ts | 76 ++++++++++++++++ webpack.config.js | 12 ++- 10 files changed, 243 insertions(+), 137 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 nginx-config/nginx.conf create mode 100644 src/helper/remove-unnecessary-outlines.ts delete mode 100644 src/index.scss create mode 100644 src/scenes/blob-scene.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2044e20 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +Dockerfile +node_modules +dist +package-lock.json +.* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d7c92e0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM schmelczera/error-pages as build-error-pages +RUN python build.py 403 404 50x + + +FROM node:latest as build-webpage +WORKDIR /home/node + +COPY src src +COPY static static +COPY package.json custom.d.ts tsconfig.json webpack.config.js ./ + +RUN npm install +RUN npm run build + + +FROM nginx:alpine + +HEALTHCHECK --interval=1m --timeout=10s CMD curl --fail http://localhost/ || exit 1 + +WORKDIR /usr/share/nginx/html + +RUN rm -rf * +COPY --from=build-webpage /home/node/dist . +COPY --from=build-error-pages /home/python/built errors +RUN find . -type f | xargs gzip -k9 &&\ + chmod -R 555 . + +COPY nginx-config /etc/nginx/ diff --git a/nginx-config/nginx.conf b/nginx-config/nginx.conf new file mode 100644 index 0000000..a8bfb5a --- /dev/null +++ b/nginx-config/nginx.conf @@ -0,0 +1,53 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; + +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + server_tokens off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log off; + + sendfile on; + sendfile_max_chunk 1m; + tcp_nopush on; + + keepalive_timeout 65; + + gzip on; + gzip_static on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied any; + gzip_disable "MSIE [1-6]\.(?!.*SV1)"; + + server { + listen 80; + server_name localhost; + + root /usr/share/nginx/html; + index index.html; + + location ~* \.(jpg|jpeg|png|ico)$ { + expires 30d; + } + + error_page 403 /403.html; + error_page 404 /404.html; + error_page 500 501 502 503 504 /50x.html; + + location ~ ^/(403|404|50x).html$ { + root /usr/share/nginx/html/errors; + internal; + } + } +} diff --git a/package.json b/package.json index 33ec4ae..0a7767a 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "sdf-2d-demo", "version": "0.0.0", - "description": "![logo](media/declared.png)", + "description": "Some simple demos to showcase the possibilities of this library.", "private": true, "main": "index.js", "scripts": { "start": "webpack-dev-server --mode development", "lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"", - "build": "webpack --mode production && find dist -type f -not -name '*.html' | xargs rm && sed -i 's/^\\/\\/#.*.map//' dist/index.html" + "build": "webpack --mode production && find dist -type f -not -regex \"dist\\/.*\\.\\(html\\|png\\|ico\\|svg\\|jpg\\)\" | xargs rm && sed -i 's/^\\/\\/#.*.map//' dist/index.html" }, "keywords": [], "author": "AndrĂ¡s Schmelczer (https://schmelczer.dev/)", @@ -21,25 +21,25 @@ "defaults" ], "sideEffects": [ - "*.scss" + "*.scss", + "*.png", + "*.jpg", + "*.ico", + "*.svg" ], "optimization": { "usedExports": true }, "devDependencies": { - "@types/gl-matrix": "^2.4.5", "@typescript-eslint/eslint-plugin": "^3.10.1", "@typescript-eslint/parser": "^3.10.1", "autoprefixer": "^9.8.6", - "clean-webpack-plugin": "^3.0.0", "css-loader": "^3.5.2", - "cssnano": "^4.1.10", "eslint": "^7.9.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-import": "^2.22.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-unused-imports": "^0.1.3", - "gl-matrix": "^3.3.0", "html-webpack-inline-source-plugin": "0.0.10", "html-webpack-plugin": "^3.2.0", "mini-css-extract-plugin": "^0.9.0", @@ -48,12 +48,10 @@ "prettier": "^2.1.2", "raw-loader": "^4.0.1", "resolve-url-loader": "^3.1.1", - "responsive-loader": "^1.2.0", "sass": "^1.26.3", "sass-loader": "^9.0.3", - "sdf-2d": "^0.0.0", + "sdf-2d": "^0.1.0-alpha", "source-map-loader": "^1.1.0", - "style-loader": "^1.1.4", "svg-url-loader": "^6.0.0", "terser-webpack-plugin": "^2.3.8", "ts-loader": "^8.0.3", diff --git a/src/helper/remove-unnecessary-outlines.ts b/src/helper/remove-unnecessary-outlines.ts new file mode 100644 index 0000000..fd2f1d5 --- /dev/null +++ b/src/helper/remove-unnecessary-outlines.ts @@ -0,0 +1,4 @@ +export const removeUnnecessaryOutlines = () => + (document.onclick = (e) => { + (e.target as HTMLElement)?.blur(); + }); diff --git a/src/index.html b/src/index.html index 360b255..8fced4c 100644 --- a/src/index.html +++ b/src/index.html @@ -2,31 +2,53 @@ + SDF-2D demo + + + + + + + + + + - - - - -
+ + SDF-2D + logo + + +
-

Error

+

Encountered an error

diff --git a/src/index.scss b/src/index.scss deleted file mode 100644 index 9ef9eb5..0000000 --- a/src/index.scss +++ /dev/null @@ -1,103 +0,0 @@ -$bg: linear-gradient(90deg, #103783, #9bafd9); - -html, -body, -canvas#main { - height: 100%; - width: 100%; - overflow: hidden; -} - -html { - @media (max-width: 800px) { - font-size: 0.7rem; - } - background: $bg; -} - -* { - margin: 0; - box-sizing: border-box; - font-family: Helvetica, Tahoma, sans-serif; - color: white; -} - -body { - position: relative; - - a { - text-decoration: none; - } - - button { - cursor: pointer; - border: 2px solid white; - border-radius: 6px; - padding: 0.2em 0.5rem; - background: none; - } - - #info, - #overlay, - #remove-clutter { - margin: 1rem 1.25rem; - position: absolute; - } - - #info { - left: 0; - font-size: 2.5rem; - - a { - display: flex; - justify-content: center; - align-items: center; - - img { - $size: 80px; - width: $size; - height: $size; - padding-left: 16px; - } - } - } - - #overlay { - font-size: 0.75rem; - right: 0; - white-space: pre; - font-family: 'Lucida Console', Monaco, monospace; - } - - #remove-clutter { - bottom: 0; - font-size: 1.25rem; - } - - #errors-container { - display: none; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - - text-align: center; - justify-content: center; - align-items: center; - - #errors { - width: min(500px, 90vw); - height: min(500px, 90vw); - h1 { - font-size: 3rem; - padding: 2rem; - } - - p { - text-align: left; - font-size: 1.25rem; - } - } - } -} diff --git a/src/index.ts b/src/index.ts index d2d5892..174c780 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,26 +1,40 @@ import { glMatrix } from 'gl-matrix'; +import '../static/favicons/apple-touch-icon.png'; +import '../static/favicons/favicon-16x16.png'; +import '../static/favicons/favicon-32x32.png'; +import '../static/favicons/favicon.ico'; +//import '../static/og-image.jpg'; import { DeltaTimeCalculator } from './helper/delta-time-calculator'; -import './index.scss'; -import { RainScene } from './scenes/rain/rain-scene'; +import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines'; +import { BlobScene } from './scenes/blob-scene'; import { Scene } from './scenes/scene'; -import { TunnelScene } from './scenes/tunnel-scene'; +import './styles/index.scss'; -const scenes = [TunnelScene, RainScene]; -const sceneIntervalInSeconds = 8; +const scenes = [/*TunnelScene, RainScene*/ BlobScene]; +const sceneIntervalInSeconds = 80000; glMatrix.setMatrixArrayType(Array); +removeUnnecessaryOutlines(); const deltaTimeCalculator = new DeltaTimeCalculator(); const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const info = document.querySelector('#info'); +const info = document.querySelector('#info') as HTMLDivElement; const errorText = document.querySelector('#error-text') as HTMLParamElement; +const errors = document.querySelector('#errors') as HTMLDivElement; const errorsContainer = document.querySelector('#errors-container') as HTMLDivElement; -const button = document.querySelector('#remove-clutter'); +const toggleButton = document.querySelector('#toggle-text'); const overlay = document.querySelector('#overlay') as HTMLDivElement; -button.addEventListener('click', () => - [info, button, overlay].forEach((e) => e.remove()) -); +let textVisible = false; +const handleTextToggle = () => { + [info, overlay, errors].forEach( + (e) => (e.style.visibility = textVisible ? 'hidden' : 'inherit') + ); + textVisible = !textVisible; + toggleButton.innerHTML = textVisible ? 'Hide text' : 'Show text'; +}; +toggleButton.addEventListener('click', handleTextToggle); +handleTextToggle(); const handleScene = async (SceneConstructor: new () => Scene) => { const scene = new SceneConstructor(); @@ -44,7 +58,6 @@ const handleScene = async (SceneConstructor: new () => Scene) => { requestAnimationFrame(handleFrame); await isOver; - scene.destroy(); }; @@ -57,7 +70,7 @@ const main = async () => { } catch (e) { console.error(e); errorText.innerText = e; - errorsContainer.style.display = 'flex'; + errorsContainer.style.visibility = 'visible'; } }; diff --git a/src/scenes/blob-scene.ts b/src/scenes/blob-scene.ts new file mode 100644 index 0000000..03e4192 --- /dev/null +++ b/src/scenes/blob-scene.ts @@ -0,0 +1,76 @@ +import { vec3 } from 'gl-matrix'; +import { Circle, CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d'; +import { Scene } from './scene'; + +export class BlobScene implements Scene { + private renderer: Renderer; + private canvas: HTMLCanvasElement; + private overlay: HTMLDivElement; + + private tunnels: Array = []; + private lights: Array = []; + + public async initialize( + canvas: HTMLCanvasElement, + overlay: HTMLDivElement + ): Promise { + this.canvas = canvas; + this.overlay = overlay; + this.renderer = await compile( + canvas, + [ + { + ...InvertedTunnel.descriptor, + shaderCombinationSteps: [0, 1, 2, 4, 8, 12], + }, + Circle.descriptor, + { + ...CircleLight.descriptor, + shaderCombinationSteps: [1, 2, 3, 4, 5, 6, 7], + }, + ], + [vec3.fromValues(0.4, 1, 0.6), vec3.fromValues(1, 1, 0), vec3.fromValues(0.3, 1, 1)] + ); + + this.renderer.setRuntimeSettings({ + ambientLight: vec3.fromValues(0.35, 0.1, 0.45), + shadowLength: 550, + }); + } + + private deltaSinceStart = 0; + public drawNextFrame( + currentTime: DOMHighResTimeStamp, + deltaTime: DOMHighResTimeStamp + ): void { + const { width, height } = this.canvas.getBoundingClientRect(); + this.deltaSinceStart += deltaTime; + this.renderer.setViewArea([0, height], [width, height]); + + this.renderer.autoscaleQuality(deltaTime); + this.overlay.innerText = JSON.stringify( + this.renderer.insights, + (_, v) => (v.toFixed ? Number(v.toFixed(2)) : v), + ' ' + ); + + const q = (this.deltaSinceStart % 5000) / 2500; + console.log(q); + + [ + new Circle([width / 2, -width / 4], width / 2), + new CircleLight([q * width, Math.sin(q * Math.PI) * height], [1, 0.8, 0], 1), + new CircleLight( + [(q - 1) * width, Math.sin((q - 1) * Math.PI) * height], + [0, 0.8, 1], + 1 + ), + ].forEach((d) => this.renderer.addDrawable(d)); + + this.renderer.renderDrawables(); + } + + public destroy(): void { + this.renderer.destroy(); + } +} diff --git a/webpack.config.js b/webpack.config.js index 0dfabec..1cbb137 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -23,7 +23,7 @@ module.exports = { filename: '[name].[contenthash].js', path: PATHS.bundles, }, - devtool: isDevelopment ? 'source-map' : '', + devtool: isDevelopment ? 'source-map' : 'null', watchOptions: { aggregateTimeout: 600, ignored: /node_modules/, @@ -100,6 +100,16 @@ module.exports = { noquotes: true, }, }, + { + test: /\.(ico|png|jpg)$/i, + use: { + loader: 'file-loader', + query: { + outputPath: '/', + name: '[name].[ext]', + }, + }, + }, { test: /\.js$/, enforce: 'pre',