Modernise
All checks were successful
Check & deploy / build (push) Successful in 28s

This commit is contained in:
Andras Schmelczer 2026-06-03 08:24:00 +01:00
parent a93ba30322
commit 790b1352fe
12 changed files with 5201 additions and 21394 deletions

View file

@ -1 +0,0 @@
**/*.js

View file

@ -1,28 +0,0 @@
{
"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"
}
}

39
eslint.config.mjs Normal file
View file

@ -0,0 +1,39 @@
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',
},
}
);

26336
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,9 +4,9 @@
"private": true,
"main": "index.html",
"scripts": {
"start": "webpack-dev-server --mode development",
"start": "webpack serve --mode development",
"lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"",
"build": "webpack --mode production && rm dist/*.js && rm dist/*.css"
"build": "webpack --mode production && rm -f dist/*.js dist/*.css"
},
"keywords": [],
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
@ -23,38 +23,35 @@
"*.scss"
],
"devDependencies": {
"@eslint/js": "^10.0.1",
"@plausible-analytics/tracker": "^0.4.5",
"@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",
"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": "^1.0.0-beta.2",
"html-webpack-inline-svg-plugin": "^2.3.0",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^3.0.0",
"prettier": "^2.1.2",
"raw-loader": "^4.0.1",
"resolve-url-loader": "^3.1.1",
"sass": "^1.27.0",
"sass-loader": "^8.0.2",
"sdf-2d": "^0.7.4",
"source-map-loader": "^1.1.1",
"svg-url-loader": "^6.0.0",
"ts-config-webpack-plugin": "^2.0.0",
"ts-loader": "^8.0.3",
"typescript": "^4.0.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
"autoprefixer": "^10.5.0",
"css-loader": "^7.1.4",
"css-minimizer-webpack-plugin": "^8.0.0",
"eslint": "^10.4.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-unused-imports": "^4.4.1",
"gl-matrix": "^3.4.4",
"globals": "^17.6.0",
"html-inline-css-webpack-plugin": "^1.11.2",
"html-inline-script-webpack-plugin": "^3.2.1",
"html-loader": "^5.1.0",
"html-webpack-plugin": "^5.6.7",
"mini-css-extract-plugin": "^2.10.2",
"postcss": "^8.5.15",
"postcss-loader": "^8.2.1",
"prettier": "^3.8.3",
"resolve-url-loader": "^5.0.0",
"sass": "^1.100.0",
"sass-loader": "^17.0.0",
"sdf-2d": "^0.7.6",
"source-map-loader": "^5.0.0",
"ts-loader": "^9.6.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.60.1",
"webpack": "^5.107.2",
"webpack-cli": "^7.0.3",
"webpack-dev-server": "^5.2.4"
}
}

View file

@ -11,10 +11,7 @@ const ANALYTICS_LOGGING = process.env.NODE_ENV !== 'production';
let isInitialized = false;
export const track = (
eventName: string,
options: PlausibleEventOptions = {}
) => {
export const track = (eventName: string, options: PlausibleEventOptions = {}) => {
try {
plausibleTrack(eventName, options);
} catch (error) {

View file

@ -1,7 +1,10 @@
import { vec2 } from 'gl-matrix';
export class Circle {
constructor(public center: vec2, public radius: number) {}
constructor(
public center: vec2,
public radius: number
) {}
public distance(target: vec2): number {
return vec2.distance(this.center, target) - this.radius;

View file

@ -30,7 +30,7 @@ initAnalytics();
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const logo = document.querySelector('#info') as HTMLElement;
const canvasContainer = document.querySelector('#canvas-container') as HTMLCanvasElement;
const errorText = document.querySelector('#error-text') as HTMLParamElement;
const errorText = document.querySelector('#error-text') as HTMLParagraphElement;
const errorsContainer = document.querySelector('#errors-container') as HTMLDivElement;
const toggleButton = document.querySelector('#toggle-text') as HTMLElement;
const minimizeButton = document.querySelector('#minimize') as HTMLElement;

View file

@ -9,7 +9,10 @@ export class Metaball {
private direction = Random.getRandom() > 0.5 ? 1 : -1;
private speed = Random.getRandomInRange(0.5, 2);
constructor(private readonly center: vec2, private readonly size: vec2) {}
constructor(
private readonly center: vec2,
private readonly size: vec2
) {}
public animate(currentTime: DOMHighResTimeStamp, width: number, height: number) {
vec2.set(

View file

@ -1,4 +1,4 @@
@import './mixins';
@use './mixins' as *;
$breakpoint: 800px;

View file

@ -1,16 +1,18 @@
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": false,
"target": "es5",
"downlevelIteration": true,
"strict": false,
"target": "ES2017",
"module": "ESNext",
"moduleResolution": "node10",
"ignoreDeprecations": "6.0",
"allowJs": true,
"experimentalDecorators": true,
"moduleResolution": "Node",
"module": "es6",
"lib": ["es2016", "dom"],
"esModuleInterop": true,
"lib": ["ES2017", "DOM"],
"skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules"]
}

View file

@ -1,11 +1,10 @@
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TsConfigWebpackPlugin = require('ts-config-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const HtmlWebpackInlineSVGPlugin = require('html-webpack-inline-svg-plugin');
const Sass = require('sass');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
const HTMLInlineCSSWebpackPlugin =
require('html-inline-css-webpack-plugin').default;
const PATHS = {
entryPoint: path.resolve(__dirname, 'src/index.ts'),
@ -13,6 +12,14 @@ const PATHS = {
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 = {
entry: {
index: PATHS.entryPoint,
@ -20,6 +27,7 @@ module.exports = {
target: 'web',
output: {
path: PATHS.bundles,
clean: true,
},
//devtool: 'source-map',
watchOptions: {
@ -28,14 +36,13 @@ module.exports = {
},
devServer: {
host: '0.0.0.0',
disableHostCheck: true,
allowedHosts: 'all',
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
xhtml: true,
template: PATHS.entryHtml,
template: `!!html-loader?${htmlLoaderOptions}!${PATHS.entryHtml}`,
minify: {
collapseWhitespace: true,
removeComments: true,
@ -44,64 +51,70 @@ module.exports = {
removeStyleLinkTypeAttributes: true,
useShortDoctype: true,
},
inlineSource: '.(js|css)$',
}),
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin),
new HtmlWebpackInlineSVGPlugin({
inlineAll: true,
}),
new TsConfigWebpackPlugin(),
new HtmlInlineScriptPlugin(),
new HTMLInlineCSSWebpackPlugin(),
],
module: {
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$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader: 'resolve-url-loader',
options: {
keepQuery: true,
},
},
// resolve-url-loader v5 always retains the query/hash (the old
// `keepQuery` option was removed), so no options are needed.
'resolve-url-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: Sass,
implementation: require('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,
use: {
loader: 'file-loader',
query: {
outputPath: '/',
name: '[name].[ext]',
},
type: 'asset/resource',
sideEffects: true,
generator: {
filename: '[name][ext]',
},
},
{
test: /\.(svg)$/,
use: {
loader: 'file-loader',
query: {
outputPath: '/',
name: '[name].[ext]',
},
},
test: /\.svg$/,
type: 'asset/inline',
},
{
test: /\.js$/,
enforce: 'pre',
exclude: /node_modules/,
use: ['source-map-loader'],
},
],
},
optimization: {
minimizer: ['...', new CssMinimizerPlugin()],
},
resolve: {
extensions: ['.ts', '.js'],
},