Compare commits
No commits in common. "790b1352fe84c55c68b32eda6e8cee9463ce6698" and "4dbc6043878decf3469755474f8d34787a027ba6" have entirely different histories.
790b1352fe
...
4dbc604387
12 changed files with 23508 additions and 7373 deletions
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
**/*.js
|
||||||
28
.eslintrc.json
Normal file
28
.eslintrc.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2020": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 11,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["unused-imports", "@typescript-eslint", "prettier"],
|
||||||
|
"rules": {
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"unused-imports/no-unused-imports-ts": "error",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import js from '@eslint/js';
|
|
||||||
import tseslint from 'typescript-eslint';
|
|
||||||
import prettierConfig from 'eslint-config-prettier';
|
|
||||||
import prettierPlugin from 'eslint-plugin-prettier';
|
|
||||||
import unusedImports from 'eslint-plugin-unused-imports';
|
|
||||||
import globals from 'globals';
|
|
||||||
|
|
||||||
export default tseslint.config(
|
|
||||||
{ ignores: ['dist/', 'node_modules/', '**/*.js'] },
|
|
||||||
js.configs.recommended,
|
|
||||||
...tseslint.configs.recommended,
|
|
||||||
prettierConfig,
|
|
||||||
{
|
|
||||||
files: ['src/**/*.ts'],
|
|
||||||
languageOptions: {
|
|
||||||
globals: { ...globals.browser },
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
'unused-imports': unusedImports,
|
|
||||||
prettier: prettierPlugin,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'prettier/prettier': 'error',
|
|
||||||
'no-unused-vars': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'unused-imports/no-unused-imports': 'error',
|
|
||||||
'unused-imports/no-unused-vars': [
|
|
||||||
'warn',
|
|
||||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
||||||
],
|
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
30598
package-lock.json
generated
30598
package-lock.json
generated
File diff suppressed because it is too large
Load diff
66
package.json
66
package.json
|
|
@ -4,9 +4,9 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.html",
|
"main": "index.html",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack serve --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 && rm -f dist/*.js dist/*.css"
|
"build": "webpack --mode production && rm dist/*.js && rm dist/*.css"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
||||||
|
|
@ -23,35 +23,37 @@
|
||||||
"*.scss"
|
"*.scss"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@types/gl-matrix": "^2.4.5",
|
||||||
"@plausible-analytics/tracker": "^0.4.5",
|
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
||||||
"autoprefixer": "^10.5.0",
|
"@typescript-eslint/parser": "^3.10.1",
|
||||||
"css-loader": "^7.1.4",
|
"autoprefixer": "^9.8.6",
|
||||||
"css-minimizer-webpack-plugin": "^8.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"eslint": "^10.4.1",
|
"css-loader": "^3.5.2",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint": "^7.9.0",
|
||||||
"eslint-plugin-prettier": "^5.5.6",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-plugin-unused-imports": "^4.4.1",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"gl-matrix": "^3.4.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"globals": "^17.6.0",
|
"eslint-plugin-unused-imports": "^0.1.3",
|
||||||
"html-inline-css-webpack-plugin": "^1.11.2",
|
"gl-matrix": "^3.3.0",
|
||||||
"html-inline-script-webpack-plugin": "^3.2.1",
|
"html-webpack-inline-source-plugin": "^1.0.0-beta.2",
|
||||||
"html-loader": "^5.1.0",
|
"html-webpack-inline-svg-plugin": "^2.3.0",
|
||||||
"html-webpack-plugin": "^5.6.7",
|
"html-webpack-plugin": "^4.5.0",
|
||||||
"mini-css-extract-plugin": "^2.10.2",
|
"mini-css-extract-plugin": "^0.9.0",
|
||||||
"postcss": "^8.5.15",
|
"optimize-css-assets-webpack-plugin": "^5.0.4",
|
||||||
"postcss-loader": "^8.2.1",
|
"postcss-loader": "^3.0.0",
|
||||||
"prettier": "^3.8.3",
|
"prettier": "^2.1.2",
|
||||||
"resolve-url-loader": "^5.0.0",
|
"raw-loader": "^4.0.1",
|
||||||
"sass": "^1.100.0",
|
"resolve-url-loader": "^3.1.1",
|
||||||
"sass-loader": "^17.0.0",
|
"sass": "^1.27.0",
|
||||||
"sdf-2d": "^0.7.6",
|
"sass-loader": "^8.0.2",
|
||||||
"source-map-loader": "^5.0.0",
|
"sdf-2d": "^0.7.4",
|
||||||
"ts-loader": "^9.6.0",
|
"source-map-loader": "^1.1.1",
|
||||||
"typescript": "^6.0.3",
|
"svg-url-loader": "^6.0.0",
|
||||||
"typescript-eslint": "^8.60.1",
|
"ts-config-webpack-plugin": "^2.0.0",
|
||||||
"webpack": "^5.107.2",
|
"ts-loader": "^8.0.3",
|
||||||
"webpack-cli": "^7.0.3",
|
"typescript": "^4.0.3",
|
||||||
"webpack-dev-server": "^5.2.4"
|
"webpack": "^4.43.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-dev-server": "^3.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
import {
|
|
||||||
init as plausibleInit,
|
|
||||||
track as plausibleTrack,
|
|
||||||
type PlausibleEventOptions,
|
|
||||||
} from '@plausible-analytics/tracker';
|
|
||||||
|
|
||||||
const ANALYTICS_AUTO_CAPTURE_PAGEVIEWS = true;
|
|
||||||
const ANALYTICS_DOMAIN = 'schmelczer.dev/sdf2d';
|
|
||||||
const ANALYTICS_ENDPOINT = 'https://stats.schmelczer.dev/status';
|
|
||||||
const ANALYTICS_LOGGING = process.env.NODE_ENV !== 'production';
|
|
||||||
|
|
||||||
let isInitialized = false;
|
|
||||||
|
|
||||||
export const track = (eventName: string, options: PlausibleEventOptions = {}) => {
|
|
||||||
try {
|
|
||||||
plausibleTrack(eventName, options);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`Could not track analytics event "${eventName}".`, error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const initAnalytics = () => {
|
|
||||||
if (isInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
plausibleInit({
|
|
||||||
domain: ANALYTICS_DOMAIN,
|
|
||||||
endpoint: ANALYTICS_ENDPOINT,
|
|
||||||
autoCapturePageviews: ANALYTICS_AUTO_CAPTURE_PAGEVIEWS,
|
|
||||||
logging: ANALYTICS_LOGGING,
|
|
||||||
});
|
|
||||||
isInitialized = true;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Could not initialize analytics.', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
|
|
||||||
export class Circle {
|
export class Circle {
|
||||||
constructor(
|
constructor(public center: vec2, public radius: number) {}
|
||||||
public center: vec2,
|
|
||||||
public radius: number
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public distance(target: vec2): number {
|
public distance(target: vec2): number {
|
||||||
return vec2.distance(this.center, target) - this.radius;
|
return vec2.distance(this.center, target) - this.radius;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import '../static/no-change/favicons/favicon-32x32.png';
|
||||||
import '../static/no-change/favicons/favicon.ico';
|
import '../static/no-change/favicons/favicon.ico';
|
||||||
import '../static/no-change/og-image.png';
|
import '../static/no-change/og-image.png';
|
||||||
import '../static/no-change/robots.txt';
|
import '../static/no-change/robots.txt';
|
||||||
import { initAnalytics } from './analytics';
|
|
||||||
import { extractInsights } from './helper/extract-insights';
|
import { extractInsights } from './helper/extract-insights';
|
||||||
import { handleFullScreen } from './helper/handle-full-screen';
|
import { handleFullScreen } from './helper/handle-full-screen';
|
||||||
import { handleInsights } from './helper/handle-insights';
|
import { handleInsights } from './helper/handle-insights';
|
||||||
|
|
@ -25,12 +24,11 @@ Random.seed = 2;
|
||||||
|
|
||||||
glMatrix.setMatrixArrayType(Array);
|
glMatrix.setMatrixArrayType(Array);
|
||||||
removeUnnecessaryOutlines();
|
removeUnnecessaryOutlines();
|
||||||
initAnalytics();
|
|
||||||
|
|
||||||
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
|
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
|
||||||
const logo = document.querySelector('#info') as HTMLElement;
|
const logo = document.querySelector('#info') as HTMLElement;
|
||||||
const canvasContainer = document.querySelector('#canvas-container') as HTMLCanvasElement;
|
const canvasContainer = document.querySelector('#canvas-container') as HTMLCanvasElement;
|
||||||
const errorText = document.querySelector('#error-text') as HTMLParagraphElement;
|
const errorText = document.querySelector('#error-text') as HTMLParamElement;
|
||||||
const errorsContainer = document.querySelector('#errors-container') as HTMLDivElement;
|
const errorsContainer = document.querySelector('#errors-container') as HTMLDivElement;
|
||||||
const toggleButton = document.querySelector('#toggle-text') as HTMLElement;
|
const toggleButton = document.querySelector('#toggle-text') as HTMLElement;
|
||||||
const minimizeButton = document.querySelector('#minimize') as HTMLElement;
|
const minimizeButton = document.querySelector('#minimize') as HTMLElement;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@ export class Metaball {
|
||||||
|
|
||||||
private direction = Random.getRandom() > 0.5 ? 1 : -1;
|
private direction = Random.getRandom() > 0.5 ? 1 : -1;
|
||||||
private speed = Random.getRandomInRange(0.5, 2);
|
private speed = Random.getRandomInRange(0.5, 2);
|
||||||
constructor(
|
constructor(private readonly center: vec2, private readonly size: vec2) {}
|
||||||
private readonly center: vec2,
|
|
||||||
private readonly size: vec2
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public animate(currentTime: DOMHighResTimeStamp, width: number, height: number) {
|
public animate(currentTime: DOMHighResTimeStamp, width: number, height: number) {
|
||||||
vec2.set(
|
vec2.set(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@use './mixins' as *;
|
@import './mixins';
|
||||||
|
|
||||||
$breakpoint: 800px;
|
$breakpoint: 800px;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"strict": false,
|
"target": "es5",
|
||||||
"target": "ES2017",
|
"downlevelIteration": true,
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "node10",
|
|
||||||
"ignoreDeprecations": "6.0",
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"esModuleInterop": true,
|
"moduleResolution": "Node",
|
||||||
"lib": ["ES2017", "DOM"],
|
"module": "es6",
|
||||||
|
"lib": ["es2016", "dom"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const TsConfigWebpackPlugin = require('ts-config-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
||||||
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
|
const HtmlWebpackInlineSVGPlugin = require('html-webpack-inline-svg-plugin');
|
||||||
const HTMLInlineCSSWebpackPlugin =
|
const Sass = require('sass');
|
||||||
require('html-inline-css-webpack-plugin').default;
|
|
||||||
|
|
||||||
const PATHS = {
|
const PATHS = {
|
||||||
entryPoint: path.resolve(__dirname, 'src/index.ts'),
|
entryPoint: path.resolve(__dirname, 'src/index.ts'),
|
||||||
|
|
@ -12,14 +13,6 @@ const PATHS = {
|
||||||
bundles: path.resolve(__dirname, 'dist'),
|
bundles: path.resolve(__dirname, 'dist'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inline the UI SVGs referenced via <img src> into the HTML (replacing the
|
|
||||||
// abandoned html-webpack-inline-svg-plugin). Scope html-loader to <img src> so
|
|
||||||
// the favicon <link href> tags are left to resolve against the emitted files.
|
|
||||||
const htmlLoaderOptions = JSON.stringify({
|
|
||||||
sources: { list: [{ tag: 'img', attribute: 'src', type: 'src' }] },
|
|
||||||
minimize: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
index: PATHS.entryPoint,
|
index: PATHS.entryPoint,
|
||||||
|
|
@ -27,7 +20,6 @@ module.exports = {
|
||||||
target: 'web',
|
target: 'web',
|
||||||
output: {
|
output: {
|
||||||
path: PATHS.bundles,
|
path: PATHS.bundles,
|
||||||
clean: true,
|
|
||||||
},
|
},
|
||||||
//devtool: 'source-map',
|
//devtool: 'source-map',
|
||||||
watchOptions: {
|
watchOptions: {
|
||||||
|
|
@ -36,13 +28,14 @@ module.exports = {
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
allowedHosts: 'all',
|
disableHostCheck: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
new MiniCssExtractPlugin(),
|
new MiniCssExtractPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
xhtml: true,
|
xhtml: true,
|
||||||
template: `!!html-loader?${htmlLoaderOptions}!${PATHS.entryHtml}`,
|
template: PATHS.entryHtml,
|
||||||
minify: {
|
minify: {
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
removeComments: true,
|
removeComments: true,
|
||||||
|
|
@ -51,70 +44,64 @@ module.exports = {
|
||||||
removeStyleLinkTypeAttributes: true,
|
removeStyleLinkTypeAttributes: true,
|
||||||
useShortDoctype: true,
|
useShortDoctype: true,
|
||||||
},
|
},
|
||||||
|
inlineSource: '.(js|css)$',
|
||||||
}),
|
}),
|
||||||
new HtmlInlineScriptPlugin(),
|
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin),
|
||||||
new HTMLInlineCSSWebpackPlugin(),
|
new HtmlWebpackInlineSVGPlugin({
|
||||||
|
inlineAll: true,
|
||||||
|
}),
|
||||||
|
new TsConfigWebpackPlugin(),
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
|
||||||
test: /\.ts$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
// transpileOnly mirrors the project's prior de-facto behaviour: the old
|
|
||||||
// ts-config-webpack-plugin ran type-checking in a separate fork-ts-checker
|
|
||||||
// process that crashes on Node 22, so types were never actually enforced.
|
|
||||||
// (`npm run lint` still type-aware-lints; full type-checking can be
|
|
||||||
// re-enabled separately once the pre-existing type errors are addressed.)
|
|
||||||
use: {
|
|
||||||
loader: 'ts-loader',
|
|
||||||
options: { transpileOnly: true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: [
|
use: [
|
||||||
MiniCssExtractPlugin.loader,
|
MiniCssExtractPlugin.loader,
|
||||||
'css-loader',
|
'css-loader',
|
||||||
'postcss-loader',
|
'postcss-loader',
|
||||||
// resolve-url-loader v5 always retains the query/hash (the old
|
{
|
||||||
// `keepQuery` option was removed), so no options are needed.
|
loader: 'resolve-url-loader',
|
||||||
'resolve-url-loader',
|
options: {
|
||||||
|
keepQuery: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
loader: 'sass-loader',
|
loader: 'sass-loader',
|
||||||
options: {
|
options: {
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
implementation: require('sass'),
|
implementation: Sass,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Favicons, og-image, 404.html and robots.txt: emit verbatim to the
|
|
||||||
// dist root (imported for their side effect in src/index.ts).
|
|
||||||
// sideEffects:true keeps these bare imports from being tree-shaken away
|
|
||||||
// under the package's "sideEffects": ["*.scss"] declaration.
|
|
||||||
test: /no-change.*$/i,
|
test: /no-change.*$/i,
|
||||||
type: 'asset/resource',
|
use: {
|
||||||
sideEffects: true,
|
loader: 'file-loader',
|
||||||
generator: {
|
query: {
|
||||||
filename: '[name][ext]',
|
outputPath: '/',
|
||||||
|
name: '[name].[ext]',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.(svg)$/,
|
||||||
type: 'asset/inline',
|
use: {
|
||||||
|
loader: 'file-loader',
|
||||||
|
query: {
|
||||||
|
outputPath: '/',
|
||||||
|
name: '[name].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
exclude: /node_modules/,
|
|
||||||
use: ['source-map-loader'],
|
use: ['source-map-loader'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
optimization: {
|
|
||||||
minimizer: ['...', new CssMinimizerPlugin()],
|
|
||||||
},
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.js'],
|
extensions: ['.ts', '.js'],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue