Update project
This commit is contained in:
parent
bcbf4224c2
commit
fd64d9491d
16 changed files with 311 additions and 99 deletions
50
.github/workflows/main.yaml
vendored
Normal file
50
.github/workflows/main.yaml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
name: Deploy everything
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
env:
|
||||||
|
CONTAINER_REGISTRY: schmelczera
|
||||||
|
DOMAIN: schmelczer.dev
|
||||||
|
PROJECT_NAME: sdf-2d-demo
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-frontend:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout current branch with lfs
|
||||||
|
uses: actions/checkout@main
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Setup auth tokens
|
||||||
|
run: |
|
||||||
|
docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Build and push frontend
|
||||||
|
run: |
|
||||||
|
docker build . -t $CONTAINER_REGISTRY/$PROJECT_NAME
|
||||||
|
docker push $CONTAINER_REGISTRY/$PROJECT_NAME
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- name: Checkout current branch with lfs
|
||||||
|
uses: actions/checkout@main
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Setup auth tokens
|
||||||
|
run: |
|
||||||
|
# SSH key
|
||||||
|
mkdir ~/.ssh
|
||||||
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||||
|
chmod 400 ~/.ssh/id_ed25519
|
||||||
|
ssh -o StrictHostKeyChecking=no root@$DOMAIN uptime
|
||||||
|
|
||||||
|
- name: Stack deploy
|
||||||
|
run: |
|
||||||
|
DOCKER_HOST=ssh://root@$DOMAIN docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
DOCKER_HOST=ssh://root@$DOMAIN docker stack deploy $PROJECT_NAME -c docker-compose.yml --with-registry-auth
|
||||||
|
|
@ -7,12 +7,11 @@ WORKDIR /home/node
|
||||||
|
|
||||||
COPY src src
|
COPY src src
|
||||||
COPY static static
|
COPY static static
|
||||||
COPY package.json custom.d.ts tsconfig.json webpack.config.js ./
|
COPY package.json tsconfig.json webpack.config.js ./
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
HEALTHCHECK --interval=1m --timeout=10s CMD curl --fail http://localhost/ || exit 1
|
HEALTHCHECK --interval=1m --timeout=10s CMD curl --fail http://localhost/ || exit 1
|
||||||
|
|
@ -22,7 +21,7 @@ WORKDIR /usr/share/nginx/html
|
||||||
RUN rm -rf *
|
RUN rm -rf *
|
||||||
COPY --from=build-webpage /home/node/dist .
|
COPY --from=build-webpage /home/node/dist .
|
||||||
COPY --from=build-error-pages /home/python/built errors
|
COPY --from=build-error-pages /home/python/built errors
|
||||||
RUN find . -type f | xargs gzip -k9 &&\
|
RUN find . -type f | xargs gzip -k9 &&\
|
||||||
chmod -R 555 .
|
chmod -R 555 .
|
||||||
|
|
||||||
COPY nginx-config /etc/nginx/
|
COPY nginx-config /etc/nginx/
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<img src="static/logo.svg" width=128 height=128 alt="logo" />
|
<img src="static/logo-colored.svg" width=128 height=128 alt="logo" />
|
||||||
|
|
||||||
# SDF-2D demo
|
# SDF-2D demo
|
||||||
|
|
||||||
|
|
|
||||||
31
docker-compose.yml
Normal file
31
docker-compose.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
sdf-2d-demo:
|
||||||
|
init: true
|
||||||
|
image: schmelczera/sdf-2d-demo
|
||||||
|
networks:
|
||||||
|
- network
|
||||||
|
deploy:
|
||||||
|
replicas: 3
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "0.1"
|
||||||
|
memory: 16M
|
||||||
|
reservations:
|
||||||
|
cpus: "0.1"
|
||||||
|
memory: 16M
|
||||||
|
placement:
|
||||||
|
max_replicas_per_node: 1
|
||||||
|
update_config:
|
||||||
|
parallelism: 1
|
||||||
|
failure_action: rollback
|
||||||
|
delay: 10s
|
||||||
|
monitor: 10s
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
window: 30s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
network:
|
||||||
|
driver: overlay
|
||||||
15
package.json
15
package.json
|
|
@ -7,7 +7,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --mode development",
|
"start": "webpack-dev-server --mode development",
|
||||||
"lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"",
|
"lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"",
|
||||||
"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"
|
"build": "rm -rf dist/* && 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": [],
|
"keywords": [],
|
||||||
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
||||||
|
|
@ -20,19 +20,12 @@
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
],
|
],
|
||||||
"sideEffects": [
|
"sideEffects": false,
|
||||||
"*.scss",
|
|
||||||
"*.png",
|
|
||||||
"*.jpg",
|
|
||||||
"*.ico",
|
|
||||||
"*.svg"
|
|
||||||
],
|
|
||||||
"optimization": {
|
|
||||||
"usedExports": true
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
||||||
"@typescript-eslint/parser": "^3.10.1",
|
"@typescript-eslint/parser": "^3.10.1",
|
||||||
|
"@types/gl-matrix": "^2.4.5",
|
||||||
|
"gl-matrix": "^3.3.0",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
"css-loader": "^3.5.2",
|
"css-loader": "^3.5.2",
|
||||||
"eslint": "^7.9.0",
|
"eslint": "^7.9.0",
|
||||||
|
|
|
||||||
2
src/helper/pretty-print.ts
Normal file
2
src/helper/pretty-print.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
export const prettyPrint = (o: any): string =>
|
||||||
|
JSON.stringify(o, (_, v) => (v.toFixed ? Number(v.toFixed(2)) : v), ' ');
|
||||||
|
|
@ -2,37 +2,23 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
<title>SDF-2D demo</title>
|
<title>SDF-2D demo</title>
|
||||||
|
|
||||||
<meta property="og:image:width" content="1500" />
|
<meta property="og:image:width" content="1438" />
|
||||||
<meta property="og:image:height" content="785" />
|
<meta property="og:image:height" content="638" />
|
||||||
<meta property="og:url" content="https://sdf2d.schmelczer.dev" />
|
<meta property="og:url" content="https://sdf2d.schmelczer.dev" />
|
||||||
<meta property="og:image" content="https://sdf2d.schmelczer.dev/og-image.jpg" />
|
<meta property="og:image" content="https://sdf2d.schmelczer.dev/og-image.jpg" />
|
||||||
|
|
||||||
<meta name="theme-color" content="#103783" />
|
<meta name="theme-color" content="#103783" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Some simple demos to showcase the possibilities of the sdf-2d library library. Click on the title to find out more."
|
content="Some simple demos to showcase the possibilities of the sdf-2d library library. Click on the title to find out more."
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link
|
|
||||||
rel="apple-touch-icon"
|
|
||||||
sizes="180x180"
|
|
||||||
href="static/favicons/apple-touch-icon.png"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/png"
|
|
||||||
sizes="32x32"
|
|
||||||
href="static/favicons/favicon-32x32.png"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/png"
|
|
||||||
sizes="16x16"
|
|
||||||
href="static/favicons/favicon-16x16.png"
|
|
||||||
/>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>Javascript is required for this website.</noscript>
|
<noscript>Javascript is required for this website.</noscript>
|
||||||
|
|
|
||||||
11
src/index.ts
11
src/index.ts
|
|
@ -3,15 +3,18 @@ import '../static/favicons/apple-touch-icon.png';
|
||||||
import '../static/favicons/favicon-16x16.png';
|
import '../static/favicons/favicon-16x16.png';
|
||||||
import '../static/favicons/favicon-32x32.png';
|
import '../static/favicons/favicon-32x32.png';
|
||||||
import '../static/favicons/favicon.ico';
|
import '../static/favicons/favicon.ico';
|
||||||
//import '../static/og-image.jpg';
|
import '../static/logo-white.svg';
|
||||||
|
import '../static/og-image.jpg';
|
||||||
import { DeltaTimeCalculator } from './helper/delta-time-calculator';
|
import { DeltaTimeCalculator } from './helper/delta-time-calculator';
|
||||||
import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines';
|
import { removeUnnecessaryOutlines } from './helper/remove-unnecessary-outlines';
|
||||||
import { BlobScene } from './scenes/blob-scene';
|
import { BlobScene } from './scenes/blob/blob-scene';
|
||||||
|
import { RainScene } from './scenes/rain/rain-scene';
|
||||||
import { Scene } from './scenes/scene';
|
import { Scene } from './scenes/scene';
|
||||||
|
import { TunnelScene } from './scenes/tunnel-scene';
|
||||||
import './styles/index.scss';
|
import './styles/index.scss';
|
||||||
|
|
||||||
const scenes = [/*TunnelScene, RainScene*/ BlobScene];
|
const scenes = [TunnelScene, RainScene, BlobScene];
|
||||||
const sceneIntervalInSeconds = 80000;
|
const sceneIntervalInSeconds = 8;
|
||||||
|
|
||||||
glMatrix.setMatrixArrayType(Array);
|
glMatrix.setMatrixArrayType(Array);
|
||||||
removeUnnecessaryOutlines();
|
removeUnnecessaryOutlines();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { vec3 } from 'gl-matrix';
|
import { vec2, vec3 } from 'gl-matrix';
|
||||||
import { Circle, CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d';
|
import { Circle, CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d';
|
||||||
import { Scene } from './scene';
|
import { prettyPrint } from '../../helper/pretty-print';
|
||||||
|
import { Scene } from '../scene';
|
||||||
|
import { Blob } from './blob';
|
||||||
|
|
||||||
export class BlobScene implements Scene {
|
export class BlobScene implements Scene {
|
||||||
private renderer: Renderer;
|
private renderer: Renderer;
|
||||||
|
|
@ -19,25 +21,33 @@ export class BlobScene implements Scene {
|
||||||
this.renderer = await compile(
|
this.renderer = await compile(
|
||||||
canvas,
|
canvas,
|
||||||
[
|
[
|
||||||
{
|
|
||||||
...InvertedTunnel.descriptor,
|
|
||||||
shaderCombinationSteps: [0, 1, 2, 4, 8, 12],
|
|
||||||
},
|
|
||||||
Circle.descriptor,
|
Circle.descriptor,
|
||||||
{
|
{
|
||||||
...CircleLight.descriptor,
|
...CircleLight.descriptor,
|
||||||
shaderCombinationSteps: [1, 2, 3, 4, 5, 6, 7],
|
shaderCombinationSteps: [1, 2],
|
||||||
},
|
},
|
||||||
|
Blob.descriptor,
|
||||||
],
|
],
|
||||||
[vec3.fromValues(0.4, 1, 0.6), vec3.fromValues(1, 1, 0), vec3.fromValues(0.3, 1, 1)]
|
[
|
||||||
|
vec3.fromValues(0, 0, 0),
|
||||||
|
vec3.fromValues(224 / 255, 96 / 255, 126 / 255),
|
||||||
|
vec3.fromValues(119 / 255, 173 / 255, 120 / 255),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
this.renderer.setRuntimeSettings({
|
this.renderer.setRuntimeSettings({
|
||||||
ambientLight: vec3.fromValues(0.35, 0.1, 0.45),
|
ambientLight: vec3.fromValues(0.35, 0.1, 0.45),
|
||||||
shadowLength: 550,
|
shadowLength: 800,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { width, height } = this.canvas.getBoundingClientRect();
|
||||||
|
const length = vec2.length([width, height]);
|
||||||
|
|
||||||
|
this.blob = new Blob([width / 2, -length / 4 + length / 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private blob: Blob;
|
||||||
|
|
||||||
private deltaSinceStart = 0;
|
private deltaSinceStart = 0;
|
||||||
public drawNextFrame(
|
public drawNextFrame(
|
||||||
currentTime: DOMHighResTimeStamp,
|
currentTime: DOMHighResTimeStamp,
|
||||||
|
|
@ -48,20 +58,28 @@ export class BlobScene implements Scene {
|
||||||
this.renderer.setViewArea([0, height], [width, height]);
|
this.renderer.setViewArea([0, height], [width, height]);
|
||||||
|
|
||||||
this.renderer.autoscaleQuality(deltaTime);
|
this.renderer.autoscaleQuality(deltaTime);
|
||||||
this.overlay.innerText = JSON.stringify(
|
this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||||
this.renderer.insights,
|
|
||||||
(_, v) => (v.toFixed ? Number(v.toFixed(2)) : v),
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
const q = (this.deltaSinceStart % 5000) / 2500;
|
const length = vec2.length([width, height]);
|
||||||
console.log(q);
|
|
||||||
|
|
||||||
|
const q = (this.deltaSinceStart % 8000) / 4000;
|
||||||
|
this.blob.animate(this.deltaSinceStart);
|
||||||
[
|
[
|
||||||
new Circle([width / 2, -width / 4], width / 2),
|
new Circle([width / 2, -length / 4], length / 2),
|
||||||
new CircleLight([q * width, Math.sin(q * Math.PI) * height], [1, 0.8, 0], 1),
|
this.blob,
|
||||||
new CircleLight(
|
new CircleLight(
|
||||||
[(q - 1) * width, Math.sin((q - 1) * Math.PI) * height],
|
[
|
||||||
|
(Math.cos((1 - q) * Math.PI) * length) / 2 + width / 2,
|
||||||
|
(Math.sin((1 - q) * Math.PI) * length) / 2,
|
||||||
|
],
|
||||||
|
[1, 0.8, 0],
|
||||||
|
1
|
||||||
|
),
|
||||||
|
new CircleLight(
|
||||||
|
[
|
||||||
|
(Math.cos(-q * Math.PI) * length) / 2 + width / 2,
|
||||||
|
(Math.sin(-q * Math.PI) * length) / 2,
|
||||||
|
],
|
||||||
[0, 0.8, 1],
|
[0, 0.8, 1],
|
||||||
1
|
1
|
||||||
),
|
),
|
||||||
139
src/scenes/blob/blob.ts
Normal file
139
src/scenes/blob/blob.ts
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
import { mat2d, vec2 } from 'gl-matrix';
|
||||||
|
import { Circle, Drawable, DrawableDescriptor } from 'sdf-2d';
|
||||||
|
|
||||||
|
export class Blob extends Drawable {
|
||||||
|
public static descriptor: DrawableDescriptor = {
|
||||||
|
sdf: {
|
||||||
|
shader: `
|
||||||
|
uniform struct {
|
||||||
|
vec2 headCenter;
|
||||||
|
vec2 leftFootCenter;
|
||||||
|
vec2 rightFootCenter;
|
||||||
|
float headRadius;
|
||||||
|
float footRadius;
|
||||||
|
float k;
|
||||||
|
}[BLOB_COUNT] blobs;
|
||||||
|
|
||||||
|
float smoothMin(float a, float b)
|
||||||
|
{
|
||||||
|
const float k = 80.0;
|
||||||
|
float res = exp2( -k*a ) + exp2( -k*b );
|
||||||
|
return -log2( res )/k;
|
||||||
|
}
|
||||||
|
|
||||||
|
float circleDistance(vec2 circleCenter, float radius) {
|
||||||
|
return distance(position, circleCenter) - radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blobMinDistance(inout float minDistance, inout float color) {
|
||||||
|
for (int i = 0; i < BLOB_COUNT; i++) {
|
||||||
|
float headDistance = circleDistance(blobs[i].headCenter, blobs[i].headRadius);
|
||||||
|
float leftFootDistance = circleDistance(blobs[i].leftFootCenter, blobs[i].footRadius);
|
||||||
|
float rightFootDistance = circleDistance(blobs[i].rightFootCenter, blobs[i].footRadius);
|
||||||
|
|
||||||
|
float res = min(
|
||||||
|
smoothMin(headDistance, leftFootDistance),
|
||||||
|
smoothMin(headDistance, rightFootDistance)
|
||||||
|
);
|
||||||
|
|
||||||
|
minDistance = min(minDistance, res);
|
||||||
|
color = mix(1.0, color, step(distanceNdcPixelSize + SURFACE_OFFSET, res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
distanceFunctionName: 'blobMinDistance',
|
||||||
|
},
|
||||||
|
uniformName: 'blobs',
|
||||||
|
uniformCountMacroName: 'BLOB_COUNT',
|
||||||
|
shaderCombinationSteps: [1],
|
||||||
|
empty: new Blob(vec2.fromValues(0, 0)),
|
||||||
|
};
|
||||||
|
|
||||||
|
public readonly boundingCircleRadius = 200;
|
||||||
|
|
||||||
|
protected readonly headRadius = 70;
|
||||||
|
protected readonly footRadius = 30;
|
||||||
|
|
||||||
|
private readonly headOffset = vec2.fromValues(0, 120);
|
||||||
|
private leftFootOffset = vec2.fromValues(-30, this.footRadius);
|
||||||
|
private rightFootOffset = vec2.fromValues(30, this.footRadius);
|
||||||
|
|
||||||
|
private leftFootOffsetDefault = vec2.fromValues(-30, this.footRadius);
|
||||||
|
private rightFootOffsetDefault = vec2.fromValues(30, this.footRadius);
|
||||||
|
|
||||||
|
protected boundingCircle = new Circle(vec2.create(), this.boundingCircleRadius);
|
||||||
|
protected head = new Circle(vec2.create(), this.headRadius);
|
||||||
|
protected leftFoot = new Circle(vec2.create(), this.footRadius);
|
||||||
|
protected rightFoot = new Circle(vec2.create(), this.footRadius);
|
||||||
|
|
||||||
|
public constructor(private center: vec2) {
|
||||||
|
super();
|
||||||
|
this.position = center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set position(value: vec2) {
|
||||||
|
vec2.copy(this.boundingCircle.center, value);
|
||||||
|
vec2.add(this.head.center, value, this.headOffset);
|
||||||
|
vec2.add(this.leftFoot.center, value, this.leftFootOffset);
|
||||||
|
vec2.add(this.rightFoot.center, value, this.rightFootOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public animate(time: number) {
|
||||||
|
const offset = 20;
|
||||||
|
const q = (time % 1000) / 500;
|
||||||
|
|
||||||
|
vec2.subtract(
|
||||||
|
this.rightFootOffset,
|
||||||
|
this.rightFootOffsetDefault,
|
||||||
|
vec2.fromValues(q * offset, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec2.subtract(
|
||||||
|
this.leftFootOffset,
|
||||||
|
this.leftFootOffsetDefault,
|
||||||
|
vec2.fromValues(q * offset, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec2.add(
|
||||||
|
this.rightFootOffset,
|
||||||
|
this.rightFootOffset,
|
||||||
|
vec2.fromValues(
|
||||||
|
Math.min(1, q) * offset * 2,
|
||||||
|
Math.sin(Math.min(1, q) * Math.PI) * 10
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
vec2.add(
|
||||||
|
this.leftFootOffset,
|
||||||
|
this.leftFootOffset,
|
||||||
|
vec2.fromValues(
|
||||||
|
(q > 1 ? q - 1 : 0) * offset * 2,
|
||||||
|
Math.sin((q > 1 ? q - 1 : 0) * Math.PI) * 10
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.position = this.center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public minDistance(target: vec2): number {
|
||||||
|
return this.boundingCircle.minDistance(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any {
|
||||||
|
return {
|
||||||
|
headCenter: vec2.transformMat2d(vec2.create(), this.head.center, transform2d),
|
||||||
|
leftFootCenter: vec2.transformMat2d(
|
||||||
|
vec2.create(),
|
||||||
|
this.leftFoot.center,
|
||||||
|
transform2d
|
||||||
|
),
|
||||||
|
rightFootCenter: vec2.transformMat2d(
|
||||||
|
vec2.create(),
|
||||||
|
this.rightFoot.center,
|
||||||
|
transform2d
|
||||||
|
),
|
||||||
|
headRadius: this.headRadius * transform1d,
|
||||||
|
footRadius: this.footRadius * transform1d,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { vec2, vec3 } from 'gl-matrix';
|
import { vec2, vec3 } from 'gl-matrix';
|
||||||
import { CircleLight, compile, Renderer, Tunnel } from 'sdf-2d';
|
import { CircleLight, compile, Renderer, Tunnel } from 'sdf-2d';
|
||||||
|
import { prettyPrint } from '../../helper/pretty-print';
|
||||||
import { Scene } from '../scene';
|
import { Scene } from '../scene';
|
||||||
import { Droplet } from './droplet';
|
import { Droplet } from './droplet';
|
||||||
|
|
||||||
|
|
@ -7,7 +8,7 @@ export class RainScene implements Scene {
|
||||||
private droplets: Array<Droplet> = [];
|
private droplets: Array<Droplet> = [];
|
||||||
private light1: CircleLight = new CircleLight(
|
private light1: CircleLight = new CircleLight(
|
||||||
vec2.create(),
|
vec2.create(),
|
||||||
vec3.fromValues(1, 0, 1),
|
vec3.fromValues(0.5, 0, 1),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
private light2: CircleLight = new CircleLight(
|
private light2: CircleLight = new CircleLight(
|
||||||
|
|
@ -20,12 +21,6 @@ export class RainScene implements Scene {
|
||||||
private canvas: HTMLCanvasElement;
|
private canvas: HTMLCanvasElement;
|
||||||
private overlay: HTMLDivElement;
|
private overlay: HTMLDivElement;
|
||||||
|
|
||||||
public constructor() {
|
|
||||||
for (let i = 0; i < 40; i++) {
|
|
||||||
this.droplets.push(new Droplet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async initialize(
|
public async initialize(
|
||||||
canvas: HTMLCanvasElement,
|
canvas: HTMLCanvasElement,
|
||||||
overlay: HTMLDivElement
|
overlay: HTMLDivElement
|
||||||
|
|
@ -51,6 +46,10 @@ export class RainScene implements Scene {
|
||||||
ambientLight: vec3.fromValues(0.45, 0.25, 0.45),
|
ambientLight: vec3.fromValues(0.45, 0.25, 0.45),
|
||||||
tileMultiplier: 10,
|
tileMultiplier: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < (canvas.getBoundingClientRect().width / 1000) * 20; i++) {
|
||||||
|
this.droplets.push(new Droplet());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public drawNextFrame(
|
public drawNextFrame(
|
||||||
|
|
@ -60,12 +59,7 @@ export class RainScene implements Scene {
|
||||||
const { width, height } = this.canvas.getBoundingClientRect();
|
const { width, height } = this.canvas.getBoundingClientRect();
|
||||||
this.renderer.setViewArea(vec2.fromValues(0, height), vec2.fromValues(width, height));
|
this.renderer.setViewArea(vec2.fromValues(0, height), vec2.fromValues(width, height));
|
||||||
this.renderer.autoscaleQuality(deltaTime);
|
this.renderer.autoscaleQuality(deltaTime);
|
||||||
|
this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||||
this.overlay.innerText = JSON.stringify(
|
|
||||||
this.renderer.insights,
|
|
||||||
(_, v) => (v.toFixed ? Number(v.toFixed(2)) : v),
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
const viewAreaSize = this.renderer.viewAreaSize;
|
const viewAreaSize = this.renderer.viewAreaSize;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { vec2, vec3 } from 'gl-matrix';
|
||||||
import { CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d';
|
import { CircleLight, compile, InvertedTunnel, Renderer } from 'sdf-2d';
|
||||||
import { clamp } from '../helper/clamp';
|
import { clamp } from '../helper/clamp';
|
||||||
import { last } from '../helper/last';
|
import { last } from '../helper/last';
|
||||||
|
import { prettyPrint } from '../helper/pretty-print';
|
||||||
import { Random } from '../helper/random';
|
import { Random } from '../helper/random';
|
||||||
import { Scene } from './scene';
|
import { Scene } from './scene';
|
||||||
|
|
||||||
|
|
@ -101,11 +102,7 @@ export class TunnelScene implements Scene {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.renderer.autoscaleQuality(deltaTime);
|
this.renderer.autoscaleQuality(deltaTime);
|
||||||
this.overlay.innerText = JSON.stringify(
|
this.overlay.innerText = prettyPrint(this.renderer.insights);
|
||||||
this.renderer.insights,
|
|
||||||
(_, v) => (v.toFixed ? Number(v.toFixed(2)) : v),
|
|
||||||
' '
|
|
||||||
);
|
|
||||||
|
|
||||||
[
|
[
|
||||||
...this.tunnels.filter(
|
...this.tunnels.filter(
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,18 @@
|
||||||
<defs>
|
<defs>
|
||||||
<g id="ray-a">
|
<g id="ray-a">
|
||||||
<rect x="18" y="-3" height="6" rx="3">
|
<rect x="18" y="-3" height="6" rx="3">
|
||||||
<animate attributeName="width" values="20;25;20" dur="4s" repeatCount="indefinite" />
|
<animate attributeName="width" values="20;25;20" dur="5s" repeatCount="indefinite" />
|
||||||
</rect>
|
</rect>
|
||||||
<circle cy="0" r="3">
|
<circle cy="0" r="3">
|
||||||
<animate attributeName="cx" values="47;40;47" dur="4s" repeatCount="indefinite" />
|
<animate attributeName="cx" values="47;40;47" dur="5s" repeatCount="indefinite" />
|
||||||
</circle>
|
</circle>
|
||||||
</g>
|
</g>
|
||||||
<g id="ray-b">
|
<g id="ray-b">
|
||||||
<rect x="18" y="-3" height="6" rx="3">
|
<rect x="18" y="-3" height="6" rx="3">
|
||||||
<animate attributeName="width" values="25;20;25" dur="4s" repeatCount="indefinite" />
|
<animate attributeName="width" values="25;20;25" dur="5s" repeatCount="indefinite" />
|
||||||
</rect>
|
</rect>
|
||||||
<circle cy="0" r="3">
|
<circle cy="0" r="3">
|
||||||
<animate attributeName="cx" values="40;47;40" dur="4s" repeatCount="indefinite" />
|
<animate attributeName="cx" values="40;47;40" dur="5s" repeatCount="indefinite" />
|
||||||
</circle>
|
</circle>
|
||||||
</g>
|
</g>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
attributeName="transform"
|
attributeName="transform"
|
||||||
type="rotate"
|
type="rotate"
|
||||||
values="0;90"
|
values="0;90"
|
||||||
dur="8s"
|
dur="10s"
|
||||||
repeatCount="indefinite"
|
repeatCount="indefinite"
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
static/og-image.jpg
Normal file
BIN
static/og-image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -3,12 +3,12 @@
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"target": "es5",
|
"target": "es6",
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"lib": ["es2015", "dom"]
|
"lib": ["es2017", "dom"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
||||||
const Sass = require('sass');
|
const Sass = require('sass');
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV == 'production';
|
|
||||||
const isDevelopment = !isProduction;
|
|
||||||
|
|
||||||
const PATHS = {
|
const PATHS = {
|
||||||
entryPoint: path.resolve(__dirname, 'src/index.ts'),
|
entryPoint: path.resolve(__dirname, 'src/index.ts'),
|
||||||
bundles: path.resolve(__dirname, 'dist'),
|
bundles: path.resolve(__dirname, 'dist'),
|
||||||
|
|
@ -23,7 +20,7 @@ module.exports = {
|
||||||
filename: '[name].[contenthash].js',
|
filename: '[name].[contenthash].js',
|
||||||
path: PATHS.bundles,
|
path: PATHS.bundles,
|
||||||
},
|
},
|
||||||
devtool: isDevelopment ? 'source-map' : 'null',
|
devtool: 'source-map',
|
||||||
watchOptions: {
|
watchOptions: {
|
||||||
aggregateTimeout: 600,
|
aggregateTimeout: 600,
|
||||||
ignored: /node_modules/,
|
ignored: /node_modules/,
|
||||||
|
|
@ -34,10 +31,11 @@ module.exports = {
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true,
|
minimize: true,
|
||||||
|
usedExports: true,
|
||||||
minimizer: [
|
minimizer: [
|
||||||
new TerserJSPlugin({
|
new TerserJSPlugin({
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
test: /\.js$/i,
|
test: /\.js$/,
|
||||||
}),
|
}),
|
||||||
new OptimizeCSSAssetsPlugin({}),
|
new OptimizeCSSAssetsPlugin({}),
|
||||||
],
|
],
|
||||||
|
|
@ -65,7 +63,7 @@ module.exports = {
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.scss$/i,
|
test: /\.scss$/,
|
||||||
use: [
|
use: [
|
||||||
MiniCssExtractPlugin.loader,
|
MiniCssExtractPlugin.loader,
|
||||||
'css-loader',
|
'css-loader',
|
||||||
|
|
@ -93,15 +91,7 @@ module.exports = {
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.(ico|png|jpg)$/,
|
||||||
loader: 'svg-url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10 * 1024,
|
|
||||||
noquotes: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(ico|png|jpg)$/i,
|
|
||||||
use: {
|
use: {
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
query: {
|
query: {
|
||||||
|
|
@ -110,6 +100,16 @@ module.exports = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.(svg)$/,
|
||||||
|
use: {
|
||||||
|
loader: 'file-loader',
|
||||||
|
query: {
|
||||||
|
outputPath: '/static',
|
||||||
|
name: '[name].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue