From 5d69739d0dbe0701378fedf046f7b4004ef68e7e Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:34:11 +0900 Subject: [PATCH 01/32] chore: add eslint, prettier (code formating) --- .eslintrc.json | 20 ++++++++++++ .idea/codeStyles/Project.xml | 48 ++++++++++++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 +++ .idea/prettier.xml | 8 +++++ .prettierrc | 7 ++++ 5 files changed, 88 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/prettier.xml create mode 100644 .prettierrc diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..1fe0a72 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:prettier/recommended" + ], + "plugins": ["prettier"], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + "prettier/prettier": "error", + "no-unused-vars": "warn", + "no-console": "off" + } +} diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..904225f --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..ea0f3cf --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..bae74ff --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "printWidth": 100, + "tabWidth": 4, + "trailingComma": "all", + "singleQuote": true, + "semi": true +} \ No newline at end of file From b30c92d4e50b2ec23e702ad5cd264982bfa5aac4 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:40:56 +0900 Subject: [PATCH 02/32] build: add vite --- vite.config.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 vite.config.ts diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..58a9b50 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; + +export default defineConfig({ + root: '.', // 기본값, 생략 가능 + publicDir: 'public', + build: { + outDir: 'dist', + target: 'esnext', + }, + server: { + port: 5173, + open: true, + }, +}); From 1ddc1ce9658d50dc946505a947d92d0e399d3e2e Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:42:54 +0900 Subject: [PATCH 03/32] chore: add pnpm --- package.json | 20 +- pnpm-lock.yaml | 752 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 768 insertions(+), 4 deletions(-) create mode 100644 pnpm-lock.yaml diff --git a/package.json b/package.json index 15fecff..d780ffc 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,21 @@ "version": "1.0.0", "type": "module", "description": "", - "main": "public/index.html", + "main": "index.html", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "format": "prettier --write ." }, - "private": true -} + "private": true, + "devDependencies": { + "eslint": "^9.32.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.3", + "prettier": "3.6.2" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..7ec903a --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,752 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + eslint: + specifier: ^9.32.0 + version: 9.32.0 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.32.0) + eslint-plugin-prettier: + specifier: ^5.5.3 + version: 5.5.3(eslint-config-prettier@10.1.8(eslint@9.32.0))(eslint@9.32.0)(prettier@3.6.2) + prettier: + specifier: 3.6.2 + version: 3.6.2 + +packages: + + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.0': + resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.1': + resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.32.0': + resolution: {integrity: sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.4': + resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@5.5.3: + resolution: {integrity: sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.32.0: + resolution: {integrity: sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + engines: {node: ^14.18.0 || >=16.0.0} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0)': + dependencies: + eslint: 9.32.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.0': {} + + '@eslint/core@0.15.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.32.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.4': + dependencies: + '@eslint/core': 0.15.1 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@pkgr/core@0.2.9': {} + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.32.0): + dependencies: + eslint: 9.32.0 + + eslint-plugin-prettier@5.5.3(eslint-config-prettier@10.1.8(eslint@9.32.0))(eslint@9.32.0)(prettier@3.6.2): + dependencies: + eslint: 9.32.0 + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + eslint-config-prettier: 10.1.8(eslint@9.32.0) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.32.0: + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.0 + '@eslint/core': 0.15.1 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.32.0 + '@eslint/plugin-kit': 0.3.4 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.6.2: {} + + punycode@2.3.1: {} + + resolve-from@4.0.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yocto-queue@0.1.0: {} From a3b6bd7442e022d2ee465471b339c3c87b92edb4 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:45:42 +0900 Subject: [PATCH 04/32] chore: add tsconfig --- tsconfig.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tsconfig.json diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0a0b2a2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2022", + "moduleResolution": "Node", + "outDir": "./dist", + "rootDir": "./src", + "strict": false, + "allowJs": true, + "checkJs": false, + "esModuleInterop": true + }, + "include": ["src/**/*"] +} From a27252ac692e60961d5acc2386e642ae82f368af Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:46:04 +0900 Subject: [PATCH 05/32] chor: add path on jsconfig --- jsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/jsconfig.json b/jsconfig.json index 8ecfcad..ec6c9e9 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -3,6 +3,7 @@ "baseUrl": "src", "paths": { "@controller/*": ["controller/*"], + "@core/*": ["core/*"], "@view/*": ["view/*"] } }, From a9f0797fa0d3629cc261187e80a81ab3153395e1 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:46:13 +0900 Subject: [PATCH 06/32] chore: add gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 06362ca..3d2fec6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ dev/train/trainData/mnist/mnistTraindata_large.js dev/train/trainData/mnist/mnist_train.csv +node_modules +dist +build +*.min.js \ No newline at end of file From 777e6b7fe830fcc1fcbfdf2fc4ed90a71aa63cd9 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:48:01 +0900 Subject: [PATCH 07/32] =?UTF-8?q?refactor:=20vite=EC=9D=98=20root=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9D=84=20=EC=A4=80=EC=88=98=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20index.html=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/index.html => index.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename public/index.html => index.html (86%) diff --git a/public/index.html b/index.html similarity index 86% rename from public/index.html rename to index.html index 7df7fa3..7f8501c 100644 --- a/public/index.html +++ b/index.html @@ -6,9 +6,8 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> Neural Network Visualization - - - + + From 75a022448bf52ad3638dea60a278ae6e36ceff36 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:51:26 +0900 Subject: [PATCH 08/32] =?UTF-8?q?migratoin:=20`QueryProcessController`,=20?= =?UTF-8?q?`throttle`,=20`NueralNetworkBase`=EB=A5=BC=20TS=EB=A1=9C=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev/train/Trainer.js | 2 +- src/controller/AppContoller.js | 30 ++++---- .../queryPipeline/QueryProcessController.js | 48 ------------- .../queryPipeline/QueryProcessController.ts | 68 +++++++++++++++++++ .../{throttle.js => throttle.ts} | 6 +- .../types/QueryProcessController.ts | 16 +++++ src/controller/types/weights.ts | 4 ++ src/core/NeuralNetworkBase.js | 35 ---------- src/core/NeuralNetworkBase.ts | 41 +++++++++++ src/core/types/NeuralNetworkBase.ts | 4 ++ 10 files changed, 154 insertions(+), 100 deletions(-) delete mode 100644 src/controller/queryPipeline/QueryProcessController.js create mode 100644 src/controller/queryPipeline/QueryProcessController.ts rename src/controller/queryPipeline/{throttle.js => throttle.ts} (51%) create mode 100644 src/controller/queryPipeline/types/QueryProcessController.ts create mode 100644 src/controller/types/weights.ts delete mode 100644 src/core/NeuralNetworkBase.js create mode 100644 src/core/NeuralNetworkBase.ts create mode 100644 src/core/types/NeuralNetworkBase.ts diff --git a/dev/train/Trainer.js b/dev/train/Trainer.js index 3594d8f..4307120 100644 --- a/dev/train/Trainer.js +++ b/dev/train/Trainer.js @@ -1,4 +1,4 @@ -import { NeuralNetworkBase } from "../../src/core/NeuralNetworkBase.js"; +import { NeuralNetworkBase } from "../../src/core/NeuralNetworkBase.ts"; // matrix operations import {matrixMultiply, transposeMatrix} from "../../src/core/ops/matrixOps.js"; diff --git a/src/controller/AppContoller.js b/src/controller/AppContoller.js index 22fd9c7..9d2f86b 100644 --- a/src/controller/AppContoller.js +++ b/src/controller/AppContoller.js @@ -1,15 +1,15 @@ -import WeightManager from "../core/WeightManager.js"; -import NeuralNetworkBase from "../core/NeuralNetworkBase.js"; -import QueryProcessController from "./queryPipeline/QueryProcessController.js"; -import UserInputCanvas from "../view/components/userQuery/UserInputCanvas.js"; -import PathTrackingCanvas from "../view/components/userQuery/PathTrackingCanvas.js"; -import AlignCanvas from "../view/components/userQuery/AlignCanvas.js"; -import ResizeCanvas from "../view/components/userQuery/ResizeCanvas.js"; -import { DataStore } from "./DataStore.js"; +import WeightManager from '../core/WeightManager.js'; +import NeuralNetworkBase from '../core/NeuralNetworkBase.ts'; +import QueryProcessController from './queryPipeline/QueryProcessController.ts'; +import UserInputCanvas from '../view/components/userQuery/UserInputCanvas.js'; +import PathTrackingCanvas from '../view/components/userQuery/PathTrackingCanvas.js'; +import AlignCanvas from '../view/components/userQuery/AlignCanvas.js'; +import ResizeCanvas from '../view/components/userQuery/ResizeCanvas.js'; +import { DataStore } from './DataStore.js'; -import eventBus from "./EventBus.js"; -import { DATA_EVENTS, HANDLER_EVENTS } from "./constants/events.js"; -import { NETWORK_CONFIG } from "./constants/networkConfig.js"; +import eventBus from './EventBus.js'; +import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.js'; +import { NETWORK_CONFIG } from './constants/networkConfig.ts'; class AppController { constructor({ dataStore }) { @@ -28,8 +28,10 @@ class AppController { $NN: $NN, }); eventBus.emit(HANDLER_EVENTS.APP_READY, this.dataStore); - eventBus.on(DATA_EVENTS.RESULT_CHANGED, (data) => {console.log("RESULT CHANGED", data)}); - }; + eventBus.on(DATA_EVENTS.RESULT_CHANGED, (data) => { + console.log('RESULT CHANGED', data); + }); + } } -export default AppController; \ No newline at end of file +export default AppController; diff --git a/src/controller/queryPipeline/QueryProcessController.js b/src/controller/queryPipeline/QueryProcessController.js deleted file mode 100644 index 0bc3697..0000000 --- a/src/controller/queryPipeline/QueryProcessController.js +++ /dev/null @@ -1,48 +0,0 @@ -import eventBus from "../EventBus.js"; -import { DATA_EVENTS, HANDLER_EVENTS, DRAWING_EVENTS } from "../constants/events.js"; -import DrawingEventHandler from "./DrawingEventHandler.js"; -import {pixelExtractor} from "../queryPipeline/pixelExtractor.js"; -import {throttle} from "../queryPipeline/throttle.js"; - - -class QueryProcessController { - constructor({ userInputCanvas, trackingCanvas, alignCanvas, resizeCanvas, $NN }) { - const drawingEventHandler = new DrawingEventHandler(); - this.userInputCanvas = userInputCanvas; - this.trackingCanvas = trackingCanvas; - this.alignCanvas = alignCanvas; - this.resizeCanvas = resizeCanvas; - - this.$NN = $NN; - this.drawingEvent(); - } - - drawingEvent() { - const throttleQuery = throttle((inputs) => { - const result = this.$NN.query(inputs); - if(result) { - eventBus.emit(DATA_EVENTS.RESULT_CHANGED, result); - // Array 중 가장 값이 큰 값의 index number가 추론 결과 - } - },100); - - eventBus.on(DRAWING_EVENTS.START_DRAW, ({x, y}) => { - this.userInputCanvas.startPath(x, y); - this.trackingCanvas.startPath(x, y); - }); - eventBus.on(DRAWING_EVENTS.DRAW, ({x, y}) => { - this.userInputCanvas.drawPath(x, y); - this.trackingCanvas.drawPath(x, y); - this.alignCanvas.updateCanvasScale(); - this.alignCanvas.centralize(this.trackingCanvas.canvas); - this.resizeCanvas.downScale(this.alignCanvas.canvas); - throttleQuery(pixelExtractor(this.resizeCanvas)); - }); - eventBus.on(DRAWING_EVENTS.END_DRAW, () => { - this.userInputCanvas.endPath(); - this.trackingCanvas.endPath(); - }); - } -} - -export default QueryProcessController; \ No newline at end of file diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts new file mode 100644 index 0000000..a1b0cd4 --- /dev/null +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -0,0 +1,68 @@ +import eventBus from '../EventBus.js'; +import { DATA_EVENTS, DRAWING_EVENTS } from '../constants/events.js'; +import DrawingEventHandler from './DrawingEventHandler.js'; +import { pixelExtractor } from './pixelExtractor.js'; +import { throttle } from './throttle'; + +import { IQueryProcessControllerProps } from './types/QueryProcessController.js'; +import { + ICanvasBase, + IUserInputCanvas, + IPathTrackingCanvas, + IAlignCanvas, + IResizeCanvas, +} from '../../view/components/userQuery/types/canvas'; +import { INeuralNetworkBase } from '../../core/types/NeuralNetworkBase'; + +class QueryProcessController { + private readonly userInputCanvas: ICanvasBase & IUserInputCanvas; + private readonly trackingCanvas: ICanvasBase & IPathTrackingCanvas; + private readonly alignCanvas: ICanvasBase & IAlignCanvas; + private readonly resizeCanvas: ICanvasBase & IResizeCanvas; + private readonly $NN: INeuralNetworkBase; + + constructor({ + userInputCanvas, + trackingCanvas, + alignCanvas, + resizeCanvas, + $NN, + }: IQueryProcessControllerProps) { + new DrawingEventHandler(); + this.userInputCanvas = userInputCanvas; + this.trackingCanvas = trackingCanvas; + this.alignCanvas = alignCanvas; + this.resizeCanvas = resizeCanvas; + + this.$NN = $NN; + this.drawingEvent(); + } + + drawingEvent(): void { + const throttleQuery = throttle((inputs) => { + const result: number[] = this.$NN.query(inputs); + if (result) { + eventBus.emit(DATA_EVENTS.RESULT_CHANGED, result); + } + }, 100); + + eventBus.on(DRAWING_EVENTS.START_DRAW, ({ x, y }) => { + this.userInputCanvas.startPath(x, y); + this.trackingCanvas.startPath(x, y); + }); + eventBus.on(DRAWING_EVENTS.DRAW, ({ x, y }) => { + this.userInputCanvas.drawPath(x, y); + this.trackingCanvas.drawPath(x, y); + this.alignCanvas.updateCanvasScale(); + this.alignCanvas.centralize(this.trackingCanvas.canvas); + this.resizeCanvas.downScale(this.alignCanvas.canvas); + throttleQuery(pixelExtractor(this.resizeCanvas)); + }); + eventBus.on(DRAWING_EVENTS.END_DRAW, () => { + this.userInputCanvas.endPath(); + this.trackingCanvas.endPath(); + }); + } +} + +export default QueryProcessController; diff --git a/src/controller/queryPipeline/throttle.js b/src/controller/queryPipeline/throttle.ts similarity index 51% rename from src/controller/queryPipeline/throttle.js rename to src/controller/queryPipeline/throttle.ts index 8d25156..bc966df 100644 --- a/src/controller/queryPipeline/throttle.js +++ b/src/controller/queryPipeline/throttle.ts @@ -1,6 +1,8 @@ -export const throttle = (fn, delay) => { +export const throttle = any> ( + fn: T, delay: number +): (...args: Parameters) => ReturnType => { let pause = false; - return (...args) => { + return (...args: Parameters): ReturnType => { if(!pause) { const result = fn(...args); pause = true; diff --git a/src/controller/queryPipeline/types/QueryProcessController.ts b/src/controller/queryPipeline/types/QueryProcessController.ts new file mode 100644 index 0000000..631d61b --- /dev/null +++ b/src/controller/queryPipeline/types/QueryProcessController.ts @@ -0,0 +1,16 @@ +import { + ICanvasBase, + IUserInputCanvas, + IPathTrackingCanvas, + IAlignCanvas, + IResizeCanvas, +} from '../../../view/components/userQuery/types/canvas'; +import { INeuralNetworkBase } from '../../../core/types/NeuralNetworkBase'; + +export interface IQueryProcessControllerProps { + userInputCanvas: ICanvasBase & IUserInputCanvas; + trackingCanvas: ICanvasBase & IPathTrackingCanvas; + alignCanvas: ICanvasBase & IAlignCanvas; + resizeCanvas: ICanvasBase & IResizeCanvas; + $NN: INeuralNetworkBase; +} diff --git a/src/controller/types/weights.ts b/src/controller/types/weights.ts new file mode 100644 index 0000000..a149746 --- /dev/null +++ b/src/controller/types/weights.ts @@ -0,0 +1,4 @@ +export interface weights { + W_inputToHidden: number[][]; + W_hiddenToOutput: number[][]; +} diff --git a/src/core/NeuralNetworkBase.js b/src/core/NeuralNetworkBase.js deleted file mode 100644 index adb4bfa..0000000 --- a/src/core/NeuralNetworkBase.js +++ /dev/null @@ -1,35 +0,0 @@ -import activationFunction from "./ops/activationOps.js"; -import { matrixMultiply } from "./ops/matrixOps.js"; -import eventBus from "../controller/EventBus.js"; -import { DATA_EVENTS } from "../controller/constants/events.js"; -import { NETWORK_CONFIG } from "../controller/constants/networkConfig.js"; - -class NeuralNetworkBase { - constructor(weights) { - this.inputNodes = NETWORK_CONFIG.inputNodes; - this.hiddenNodes = NETWORK_CONFIG.hiddenNodes; - this.outputNodes = NETWORK_CONFIG.outputNodes; - this.learningRate = NETWORK_CONFIG.learningRate; - - this.W_inputToHidden = weights?.W_inputToHidden ?? null; - this.W_hiddenToOutput = weights?.W_hiddenToOutput ?? null; - } - - // CNN operations - feedForward(inputs) { - console.log("inputs", inputs); - const hiddenInputs = matrixMultiply(this.W_inputToHidden, inputs.map(v => [v])); //신경망 출력 결과를 Nx1 형태의 행렬곱으로 변환. - const hiddenOutputs = activationFunction(hiddenInputs); - const finalInputs = matrixMultiply(this.W_hiddenToOutput, hiddenOutputs); - const finalOutputs = activationFunction(finalInputs); - return { hiddenInputs, hiddenOutputs, finalInputs, finalOutputs }; - } - - query(inputs){ - const { hiddenInputs, hiddenOutputs , finalOutputs } = this.feedForward(inputs); - eventBus.emit(DATA_EVENTS.NODE_UPDATE, {hiddenInputs, hiddenOutputs, finalOutputs}); - return finalOutputs; - } -} - -export default NeuralNetworkBase; \ No newline at end of file diff --git a/src/core/NeuralNetworkBase.ts b/src/core/NeuralNetworkBase.ts new file mode 100644 index 0000000..152ee46 --- /dev/null +++ b/src/core/NeuralNetworkBase.ts @@ -0,0 +1,41 @@ +import activationFunction from './ops/activationOps.js'; +import { matrixMultiply } from './ops/matrixOps.js'; +import eventBus from '../controller/EventBus.js'; +import { DATA_EVENTS } from '../controller/constants/events.js'; + +import { weights } from '../controller/types/weights'; + +class NeuralNetworkBase { + private readonly W_inputToHidden: number[][] | null; + private readonly W_hiddenToOutput: number[][] | null; + + constructor(weights: Partial) { + // weight를 optional하게 처리하기 위해 Partial 사용 + this.W_inputToHidden = weights?.W_inputToHidden ?? null; + this.W_hiddenToOutput = weights?.W_hiddenToOutput ?? null; + } + + // CNN operations + feedForward(inputs: number[]): { + hiddenInputs: number[]; + hiddenOutputs: number[]; + finalOutputs: number[]; + } { + const hiddenInputs: number[] = matrixMultiply( + this.W_inputToHidden, + inputs.map((v) => [v]), + ); //신경망 출력 결과를 Nx1 형태의 행렬곱으로 변환. + const hiddenOutputs: number[] = activationFunction(hiddenInputs); + const finalInputs: number[] = matrixMultiply(this.W_hiddenToOutput, hiddenOutputs); + const finalOutputs: number[] = activationFunction(finalInputs); + return { hiddenInputs, hiddenOutputs, finalOutputs }; + } + + query(inputs: number[]): number[] { + const { hiddenInputs, hiddenOutputs, finalOutputs } = this.feedForward(inputs); + eventBus.emit(DATA_EVENTS.NODE_UPDATE, { hiddenInputs, hiddenOutputs, finalOutputs }); + return finalOutputs; + } +} + +export default NeuralNetworkBase; diff --git a/src/core/types/NeuralNetworkBase.ts b/src/core/types/NeuralNetworkBase.ts new file mode 100644 index 0000000..7035612 --- /dev/null +++ b/src/core/types/NeuralNetworkBase.ts @@ -0,0 +1,4 @@ +export interface INeuralNetworkBase { + feedForward(inputs: number[]): { hiddenInputs: number[]; hiddenOutputs: number[] }; + query(inputs: number[]): number[]; +} From 24f10ead8ba3766e1d70dcff5f99e8095e4721eb Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:53:53 +0900 Subject: [PATCH 09/32] =?UTF-8?q?chore:=20=EC=83=81=EC=88=98=20=EB=B0=8F?= =?UTF-8?q?=20=EC=BA=94=EB=B2=84=EC=8A=A4=EC=9D=98=20type=20=EC=A7=80?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/constants/networkConfig.js | 6 ----- src/controller/constants/networkConfig.ts | 8 +++++++ src/controller/types/constant.ts | 6 +++++ src/view/components/userQuery/types/canvas.ts | 23 +++++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) delete mode 100644 src/controller/constants/networkConfig.js create mode 100644 src/controller/constants/networkConfig.ts create mode 100644 src/controller/types/constant.ts create mode 100644 src/view/components/userQuery/types/canvas.ts diff --git a/src/controller/constants/networkConfig.js b/src/controller/constants/networkConfig.js deleted file mode 100644 index 8d6a6c8..0000000 --- a/src/controller/constants/networkConfig.js +++ /dev/null @@ -1,6 +0,0 @@ -export const NETWORK_CONFIG = { - inputNodes: 784, - hiddenNodes: 200, - outputNodes: 10, - learningRate: 0.15, -} \ No newline at end of file diff --git a/src/controller/constants/networkConfig.ts b/src/controller/constants/networkConfig.ts new file mode 100644 index 0000000..ed551e8 --- /dev/null +++ b/src/controller/constants/networkConfig.ts @@ -0,0 +1,8 @@ +import { CONSTANT } from '../types/constant'; + +export const NETWORK_CONFIG: CONSTANT = { + inputNodes: 784, + hiddenNodes: 200, + outputNodes: 10, + learningRate: 0.15, +}; diff --git a/src/controller/types/constant.ts b/src/controller/types/constant.ts new file mode 100644 index 0000000..f4c95e9 --- /dev/null +++ b/src/controller/types/constant.ts @@ -0,0 +1,6 @@ +export interface CONSTANT { + inputNodes: number; + hiddenNodes: number; + outputNodes: number; + learningRate: number; +} diff --git a/src/view/components/userQuery/types/canvas.ts b/src/view/components/userQuery/types/canvas.ts new file mode 100644 index 0000000..446c51c --- /dev/null +++ b/src/view/components/userQuery/types/canvas.ts @@ -0,0 +1,23 @@ +export interface ICanvasBase { + setupCanvas(): void; + clear(): void; + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; +} + +export interface IUserInputCanvas extends IPathTrackingCanvas { + drawGridDots(): void; +} +export interface IPathTrackingCanvas { + startPath(x: number, y: number): void; + drawPath(x: number, y: number): void; + endPath(): void; +} +export interface IAlignCanvas { + updateCanvasScale(): void; + centralize(path: HTMLCanvasElement): void; +} + +export interface IResizeCanvas { + downScale(path: HTMLCanvasElement): void; +} \ No newline at end of file From cbdde7d82d31134816e0a1a0ed3e32428e4dc57a Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:54:26 +0900 Subject: [PATCH 10/32] =?UTF-8?q?rename:=20vite=EC=9D=98=20entry=20?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/{index.js => main.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{index.js => main.ts} (100%) diff --git a/src/index.js b/src/main.ts similarity index 100% rename from src/index.js rename to src/main.ts From c1bfc4f17c40949dc8c7beda0d8b479f59190858 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 27 Jul 2025 15:58:58 +0900 Subject: [PATCH 11/32] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=20=ED=8F=AC?= =?UTF-8?q?=EB=A7=B7=ED=8C=85=20=EB=B0=8F=20interface=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=9C=20clear=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80(canvas)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 faet/query에 추가해야할 커밋이었으나, 빌드 및 패키지 매니저의 추가로 환경 설정이 불편하여 해당 브랜치에 그대로 추가. (브랜치 스위칭하는데 더 큰 비용이 들 것 같음) --- src/view/components/CanvasComponentBase.js | 3 +-- src/view/components/userQuery/AlignCanvas.js | 5 +++++ src/view/components/userQuery/ResizeCanvas.js | 4 ++++ src/view/components/userQuery/UserInputCanvas.js | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/view/components/CanvasComponentBase.js b/src/view/components/CanvasComponentBase.js index bf544ff..2af8a95 100644 --- a/src/view/components/CanvasComponentBase.js +++ b/src/view/components/CanvasComponentBase.js @@ -30,7 +30,6 @@ class CanvasComponentBase { clear() { this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); } - } -export default CanvasComponentBase; \ No newline at end of file +export default CanvasComponentBase; diff --git a/src/view/components/userQuery/AlignCanvas.js b/src/view/components/userQuery/AlignCanvas.js index c5ae35e..743ecdc 100644 --- a/src/view/components/userQuery/AlignCanvas.js +++ b/src/view/components/userQuery/AlignCanvas.js @@ -38,6 +38,11 @@ class AlignCanvas { BoundingBox.originalObject.width, BoundingBox.originalObject.height ); } + + clear() { + this.canvas.width = this.canvas.height = 1; + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + } } export default AlignCanvas; \ No newline at end of file diff --git a/src/view/components/userQuery/ResizeCanvas.js b/src/view/components/userQuery/ResizeCanvas.js index c424a57..cd0a657 100644 --- a/src/view/components/userQuery/ResizeCanvas.js +++ b/src/view/components/userQuery/ResizeCanvas.js @@ -10,6 +10,10 @@ class ResizeCanvas { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.drawImage(path, 0, 0, path.width, path.height, 0, 0, this.canvas.width, this.canvas.height); } + + clear() { + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + } } export default ResizeCanvas; \ No newline at end of file diff --git a/src/view/components/userQuery/UserInputCanvas.js b/src/view/components/userQuery/UserInputCanvas.js index 6693753..b329245 100644 --- a/src/view/components/userQuery/UserInputCanvas.js +++ b/src/view/components/userQuery/UserInputCanvas.js @@ -15,6 +15,7 @@ class UserInputCanvas { clear = () => { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.drawGridDots(); } setupCanvas() { From ccab05025cee0bd735c28d3edd64a49bc15c800a Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 22:16:40 +0900 Subject: [PATCH 12/32] refactor: migration to typescript(WIP) --- dev/train/Trainer.js | 43 +++++++++++----- src/controller/AppContoller.js | 13 ++--- src/controller/DataStore.ts | 50 +++++++++++++++++++ src/controller/EventBus.js | 20 -------- src/controller/EventBus.ts | 33 ++++++++++++ .../{canvasConfig.js => canvasConfig.ts} | 4 +- .../constants/{events.js => events.ts} | 18 ++++--- src/controller/constants/networkConfig.ts | 4 +- src/controller/constants/types/events.ts | 0 .../types/networkConfig.ts} | 2 +- src/controller/dataStore.js | 42 ---------------- .../queryPipeline/DrawingEventHandler.js | 39 ++++++++------- .../queryPipeline/QueryProcessController.ts | 25 ++++++---- .../queryPipeline/pixelExtractor.js | 28 ----------- .../queryPipeline/pixelExtractor.ts | 42 ++++++++++++++++ .../types/DrawingEventHandler.ts | 12 +++++ .../types/QueryProcessController.ts | 2 + src/controller/types/DataStore.ts | 16 ++++++ src/controller/types/eventBus.ts | 31 ++++++++++++ src/core/NeuralNetworkBase.ts | 17 ++++--- src/core/WeightManager.js | 33 ------------ src/core/WeightManager.ts | 43 ++++++++++++++++ src/core/ops/matrixOps.js | 17 ------- src/core/ops/matrixOps.ts | 25 ++++++++++ src/core/ops/types/OpsType.ts | 1 + src/core/utils/createRandomWeights.js | 7 --- src/core/utils/createRandomWeights.ts | 7 +++ src/core/utils/loadPretrainedWeights.js | 5 -- src/core/utils/loadPretrainedWeights.ts | 7 +++ src/main.ts | 5 +- src/view/DataPresnter.ts | 0 .../components/canvasUtils/BoundingBox.js | 38 -------------- .../components/canvasUtils/BoundingBox.ts | 44 ++++++++++++++++ src/view/components/canvasUtils/types.ts | 19 +++++++ src/view/components/userQuery/AlignCanvas.js | 33 ++++++------ .../userQuery/PathTrackingCanvas.js | 8 +-- .../components/userQuery/UserInputCanvas.js | 8 +-- 37 files changed, 458 insertions(+), 283 deletions(-) create mode 100644 src/controller/DataStore.ts delete mode 100644 src/controller/EventBus.js create mode 100644 src/controller/EventBus.ts rename src/controller/constants/{canvasConfig.js => canvasConfig.ts} (53%) rename src/controller/constants/{events.js => events.ts} (54%) create mode 100644 src/controller/constants/types/events.ts rename src/controller/{types/constant.ts => constants/types/networkConfig.ts} (75%) delete mode 100644 src/controller/dataStore.js delete mode 100644 src/controller/queryPipeline/pixelExtractor.js create mode 100644 src/controller/queryPipeline/pixelExtractor.ts create mode 100644 src/controller/queryPipeline/types/DrawingEventHandler.ts create mode 100644 src/controller/types/DataStore.ts create mode 100644 src/controller/types/eventBus.ts delete mode 100644 src/core/WeightManager.js create mode 100644 src/core/WeightManager.ts delete mode 100644 src/core/ops/matrixOps.js create mode 100644 src/core/ops/matrixOps.ts create mode 100644 src/core/ops/types/OpsType.ts delete mode 100644 src/core/utils/createRandomWeights.js create mode 100644 src/core/utils/createRandomWeights.ts delete mode 100644 src/core/utils/loadPretrainedWeights.js create mode 100644 src/core/utils/loadPretrainedWeights.ts create mode 100644 src/view/DataPresnter.ts delete mode 100644 src/view/components/canvasUtils/BoundingBox.js create mode 100644 src/view/components/canvasUtils/BoundingBox.ts create mode 100644 src/view/components/canvasUtils/types.ts diff --git a/dev/train/Trainer.js b/dev/train/Trainer.js index 4307120..0434c50 100644 --- a/dev/train/Trainer.js +++ b/dev/train/Trainer.js @@ -1,27 +1,44 @@ -import { NeuralNetworkBase } from "../../src/core/NeuralNetworkBase.ts"; +import { NeuralNetworkBase } from '../../src/core/NeuralNetworkBase.ts'; // matrix operations -import {matrixMultiply, transposeMatrix} from "../../src/core/ops/matrixOps.js"; +import { matrixMultiply, transposeMatrix } from '../../src/core/ops/matrixOps.ts'; export class Trainer extends NeuralNetworkBase { - train(inputs, targets){ + train(inputs, targets) { // CNN operations const { finalOutputs, hiddenOutputs } = this.feedForward(inputs); // calculate errors - const output_errors = targets.map((v, idx) => v - finalOutputs[idx]).map(v => [v]); // 출력 계층의 오차를 목표값 - 출력값으로 지정 + const output_errors = targets.map((v, idx) => v - finalOutputs[idx]).map((v) => [v]); // 출력 계층의 오차를 목표값 - 출력값으로 지정 const hidden_errors = matrixMultiply(transposeMatrix(this.W_hiddenToOutput), output_errors); // 은닉 계층의 오차를 은닉-> 출력 계층의 가중치값과(W_hiddenToOutput.T) 출력 계층의 오차들을 재조합하여 계산 // activation function derivative - const activationDerivative_HtO = finalOutputs.map(v => 1.0 - v).map((v, idx) => v * finalOutputs[idx]); // hidden to output derivative - const outputGradient = activationDerivative_HtO.map((v, idx) => v * output_errors[idx]).map(v => [v]); - const W_HtO_Update = matrixMultiply(outputGradient, transposeMatrix(hiddenOutputs)).map(array => array.map(v => v * this.learningRate)); // 오차값을 이용해 은닉 계층과 출력 계층간의 가중치 업데이트 + const activationDerivative_HtO = finalOutputs + .map((v) => 1.0 - v) + .map((v, idx) => v * finalOutputs[idx]); // hidden to output derivative + const outputGradient = activationDerivative_HtO + .map((v, idx) => v * output_errors[idx]) + .map((v) => [v]); + const W_HtO_Update = matrixMultiply(outputGradient, transposeMatrix(hiddenOutputs)).map( + (array) => array.map((v) => v * this.learningRate), + ); // 오차값을 이용해 은닉 계층과 출력 계층간의 가중치 업데이트 - const activationDerivative_ItH = hiddenOutputs.map(v => 1.0 - v).map((v, idx) => v * hiddenOutputs[idx]); - const hiddenGradient = activationDerivative_ItH.map((v, idx) => v * hidden_errors[idx]).map(v => [v]); - const W_ItH_update = matrixMultiply(hiddenGradient, transposeMatrix(inputs.map(v => [v]))).map(array => array.map(v => v * this.learningRate)); + const activationDerivative_ItH = hiddenOutputs + .map((v) => 1.0 - v) + .map((v, idx) => v * hiddenOutputs[idx]); + const hiddenGradient = activationDerivative_ItH + .map((v, idx) => v * hidden_errors[idx]) + .map((v) => [v]); + const W_ItH_update = matrixMultiply( + hiddenGradient, + transposeMatrix(inputs.map((v) => [v])), + ).map((array) => array.map((v) => v * this.learningRate)); // update weights - this.W_hiddenToOutput = this.W_hiddenToOutput.map((row, i)=> row.map((v, j) => v + W_HtO_Update[i][j])); - this.W_inputToHidden = this.W_inputToHidden.map((row, i)=> row.map((v, j) => v + W_ItH_update[i][j])); + this.W_hiddenToOutput = this.W_hiddenToOutput.map((row, i) => + row.map((v, j) => v + W_HtO_Update[i][j]), + ); + this.W_inputToHidden = this.W_inputToHidden.map((row, i) => + row.map((v, j) => v + W_ItH_update[i][j]), + ); } -} \ No newline at end of file +} diff --git a/src/controller/AppContoller.js b/src/controller/AppContoller.js index 9d2f86b..eca5910 100644 --- a/src/controller/AppContoller.js +++ b/src/controller/AppContoller.js @@ -1,21 +1,17 @@ -import WeightManager from '../core/WeightManager.js'; +import WeightManager from '../core/WeightManager.ts'; import NeuralNetworkBase from '../core/NeuralNetworkBase.ts'; import QueryProcessController from './queryPipeline/QueryProcessController.ts'; import UserInputCanvas from '../view/components/userQuery/UserInputCanvas.js'; import PathTrackingCanvas from '../view/components/userQuery/PathTrackingCanvas.js'; import AlignCanvas from '../view/components/userQuery/AlignCanvas.js'; import ResizeCanvas from '../view/components/userQuery/ResizeCanvas.js'; -import { DataStore } from './DataStore.js'; +import DataStore from './DataStore.ts'; -import eventBus from './EventBus.js'; -import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.js'; +import eventBus from './EventBus.ts'; +import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.ts'; import { NETWORK_CONFIG } from './constants/networkConfig.ts'; class AppController { - constructor({ dataStore }) { - this.dataStore = dataStore; - } - async initialize() { const $WM = new WeightManager(NETWORK_CONFIG); const $NN = new NeuralNetworkBase(await $WM.getWeights()); @@ -26,6 +22,7 @@ class AppController { alignCanvas: new AlignCanvas(), resizeCanvas: new ResizeCanvas(), $NN: $NN, + $DS: $DS, }); eventBus.emit(HANDLER_EVENTS.APP_READY, this.dataStore); eventBus.on(DATA_EVENTS.RESULT_CHANGED, (data) => { diff --git a/src/controller/DataStore.ts b/src/controller/DataStore.ts new file mode 100644 index 0000000..eecdd50 --- /dev/null +++ b/src/controller/DataStore.ts @@ -0,0 +1,50 @@ +import eventBus from './EventBus.js'; +import { DATA_EVENTS } from './constants/events.js'; + +import { nodeState } from './types/DataStore'; + +class DataStore { + private queryInfo: number[] | null = null; + private nodeState: nodeState | null = null; + private queryResult: number[] | null = null; + + constructor() { + this.queryInfo = null; + this.nodeState = null; + this.queryResult = null; + } + + setQueryInfo(queryInfo: number[]): void { + if (queryInfo === null) throw new Error('No query info found'); + this.queryInfo = queryInfo; + eventBus.emit(DATA_EVENTS.QUERY_CHANGED, this.queryInfo); + } + getQueryInfo(): number[] { + return this.queryInfo; + } + + setNodeState(nodeState: nodeState): void { + if (nodeState === null) throw new Error('No node state found'); + this.nodeState = nodeState; + } + getNodeState(): nodeState { + return this.nodeState; + } + + setQueryResult(queryResult: number[]): void { + if (queryResult === null) throw new Error('No query result found'); + this.queryResult = queryResult; + eventBus.emit(DATA_EVENTS.RESULT_CHANGED, queryResult); + } + getQueryResult() { + return this.queryResult; + } + + reset() { + this.queryInfo = null; + this.nodeState = null; + this.queryResult = null; + } +} + +export default DataStore; diff --git a/src/controller/EventBus.js b/src/controller/EventBus.js deleted file mode 100644 index e8d182a..0000000 --- a/src/controller/EventBus.js +++ /dev/null @@ -1,20 +0,0 @@ -const EventBus = { - _events: {}, - - on(eventName, subscriber) { - if(!this._events[eventName]) this._events[eventName] = []; - this._events[eventName].push(subscriber); - }, - - off(eventName, subscriber) { - if(!this._events[eventName]) return; - this._events[eventName] = this._events[eventName].filter(fn => fn !== subscriber); - }, - - emit(eventName, payload) { - if(!this._events[eventName]) return; - this._events[eventName].forEach(fn => fn(payload)); - } -} - -export default EventBus; \ No newline at end of file diff --git a/src/controller/EventBus.ts b/src/controller/EventBus.ts new file mode 100644 index 0000000..ffe271f --- /dev/null +++ b/src/controller/EventBus.ts @@ -0,0 +1,33 @@ +import { IEventBus } from './types/eventBus'; +import { eventPayloads } from './types/eventBus'; + +const EventBus: IEventBus = { + events: {}, + + on( + eventName: K, + subscriber: (payload: eventPayloads[K]) => any, + ): void { + if (!this.events[eventName]) this.events[eventName] = []; + this.events[eventName].push(subscriber); + }, + + off( + eventName: K, + subscriber: (payload: eventPayloads[K]) => any, + ): void { + if (!this.events[eventName]) return; + this.events[eventName] = this.events[eventName].filter( + (fn: (payload: eventPayloads[K]) => void): boolean => fn !== subscriber, + ); + }, + + emit(eventName: K, payload: eventPayloads[K]): void { + if (!this.events[eventName]) return; + this.events[eventName].forEach((fn: (payload: eventPayloads[K]) => any): any => + fn(payload), + ); + }, +}; + +export default EventBus; diff --git a/src/controller/constants/canvasConfig.js b/src/controller/constants/canvasConfig.ts similarity index 53% rename from src/controller/constants/canvasConfig.js rename to src/controller/constants/canvasConfig.ts index 23eef1c..dbca9a0 100644 --- a/src/controller/constants/canvasConfig.js +++ b/src/controller/constants/canvasConfig.ts @@ -2,4 +2,6 @@ export const CANVAS_CONFIG = Object.freeze({ lineWidth: 20, lineCap: 'round', lineJoin: 'round', -}); \ No newline at end of file +} as const); + +export type CanvasConfig = (typeof CANVAS_CONFIG)[keyof typeof CANVAS_CONFIG]; diff --git a/src/controller/constants/events.js b/src/controller/constants/events.ts similarity index 54% rename from src/controller/constants/events.js rename to src/controller/constants/events.ts index edebe68..7c6ad31 100644 --- a/src/controller/constants/events.js +++ b/src/controller/constants/events.ts @@ -4,18 +4,22 @@ export const DATA_EVENTS = Object.freeze({ NODE_UPDATE: 'node:update', NODE_CHANGED: 'node:changed', RESULT_UPDATE: 'result:update', - RESULT_CHANGED: 'result:changed' -}); + RESULT_CHANGED: 'result:changed', +} as const); export const HANDLER_EVENTS = Object.freeze({ APP_READY: 'app:ready', NN_INITIALIZE: 'nn:initialize', ICH_INITIALIZE: 'ich:initialize', -}) +} as const); export const DRAWING_EVENTS = Object.freeze({ - START_DRAW: 'draw: start', - DRAW: 'draw: drawing', - END_DRAW: 'draw: end', + START_DRAW: 'draw:start', + DRAW: 'draw:drawing', + END_DRAW: 'draw:end', BOUNDINGBOX_UPDATE: 'boundingbox:update', -}) \ No newline at end of file +} as const); + +export type DataEvent = (typeof DATA_EVENTS)[keyof typeof DATA_EVENTS]; +export type HandlerEvent = (typeof DATA_EVENTS)[keyof typeof DATA_EVENTS]; +export type DrawingEvent = (typeof DATA_EVENTS)[keyof typeof DATA_EVENTS]; diff --git a/src/controller/constants/networkConfig.ts b/src/controller/constants/networkConfig.ts index ed551e8..fe022fd 100644 --- a/src/controller/constants/networkConfig.ts +++ b/src/controller/constants/networkConfig.ts @@ -1,6 +1,6 @@ -import { CONSTANT } from '../types/constant'; +import { networkConfig } from './types/networkConfig'; -export const NETWORK_CONFIG: CONSTANT = { +export const NETWORK_CONFIG: networkConfig = { inputNodes: 784, hiddenNodes: 200, outputNodes: 10, diff --git a/src/controller/constants/types/events.ts b/src/controller/constants/types/events.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/controller/types/constant.ts b/src/controller/constants/types/networkConfig.ts similarity index 75% rename from src/controller/types/constant.ts rename to src/controller/constants/types/networkConfig.ts index f4c95e9..f099979 100644 --- a/src/controller/types/constant.ts +++ b/src/controller/constants/types/networkConfig.ts @@ -1,4 +1,4 @@ -export interface CONSTANT { +export interface networkConfig { inputNodes: number; hiddenNodes: number; outputNodes: number; diff --git a/src/controller/dataStore.js b/src/controller/dataStore.js deleted file mode 100644 index 434e342..0000000 --- a/src/controller/dataStore.js +++ /dev/null @@ -1,42 +0,0 @@ -import eventBus from "./EventBus.js"; -import { DATA_EVENTS } from "./constants/events.js" - -export class DataStore { - constructor() { - this._queryInfo = null; - this._nodeState = {}; - this._queryResult = null; - - eventBus.on(DATA_EVENTS.NODE_UPDATE, this.setQueryInfo.bind(this)); - eventBus.on(DATA_EVENTS.RESULT_UPDATE, this.setQueryResult.bind(this)); - } - - setQueryInfo(queryInfo) { - this._queryInfo = queryInfo; - eventBus.emit(DATA_EVENTS.QUERY_CHANGED, queryInfo) - } - getQueryInfo() { - return this._queryInfo; - } - - setNodeState(nodeState) { - this._nodeState = nodeState; - } - getNodeState() { - return this._nodeState; - } - - setQueryResult(queryResult) { - this._queryResult = queryResult; - eventBus.emit(DATA_EVENTS.QUERY_CHANGED, queryResult); - } - getQueryResult() { - return this._queryResult; - } - - reset() { - this._queryInfo = null; - this._nodeState = {}; - this._queryResult = null; - } -} \ No newline at end of file diff --git a/src/controller/queryPipeline/DrawingEventHandler.js b/src/controller/queryPipeline/DrawingEventHandler.js index 05671c2..8f0facf 100644 --- a/src/controller/queryPipeline/DrawingEventHandler.js +++ b/src/controller/queryPipeline/DrawingEventHandler.js @@ -1,6 +1,6 @@ -import BoundingBox from "../../view/components/canvasUtils/BoundingBox.js"; -import eventBus from "../EventBus.js"; -import { DRAWING_EVENTS } from "../constants/events.js"; +import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; +import eventBus from '../EventBus.ts'; +import { DRAWING_EVENTS } from '../constants/events.ts'; class DrawingEventHandler { constructor() { @@ -11,20 +11,20 @@ class DrawingEventHandler { registerEvents() { const startDraw = (x, y) => { this.isDrawing = true; - eventBus.emit(DRAWING_EVENTS.START_DRAW, {x, y}); - } + eventBus.emit(DRAWING_EVENTS.START_DRAW, { x, y }); + }; const draw = (x, y) => { if (!this.isDrawing) return; BoundingBox.update(x, y); - eventBus.emit(DRAWING_EVENTS.DRAW, {x, y}) - } + eventBus.emit(DRAWING_EVENTS.DRAW, { x, y }); + }; const endDraw = () => { this.isDrawing = false; BoundingBox.log(); eventBus.emit(DRAWING_EVENTS.END_DRAW); - } + }; const getTouchPosition = (e) => { e.preventDefault(); @@ -33,31 +33,32 @@ class DrawingEventHandler { return { x: touch.clientX - rect.left, y: touch.clientY - rect.top, - } - } + }; + }; - this.inputCanvas.addEventListener("mousedown", (e) => { + this.inputCanvas.addEventListener('mousedown', (e) => { startDraw(e.offsetX, e.offsetY); }); - this.inputCanvas.addEventListener("touchstart", (e) => { - let {x, y} = getTouchPosition(e); + this.inputCanvas.addEventListener('touchstart', (e) => { + let { x, y } = getTouchPosition(e); startDraw(x, y); }); - this.inputCanvas.addEventListener("mousemove", (e) => { + this.inputCanvas.addEventListener('mousemove', (e) => { draw(e.offsetX, e.offsetY); }); - this.inputCanvas.addEventListener("touchmove", (e) => { - let {x, y} = getTouchPosition(e); + this.inputCanvas.addEventListener('touchmove', (e) => { + let { x, y } = getTouchPosition(e); draw(x, y); }); - this.inputCanvas.addEventListener("mouseup", endDraw); - this.inputCanvas.addEventListener("mouseout", endDraw); - this.inputCanvas.addEventListener("touchend", (e) => { + this.inputCanvas.addEventListener('mouseup', endDraw); + this.inputCanvas.addEventListener('mouseout', endDraw); + this.inputCanvas.addEventListener('touchend', (e) => { e.preventDefault(); endDraw(); }); + // TODO: Touch/Click 이벤트 코드 리팩토링(중복 없애기) } } diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts index a1b0cd4..6b3c956 100644 --- a/src/controller/queryPipeline/QueryProcessController.ts +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -3,7 +3,6 @@ import { DATA_EVENTS, DRAWING_EVENTS } from '../constants/events.js'; import DrawingEventHandler from './DrawingEventHandler.js'; import { pixelExtractor } from './pixelExtractor.js'; import { throttle } from './throttle'; - import { IQueryProcessControllerProps } from './types/QueryProcessController.js'; import { ICanvasBase, @@ -13,6 +12,7 @@ import { IResizeCanvas, } from '../../view/components/userQuery/types/canvas'; import { INeuralNetworkBase } from '../../core/types/NeuralNetworkBase'; +import { IDataStore } from '../types/DataStore'; class QueryProcessController { private readonly userInputCanvas: ICanvasBase & IUserInputCanvas; @@ -20,6 +20,7 @@ class QueryProcessController { private readonly alignCanvas: ICanvasBase & IAlignCanvas; private readonly resizeCanvas: ICanvasBase & IResizeCanvas; private readonly $NN: INeuralNetworkBase; + private readonly $DS: IDataStore; constructor({ userInputCanvas, @@ -27,6 +28,7 @@ class QueryProcessController { alignCanvas, resizeCanvas, $NN, + $DS, }: IQueryProcessControllerProps) { new DrawingEventHandler(); this.userInputCanvas = userInputCanvas; @@ -35,17 +37,12 @@ class QueryProcessController { this.resizeCanvas = resizeCanvas; this.$NN = $NN; + this.$DS = $DS; this.drawingEvent(); + this.query(); } drawingEvent(): void { - const throttleQuery = throttle((inputs) => { - const result: number[] = this.$NN.query(inputs); - if (result) { - eventBus.emit(DATA_EVENTS.RESULT_CHANGED, result); - } - }, 100); - eventBus.on(DRAWING_EVENTS.START_DRAW, ({ x, y }) => { this.userInputCanvas.startPath(x, y); this.trackingCanvas.startPath(x, y); @@ -56,13 +53,23 @@ class QueryProcessController { this.alignCanvas.updateCanvasScale(); this.alignCanvas.centralize(this.trackingCanvas.canvas); this.resizeCanvas.downScale(this.alignCanvas.canvas); - throttleQuery(pixelExtractor(this.resizeCanvas)); + this.$DS.setQueryInfo(pixelExtractor(this.resizeCanvas)); }); eventBus.on(DRAWING_EVENTS.END_DRAW, () => { this.userInputCanvas.endPath(); this.trackingCanvas.endPath(); }); } + + query() { + const throttleQuery = throttle((inputs) => { + const result: number[] = this.$NN.query(inputs); + if (result) eventBus.emit(DATA_EVENTS.RESULT_CHANGED, result); + }, 100); + + eventBus.on(DATA_EVENTS.QUERY_CHANGED, (inputs: number[]) => throttleQuery(inputs)); + // TODO: type interface 추가하기, 이벤트버스 구조와 쿼리 구조 다시 생각해보기, TS 마이그레이션 + } } export default QueryProcessController; diff --git a/src/controller/queryPipeline/pixelExtractor.js b/src/controller/queryPipeline/pixelExtractor.js deleted file mode 100644 index d4156c7..0000000 --- a/src/controller/queryPipeline/pixelExtractor.js +++ /dev/null @@ -1,28 +0,0 @@ -export const pixelExtractor = (path) => { - const pathToMatrix = (width, height, data) => { - return Array.from({ length: height }, (_, y) => { - return Array.from({ length: width }, (_, x) => { - const i = (y * width + x) * 4; - const [r, g, b, a] = data.slice(i, i + 4); - return { r, g, b, a }; - }); - }); - } - - const grayscaleMatrix = (matrixRGB) => { - return matrixRGB.flatMap(pixelObject => - pixelObject.map(v => { - const RGB_sum = v.r + v.g + v.b; - return Math.round(RGB_sum/3); - })); - } - - const normalize = (grayscaleMatrix) => { - return grayscaleMatrix.map(v => (v/255)*0.99+0.01); - } - - const {width, height, data} = path.ctx.getImageData(0, 0, path.canvas.width, path.canvas.height); - const matrixRGB = pathToMatrix(width, height, data); - const grayScale = grayscaleMatrix(matrixRGB); - return normalize(grayScale); -}; \ No newline at end of file diff --git a/src/controller/queryPipeline/pixelExtractor.ts b/src/controller/queryPipeline/pixelExtractor.ts new file mode 100644 index 0000000..1f43ba4 --- /dev/null +++ b/src/controller/queryPipeline/pixelExtractor.ts @@ -0,0 +1,42 @@ +import { IResizeCanvas, ICanvasBase } from '../../view/components/userQuery/types/canvas'; + +export const pixelExtractor = (path: IResizeCanvas & ICanvasBase) => { + const pathToMatrix = (width: number, height: number, data: Uint8ClampedArray): object[] => { + return Array.from( + { length: height }, + (_: unknown, y: number): { r: number; g: number; b: number; a: number }[] => { + return Array.from( + { length: width }, + (_: unknown, x: number): { r: number; g: number; b: number; a: number } => { + const i: number = (y * width + x) * 4; + const [r, g, b, a] = data.slice(i, i + 4); + return { r, g, b, a }; + }, + ); + }, + ); + }; + + const grayscaleMatrix = (matrixRGB: object[]): number[] => { + return matrixRGB.flatMap((pixelObject: object[]) => + pixelObject.map((v: { r: number; g: number; b: number; a: number }): number => { + const RGB_sum: number = v.r + v.g + v.b; + return Math.round(RGB_sum / 3); + }), + ); + }; + + const normalize = (grayscaleMatrix: number[]): number[] => { + return grayscaleMatrix.map((v) => (v / 255) * 0.99 + 0.01); + }; + + const { width, height, data } = path.ctx.getImageData( + 0, + 0, + path.canvas.width, + path.canvas.height, + ); + const matrixRGB: object[] = pathToMatrix(width, height, data); + const grayScale = grayscaleMatrix(matrixRGB); + return normalize(grayScale); +}; diff --git a/src/controller/queryPipeline/types/DrawingEventHandler.ts b/src/controller/queryPipeline/types/DrawingEventHandler.ts new file mode 100644 index 0000000..d4a36b5 --- /dev/null +++ b/src/controller/queryPipeline/types/DrawingEventHandler.ts @@ -0,0 +1,12 @@ +interface DrawingEventHandlerParams { + startDraw(x: number, y: number): void; + draw(x: number, y: number): void; + endDraw(): void; + getTouchPosition(e: TouchEvent): { x: number; y: number }; + + addEventListener(listener: EventListener): void; +} + +interface DrawingEventHandlerParams { + registerEvents: DrawingEventHandlerParams; +} diff --git a/src/controller/queryPipeline/types/QueryProcessController.ts b/src/controller/queryPipeline/types/QueryProcessController.ts index 631d61b..b549161 100644 --- a/src/controller/queryPipeline/types/QueryProcessController.ts +++ b/src/controller/queryPipeline/types/QueryProcessController.ts @@ -6,6 +6,7 @@ import { IResizeCanvas, } from '../../../view/components/userQuery/types/canvas'; import { INeuralNetworkBase } from '../../../core/types/NeuralNetworkBase'; +import { IDataStore } from '../../types/DataStore'; export interface IQueryProcessControllerProps { userInputCanvas: ICanvasBase & IUserInputCanvas; @@ -13,4 +14,5 @@ export interface IQueryProcessControllerProps { alignCanvas: ICanvasBase & IAlignCanvas; resizeCanvas: ICanvasBase & IResizeCanvas; $NN: INeuralNetworkBase; + $DS: IDataStore; } diff --git a/src/controller/types/DataStore.ts b/src/controller/types/DataStore.ts new file mode 100644 index 0000000..e6b04f6 --- /dev/null +++ b/src/controller/types/DataStore.ts @@ -0,0 +1,16 @@ +export interface IDataStore { + setQueryInfo(queryInfo: number[]): void; + getQueryInfo(): number[]; + + setNodeState(nodeState: nodeState): void; + getNodeState(): nodeState; + + setQueryResult(queryResult: number[]): void; + getQueryResult(): number[]; +} + +export interface nodeState { + inputNodes: number[]; + hiddenNodes: number[]; + outputNodes: number[]; +} diff --git a/src/controller/types/eventBus.ts b/src/controller/types/eventBus.ts new file mode 100644 index 0000000..f3ad0a7 --- /dev/null +++ b/src/controller/types/eventBus.ts @@ -0,0 +1,31 @@ +import { Matrix2D } from '../../core/ops/types/OpsType'; + +export interface eventPayloads { + // Data handling event + 'query:changed': number[]; + 'node:changed': { inputNodes: number[]; hiddenNodes: number[]; outputNodes: number[] }; + 'result:changed': number[]; + + // Canvas handling event + 'draw:start': { x: number; y: number }; + 'draw:drawing': { x: number; y: number }; + 'draw:end': void; + 'bondingbox:update': { X: number; y: number }; + + 'node:update': { hiddenInputs: Matrix2D; hiddenOutputs: Matrix2D; finalOutputs: Matrix2D }; +} + +export interface IEventBus { + events: object; + on( + eventName: K, + subscriber: (payload: eventPayloads[K]) => void, + ): void; + + off( + eventName: K, + subscriber: (payload: eventPayloads[K]) => void, + ): void; + + emit(eventName: K, payload: eventPayloads[K]): void; +} diff --git a/src/core/NeuralNetworkBase.ts b/src/core/NeuralNetworkBase.ts index 152ee46..9796c0f 100644 --- a/src/core/NeuralNetworkBase.ts +++ b/src/core/NeuralNetworkBase.ts @@ -4,6 +4,7 @@ import eventBus from '../controller/EventBus.js'; import { DATA_EVENTS } from '../controller/constants/events.js'; import { weights } from '../controller/types/weights'; +import { Matrix2D } from './ops/types/OpsType'; class NeuralNetworkBase { private readonly W_inputToHidden: number[][] | null; @@ -17,21 +18,21 @@ class NeuralNetworkBase { // CNN operations feedForward(inputs: number[]): { - hiddenInputs: number[]; - hiddenOutputs: number[]; - finalOutputs: number[]; + hiddenInputs: Matrix2D; + hiddenOutputs: Matrix2D; + finalOutputs: Matrix2D; } { - const hiddenInputs: number[] = matrixMultiply( + const hiddenInputs: number[][] = matrixMultiply( this.W_inputToHidden, inputs.map((v) => [v]), ); //신경망 출력 결과를 Nx1 형태의 행렬곱으로 변환. - const hiddenOutputs: number[] = activationFunction(hiddenInputs); - const finalInputs: number[] = matrixMultiply(this.W_hiddenToOutput, hiddenOutputs); - const finalOutputs: number[] = activationFunction(finalInputs); + const hiddenOutputs: Matrix2D = activationFunction(hiddenInputs); + const finalInputs: Matrix2D = matrixMultiply(this.W_hiddenToOutput, hiddenOutputs); + const finalOutputs: Matrix2D = activationFunction(finalInputs); return { hiddenInputs, hiddenOutputs, finalOutputs }; } - query(inputs: number[]): number[] { + query(inputs: number[]): Matrix2D { const { hiddenInputs, hiddenOutputs, finalOutputs } = this.feedForward(inputs); eventBus.emit(DATA_EVENTS.NODE_UPDATE, { hiddenInputs, hiddenOutputs, finalOutputs }); return finalOutputs; diff --git a/src/core/WeightManager.js b/src/core/WeightManager.js deleted file mode 100644 index 40b49ef..0000000 --- a/src/core/WeightManager.js +++ /dev/null @@ -1,33 +0,0 @@ -import { createRandomWeight } from "./utils/createRandomWeights.js"; -import { loadPretrainedWeights } from "./utils/loadPretrainedWeights.js"; - -class WeightManager { - _cache = null; - - constructor(networkConfig) { - this.config = networkConfig; - this.path = "assets/preTrainedWeights_h200_lr15p.json"; - } - - async getWeights() { - if(this._cache) return this._cache - try{ - const json = await loadPretrainedWeights(this.path); - this._cache = { - W_inputToHidden: json.W_inputToHidden, - W_hiddenToOutput: json.W_hiddenToOutput, - }; - }catch(err){ - console.warn(`[WeightManager] Using random weights due to error: ${err.message}`); - this._cache = { - W_inputToHidden: createRandomWeight(this.config.hiddenNodes, this.config.inputNodes), - W_hiddenToOutput: createRandomWeight(this.config.outputNodes, this.config.hiddenNodes), - }; - } - console.log("Network weights fetched"); - return this._cache; - } - -} - -export default WeightManager; \ No newline at end of file diff --git a/src/core/WeightManager.ts b/src/core/WeightManager.ts new file mode 100644 index 0000000..12f4710 --- /dev/null +++ b/src/core/WeightManager.ts @@ -0,0 +1,43 @@ +import { createRandomWeight } from './utils/createRandomWeights.js'; +import { loadPretrainedWeights } from './utils/loadPretrainedWeights.js'; +import { networkConfig } from '../controller/constants/types/networkConfig'; + +import { weights } from '../controller/types/weights'; + +class WeightManager { + _cache: null | weights = null; + private config: networkConfig; + private readonly path: string; + + constructor(networkConfig: networkConfig) { + this.config = networkConfig; + this.path = 'assets/preTrainedWeights_h200_lr15p.json'; + } + + async getWeights(): Promise { + if (this._cache) return this._cache; + try { + const json = await loadPretrainedWeights(this.path); + this._cache = { + W_inputToHidden: json.W_inputToHidden, + W_hiddenToOutput: json.W_hiddenToOutput, + }; + } catch (err) { + console.warn(`[WeightManager] Using random weights due to error: ${err.message}`); + this._cache = { + W_inputToHidden: createRandomWeight( + this.config.hiddenNodes, + this.config.inputNodes, + ), + W_hiddenToOutput: createRandomWeight( + this.config.outputNodes, + this.config.hiddenNodes, + ), + }; + } + console.log('Network weights fetched'); + return this._cache; + } +} + +export default WeightManager; diff --git a/src/core/ops/matrixOps.js b/src/core/ops/matrixOps.js deleted file mode 100644 index 41247f3..0000000 --- a/src/core/ops/matrixOps.js +++ /dev/null @@ -1,17 +0,0 @@ -export const matrixMultiply = (A, B) => { - A = Array.isArray(A[0]) ? A : [A]; - - if (!Array.isArray(A) || !Array.isArray(B)) throw new Error('matrixA, B must be an array'); - else if (A[0].length !== B.length) throw new Error('rows and columns length doesn\'t match'); - - return A.map((row, i) => - B[0].map((_, j) => - row.reduce((sum, _, k) => { - return sum + A[i][k]*B[k][j]; - }, 0) - ) - ) -} - -export const transposeMatrix = matrix => - matrix[0].map((_, idx)=> matrix.map(row => row[idx])) \ No newline at end of file diff --git a/src/core/ops/matrixOps.ts b/src/core/ops/matrixOps.ts new file mode 100644 index 0000000..f6eda6e --- /dev/null +++ b/src/core/ops/matrixOps.ts @@ -0,0 +1,25 @@ +import { Matrix2D } from './types/OpsType'; + +const ensure2DArray = (matrix: number[] | number[][]): number[][] => { + return Array.isArray(matrix[0]) ? (matrix as number[][]) : [matrix as unknown as number[]]; +}; + +export const matrixMultiply = (A: Matrix2D, B: Matrix2D): Matrix2D => { + A = ensure2DArray(A); + + if (!Array.isArray(A) || !Array.isArray(B)) throw new Error('matrixA, B must be an array'); + else if (A[0].length !== B.length) throw new Error("rows and columns length doesn't match"); + + return A.map((row: number[], i: number): number[] => + B[0].map((_: unknown, j: number): number => + row.reduce((sum: number, _: unknown, k: number): number => { + return sum + A[i][k] * B[k][j]; + }, 0), + ), + ); +}; + +export const transposeMatrix = (matrix: Matrix2D): Matrix2D => + matrix[0].map((_: unknown, idx: number): number[] => + matrix.map((row: number[]): number => row[idx]), + ); diff --git a/src/core/ops/types/OpsType.ts b/src/core/ops/types/OpsType.ts new file mode 100644 index 0000000..5f6ec6d --- /dev/null +++ b/src/core/ops/types/OpsType.ts @@ -0,0 +1 @@ +export type Matrix2D = number[][]; diff --git a/src/core/utils/createRandomWeights.js b/src/core/utils/createRandomWeights.js deleted file mode 100644 index 8ff2a1f..0000000 --- a/src/core/utils/createRandomWeights.js +++ /dev/null @@ -1,7 +0,0 @@ -export const createRandomWeight = (col, row) => - Array.from({ length: col }, () => - Array.from({ length: row }, () => { - const value = (Math.random() - .5) * 1.99999; - return value; - }) - ); \ No newline at end of file diff --git a/src/core/utils/createRandomWeights.ts b/src/core/utils/createRandomWeights.ts new file mode 100644 index 0000000..b5d3086 --- /dev/null +++ b/src/core/utils/createRandomWeights.ts @@ -0,0 +1,7 @@ +export const createRandomWeight = (col: number, row: number): number[][] => + Array.from({ length: col }, (): number[] => + Array.from({ length: row }, (): number => { + const value: number = (Math.random() - 0.5) * 1.99999; + return value; + }), + ); diff --git a/src/core/utils/loadPretrainedWeights.js b/src/core/utils/loadPretrainedWeights.js deleted file mode 100644 index 9eab7ae..0000000 --- a/src/core/utils/loadPretrainedWeights.js +++ /dev/null @@ -1,5 +0,0 @@ -export async function loadPretrainedWeights(path) { - const response = await fetch(path); - if(!response.ok) throw new Error(`Failed to load weight datas from ${path}`); - return await response.json(); -} \ No newline at end of file diff --git a/src/core/utils/loadPretrainedWeights.ts b/src/core/utils/loadPretrainedWeights.ts new file mode 100644 index 0000000..d10d0e1 --- /dev/null +++ b/src/core/utils/loadPretrainedWeights.ts @@ -0,0 +1,7 @@ +import { weights } from '../../controller/types/weights'; + +export async function loadPretrainedWeights(path: string): Promise { + const response: Response = await fetch(path); + if (!response.ok) throw new Error(`Failed to load weight data from ${path}`); + return await response.json(); +} diff --git a/src/main.ts b/src/main.ts index 807ff3c..ca0bcf1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,5 @@ import AppController from './controller/AppContoller.js'; -import { DataStore } from "./controller/DataStore.js"; -const App = new AppController({DataStore}); +const App = new AppController(); await App.initialize(); -console.log("App initialized!"); \ No newline at end of file +console.log('App initialized!'); diff --git a/src/view/DataPresnter.ts b/src/view/DataPresnter.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/view/components/canvasUtils/BoundingBox.js b/src/view/components/canvasUtils/BoundingBox.js deleted file mode 100644 index 7fe4911..0000000 --- a/src/view/components/canvasUtils/BoundingBox.js +++ /dev/null @@ -1,38 +0,0 @@ -class BoundingBox { - constructor() { - this.initialCoords = { - minX: Infinity, - minY: Infinity, - maxX: -Infinity, - maxY: -Infinity, - } - this.coordinate = {...this.initialCoords}; - this.originalObject = {}; - } - - update(currentX, currentY) { - this.coordinate = { - minX: Math.round(Math.min(this.coordinate.minX, currentX)), - minY: Math.round(Math.min(this.coordinate.minY, currentY)), - maxX: Math.round(Math.max(this.coordinate.maxX, currentX)), - maxY: Math.round(Math.max(this.coordinate.maxY, currentY)), - } - Object.assign(this.originalObject, - { - x: this.coordinate.minX-20, - y: this.coordinate.minY-20, - width: this.coordinate.maxX+40 - this.coordinate.minX, - height: this.coordinate.maxY+40 - this.coordinate.minY,}); - } - - log() { - console.log(this.coordinate); - console.log(this.originalObject); - } - - reset() { - this.coordinate = {...this.initialCoords}; - } -} - -export default new BoundingBox; \ No newline at end of file diff --git a/src/view/components/canvasUtils/BoundingBox.ts b/src/view/components/canvasUtils/BoundingBox.ts new file mode 100644 index 0000000..089bb09 --- /dev/null +++ b/src/view/components/canvasUtils/BoundingBox.ts @@ -0,0 +1,44 @@ +import { IinitialCoords, originalObject } from './types'; + +class BoundingBox { + private readonly initialCoords: IinitialCoords; + private coordinate: IinitialCoords; + private readonly originalObject: originalObject | object; + + constructor() { + this.initialCoords = { + minX: Infinity, + minY: Infinity, + maxX: -Infinity, + maxY: -Infinity, + }; + this.coordinate = { ...this.initialCoords }; + this.originalObject = {}; + } + + update(currentX: number, currentY: number): void { + this.coordinate = { + minX: Math.round(Math.min(this.coordinate.minX, currentX)), + minY: Math.round(Math.min(this.coordinate.minY, currentY)), + maxX: Math.round(Math.max(this.coordinate.maxX, currentX)), + maxY: Math.round(Math.max(this.coordinate.maxY, currentY)), + }; + Object.assign(this.originalObject, { + x: this.coordinate.minX - 20, + y: this.coordinate.minY - 20, + width: this.coordinate.maxX + 40 - this.coordinate.minX, + height: this.coordinate.maxY + 40 - this.coordinate.minY, + }); + } + + log(): void { + console.log(this.coordinate); + console.log(this.originalObject); + } + + reset(): void { + this.coordinate = { ...this.initialCoords }; + } +} + +export default new BoundingBox(); diff --git a/src/view/components/canvasUtils/types.ts b/src/view/components/canvasUtils/types.ts new file mode 100644 index 0000000..b9e8646 --- /dev/null +++ b/src/view/components/canvasUtils/types.ts @@ -0,0 +1,19 @@ +export interface IinitialCoords { + minX: number; + minY: number; + maxX: number; + maxY: number; +} + +export interface originalObject { + x: number; + y: number; + width: number; + height: number; +} + +interface BoundingBox { + update(currentX: number, currentY: number): void; + log(): void; + reset(): void; +} diff --git a/src/view/components/userQuery/AlignCanvas.js b/src/view/components/userQuery/AlignCanvas.js index 743ecdc..f84d46c 100644 --- a/src/view/components/userQuery/AlignCanvas.js +++ b/src/view/components/userQuery/AlignCanvas.js @@ -1,4 +1,4 @@ -import BoundingBox from "../canvasUtils/BoundingBox.js"; +import BoundingBox from '../canvasUtils/BoundingBox.ts'; class AlignCanvas { constructor() { @@ -16,12 +16,12 @@ class AlignCanvas { this.updateCanvasScale(); } updateCanvasScale() { - if(BoundingBox.originalObject.width > BoundingBox.originalObject.height){ - this.canvas.width = BoundingBox.originalObject.width*1.3; - this.canvas.height = BoundingBox.originalObject.width*1.3; + if (BoundingBox.originalObject.width > BoundingBox.originalObject.height) { + this.canvas.width = BoundingBox.originalObject.width * 1.3; + this.canvas.height = BoundingBox.originalObject.width * 1.3; } else { - this.canvas.width = BoundingBox.originalObject.height*1.3; - this.canvas.height = BoundingBox.originalObject.height*1.3; + this.canvas.width = BoundingBox.originalObject.height * 1.3; + this.canvas.height = BoundingBox.originalObject.height * 1.3; } } @@ -30,13 +30,18 @@ class AlignCanvas { const alignStartPosition = { x: (this.canvas.width - BoundingBox.originalObject.width) / 2, y: (this.canvas.height - BoundingBox.originalObject.height) / 2, - } - this.ctx.drawImage(path, - BoundingBox.originalObject.x, BoundingBox.originalObject.y, - BoundingBox.originalObject.width, BoundingBox.originalObject.height, - alignStartPosition.x, alignStartPosition.y, - BoundingBox.originalObject.width, BoundingBox.originalObject.height - ); + }; + this.ctx.drawImage( + path, + BoundingBox.originalObject.x, + BoundingBox.originalObject.y, + BoundingBox.originalObject.width, + BoundingBox.originalObject.height, + alignStartPosition.x, + alignStartPosition.y, + BoundingBox.originalObject.width, + BoundingBox.originalObject.height, + ); } clear() { @@ -45,4 +50,4 @@ class AlignCanvas { } } -export default AlignCanvas; \ No newline at end of file +export default AlignCanvas; diff --git a/src/view/components/userQuery/PathTrackingCanvas.js b/src/view/components/userQuery/PathTrackingCanvas.js index 2f0248e..386a61f 100644 --- a/src/view/components/userQuery/PathTrackingCanvas.js +++ b/src/view/components/userQuery/PathTrackingCanvas.js @@ -1,16 +1,16 @@ -import { CANVAS_CONFIG } from "../../../controller/constants/canvasConfig.js"; +import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class PathTrackingCanvas { constructor() { // this.strokeCanvas = document.createElement('pathTrackingCanvas'); this.canvas = document.getElementById('pathTrackingCanvas'); this.ctx = this.canvas.getContext('2d', { willReadFrequently: true }); - this.setupCanvas() + this.setupCanvas(); } setupCanvas() { this.canvas.width = window.innerWidth; - this.canvas.height = window.innerHeight / 3; + this.canvas.height = window.innerHeight / 3; this.ctx.fillStyle = 'rgba(0, 0, 0)'; this.ctx.strokeStyle = 'rgba(255, 255, 255)'; @@ -37,4 +37,4 @@ class PathTrackingCanvas { } } -export default PathTrackingCanvas; \ No newline at end of file +export default PathTrackingCanvas; diff --git a/src/view/components/userQuery/UserInputCanvas.js b/src/view/components/userQuery/UserInputCanvas.js index b329245..7ef7f26 100644 --- a/src/view/components/userQuery/UserInputCanvas.js +++ b/src/view/components/userQuery/UserInputCanvas.js @@ -1,4 +1,4 @@ -import { CANVAS_CONFIG } from "../../../controller/constants/canvasConfig.js"; +import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class UserInputCanvas { constructor() { @@ -16,7 +16,7 @@ class UserInputCanvas { clear = () => { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.drawGridDots(); - } + }; setupCanvas() { this.canvas.width = window.innerWidth; @@ -34,7 +34,7 @@ class UserInputCanvas { this.ctx.fillStyle = 'rgba(255,255,255,0.3)'; this.ctx.arc(x, y, 1, 0, 2 * Math.PI); this.ctx.fill(); - } + }; for (let x = 5; x < this.canvas.width; x += 12) { for (let y = 5; y < this.canvas.height; y += 12) { @@ -58,4 +58,4 @@ class UserInputCanvas { } } -export default UserInputCanvas; \ No newline at end of file +export default UserInputCanvas; From 7e86c81beaec2fc6099983213181f94d575a7163 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 22:17:29 +0900 Subject: [PATCH 13/32] =?UTF-8?q?build:=20package,=20pnpm-lock=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vite --- package.json | 3 +- pnpm-lock.yaml | 576 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 578 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d780ffc..eba51c4 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "eslint": "^9.32.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.3", - "prettier": "3.6.2" + "prettier": "3.6.2", + "vite": "^7.0.6" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ec903a..9c498a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,168 @@ importers: prettier: specifier: 3.6.2 version: 3.6.2 + vite: + specifier: ^7.0.6 + version: 7.0.6 packages: + '@esbuild/aix-ppc64@0.25.8': + resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.8': + resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.8': + resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.8': + resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.8': + resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.8': + resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.8': + resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.8': + resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.8': + resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.8': + resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.8': + resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.8': + resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.8': + resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.8': + resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.8': + resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.8': + resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.8': + resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.8': + resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.8': + resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.8': + resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.8': + resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.8': + resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.8': + resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.8': + resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.8': + resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.8': + resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.7.0': resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -85,6 +244,106 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@rollup/rollup-android-arm-eabi@4.46.2': + resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.46.2': + resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.46.2': + resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.46.2': + resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.46.2': + resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.46.2': + resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.46.2': + resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.46.2': + resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.46.2': + resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.46.2': + resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + cpu: [x64] + os: [win32] + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -151,6 +410,11 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + esbuild@0.25.8: + resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + engines: {node: '>=18'} + hasBin: true + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -229,6 +493,14 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -244,6 +516,11 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -312,6 +589,11 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -339,6 +621,17 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -360,6 +653,11 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + rollup@4.46.2: + resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -368,6 +666,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -380,6 +682,10 @@ packages: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -387,6 +693,46 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + vite@7.0.6: + resolution: {integrity: sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -402,6 +748,84 @@ packages: snapshots: + '@esbuild/aix-ppc64@0.25.8': + optional: true + + '@esbuild/android-arm64@0.25.8': + optional: true + + '@esbuild/android-arm@0.25.8': + optional: true + + '@esbuild/android-x64@0.25.8': + optional: true + + '@esbuild/darwin-arm64@0.25.8': + optional: true + + '@esbuild/darwin-x64@0.25.8': + optional: true + + '@esbuild/freebsd-arm64@0.25.8': + optional: true + + '@esbuild/freebsd-x64@0.25.8': + optional: true + + '@esbuild/linux-arm64@0.25.8': + optional: true + + '@esbuild/linux-arm@0.25.8': + optional: true + + '@esbuild/linux-ia32@0.25.8': + optional: true + + '@esbuild/linux-loong64@0.25.8': + optional: true + + '@esbuild/linux-mips64el@0.25.8': + optional: true + + '@esbuild/linux-ppc64@0.25.8': + optional: true + + '@esbuild/linux-riscv64@0.25.8': + optional: true + + '@esbuild/linux-s390x@0.25.8': + optional: true + + '@esbuild/linux-x64@0.25.8': + optional: true + + '@esbuild/netbsd-arm64@0.25.8': + optional: true + + '@esbuild/netbsd-x64@0.25.8': + optional: true + + '@esbuild/openbsd-arm64@0.25.8': + optional: true + + '@esbuild/openbsd-x64@0.25.8': + optional: true + + '@esbuild/openharmony-arm64@0.25.8': + optional: true + + '@esbuild/sunos-x64@0.25.8': + optional: true + + '@esbuild/win32-arm64@0.25.8': + optional: true + + '@esbuild/win32-ia32@0.25.8': + optional: true + + '@esbuild/win32-x64@0.25.8': + optional: true + '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0)': dependencies: eslint: 9.32.0 @@ -461,6 +885,66 @@ snapshots: '@pkgr/core@0.2.9': {} + '@rollup/rollup-android-arm-eabi@4.46.2': + optional: true + + '@rollup/rollup-android-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-x64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.46.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.46.2': + optional: true + '@types/estree@1.0.8': {} '@types/json-schema@7.0.15': {} @@ -518,6 +1002,35 @@ snapshots: deep-is@0.1.4: {} + esbuild@0.25.8: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.8 + '@esbuild/android-arm': 0.25.8 + '@esbuild/android-arm64': 0.25.8 + '@esbuild/android-x64': 0.25.8 + '@esbuild/darwin-arm64': 0.25.8 + '@esbuild/darwin-x64': 0.25.8 + '@esbuild/freebsd-arm64': 0.25.8 + '@esbuild/freebsd-x64': 0.25.8 + '@esbuild/linux-arm': 0.25.8 + '@esbuild/linux-arm64': 0.25.8 + '@esbuild/linux-ia32': 0.25.8 + '@esbuild/linux-loong64': 0.25.8 + '@esbuild/linux-mips64el': 0.25.8 + '@esbuild/linux-ppc64': 0.25.8 + '@esbuild/linux-riscv64': 0.25.8 + '@esbuild/linux-s390x': 0.25.8 + '@esbuild/linux-x64': 0.25.8 + '@esbuild/netbsd-arm64': 0.25.8 + '@esbuild/netbsd-x64': 0.25.8 + '@esbuild/openbsd-arm64': 0.25.8 + '@esbuild/openbsd-x64': 0.25.8 + '@esbuild/openharmony-arm64': 0.25.8 + '@esbuild/sunos-x64': 0.25.8 + '@esbuild/win32-arm64': 0.25.8 + '@esbuild/win32-ia32': 0.25.8 + '@esbuild/win32-x64': 0.25.8 + escape-string-regexp@4.0.0: {} eslint-config-prettier@10.1.8(eslint@9.32.0): @@ -608,6 +1121,10 @@ snapshots: fast-levenshtein@2.0.6: {} + fdir@6.4.6(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -624,6 +1141,9 @@ snapshots: flatted@3.3.3: {} + fsevents@2.3.3: + optional: true + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -680,6 +1200,8 @@ snapshots: ms@2.1.3: {} + nanoid@3.3.11: {} + natural-compare@1.4.0: {} optionator@0.9.4: @@ -707,6 +1229,16 @@ snapshots: path-key@3.1.1: {} + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -719,12 +1251,40 @@ snapshots: resolve-from@4.0.0: {} + rollup@4.46.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.46.2 + '@rollup/rollup-android-arm64': 4.46.2 + '@rollup/rollup-darwin-arm64': 4.46.2 + '@rollup/rollup-darwin-x64': 4.46.2 + '@rollup/rollup-freebsd-arm64': 4.46.2 + '@rollup/rollup-freebsd-x64': 4.46.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 + '@rollup/rollup-linux-arm-musleabihf': 4.46.2 + '@rollup/rollup-linux-arm64-gnu': 4.46.2 + '@rollup/rollup-linux-arm64-musl': 4.46.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 + '@rollup/rollup-linux-ppc64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-musl': 4.46.2 + '@rollup/rollup-linux-s390x-gnu': 4.46.2 + '@rollup/rollup-linux-x64-gnu': 4.46.2 + '@rollup/rollup-linux-x64-musl': 4.46.2 + '@rollup/rollup-win32-arm64-msvc': 4.46.2 + '@rollup/rollup-win32-ia32-msvc': 4.46.2 + '@rollup/rollup-win32-x64-msvc': 4.46.2 + fsevents: 2.3.3 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + source-map-js@1.2.1: {} + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -735,6 +1295,11 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 + tinyglobby@0.2.14: + dependencies: + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -743,6 +1308,17 @@ snapshots: dependencies: punycode: 2.3.1 + vite@7.0.6: + dependencies: + esbuild: 0.25.8 + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.2 + tinyglobby: 0.2.14 + optionalDependencies: + fsevents: 2.3.3 + which@2.0.2: dependencies: isexe: 2.0.0 From 54ccb9d392ea13b5899706f8418e1588fcd825c4 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 23:33:38 +0900 Subject: [PATCH 14/32] =?UTF-8?q?chore:=20tsconfig=20'allowImportingTsExte?= =?UTF-8?q?nsions'=20=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tsconfig.json b/tsconfig.json index 0a0b2a2..592c17f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,8 @@ "target": "ES2020", "module": "ES2022", "moduleResolution": "Node", + "allowImportingTsExtensions": true, + "noEmit": true, "outDir": "./dist", "rootDir": "./src", "strict": false, From 1c7769e828cbfa491ed67263f22e1fd0a9c08ea9 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 23:34:55 +0900 Subject: [PATCH 15/32] =?UTF-8?q?migration:=20=EC=BA=94=EB=B2=84=EC=8A=A4?= =?UTF-8?q?=20=ED=95=B8=EB=93=A4=EB=A7=81=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81(WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../queryPipeline/DrawingEventHandler.js | 65 ---------------- .../queryPipeline/DrawingEventHandler.ts | 74 +++++++++++++++++++ 2 files changed, 74 insertions(+), 65 deletions(-) delete mode 100644 src/controller/queryPipeline/DrawingEventHandler.js create mode 100644 src/controller/queryPipeline/DrawingEventHandler.ts diff --git a/src/controller/queryPipeline/DrawingEventHandler.js b/src/controller/queryPipeline/DrawingEventHandler.js deleted file mode 100644 index 8f0facf..0000000 --- a/src/controller/queryPipeline/DrawingEventHandler.js +++ /dev/null @@ -1,65 +0,0 @@ -import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; -import eventBus from '../EventBus.ts'; -import { DRAWING_EVENTS } from '../constants/events.ts'; - -class DrawingEventHandler { - constructor() { - this.inputCanvas = document.getElementById('userInputCanvas'); - this.registerEvents(); - } - - registerEvents() { - const startDraw = (x, y) => { - this.isDrawing = true; - eventBus.emit(DRAWING_EVENTS.START_DRAW, { x, y }); - }; - - const draw = (x, y) => { - if (!this.isDrawing) return; - BoundingBox.update(x, y); - eventBus.emit(DRAWING_EVENTS.DRAW, { x, y }); - }; - - const endDraw = () => { - this.isDrawing = false; - BoundingBox.log(); - eventBus.emit(DRAWING_EVENTS.END_DRAW); - }; - - const getTouchPosition = (e) => { - e.preventDefault(); - const touch = e.touches[0]; - const rect = this.inputCanvas.getBoundingClientRect(); - return { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - }; - }; - - this.inputCanvas.addEventListener('mousedown', (e) => { - startDraw(e.offsetX, e.offsetY); - }); - this.inputCanvas.addEventListener('touchstart', (e) => { - let { x, y } = getTouchPosition(e); - startDraw(x, y); - }); - - this.inputCanvas.addEventListener('mousemove', (e) => { - draw(e.offsetX, e.offsetY); - }); - this.inputCanvas.addEventListener('touchmove', (e) => { - let { x, y } = getTouchPosition(e); - draw(x, y); - }); - - this.inputCanvas.addEventListener('mouseup', endDraw); - this.inputCanvas.addEventListener('mouseout', endDraw); - this.inputCanvas.addEventListener('touchend', (e) => { - e.preventDefault(); - endDraw(); - }); - // TODO: Touch/Click 이벤트 코드 리팩토링(중복 없애기) - } -} - -export default DrawingEventHandler; diff --git a/src/controller/queryPipeline/DrawingEventHandler.ts b/src/controller/queryPipeline/DrawingEventHandler.ts new file mode 100644 index 0000000..f86439a --- /dev/null +++ b/src/controller/queryPipeline/DrawingEventHandler.ts @@ -0,0 +1,74 @@ +import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; +import eventBus from '../EventBus.ts'; +import { DRAWING_EVENTS } from '../constants/events.ts'; + +class DrawingEventHandler { + private inputCanvas: HTMLCanvasElement | null; + private isDrawing: boolean; + // TODO: 이벤트 핸들러 리팩토링 + + constructor() { + this.inputCanvas = document.getElementById('userInputCanvas') as HTMLCanvasElement; + this.isDrawing = false; + this.registerEvents(); + } + + registerEvents(): void { + this.inputCanvas.addEventListener('mousedown', this.handleStartDraw); + this.inputCanvas.addEventListener('touchstart', this.handleStartDraw); + this.inputCanvas.addEventListener('mousemove', this.handleDraw); + this.inputCanvas.addEventListener('touchmove', this.handleDraw); + this.inputCanvas.addEventListener('mouseup', this.endDraw); + this.inputCanvas.addEventListener('mouseout', this.endDraw); + this.inputCanvas.addEventListener('touchend', (e: TouchEvent): void => { + e.preventDefault(); + this.endDraw(); + }); + } + + startDraw = (x: number, y: number): void => { + this.isDrawing = true; + eventBus.emit(DRAWING_EVENTS.START_DRAW, { x, y }); + }; + + draw = (x: number, y: number): void => { + if (!this.isDrawing) return; + BoundingBox.update(x, y); + eventBus.emit(DRAWING_EVENTS.DRAW, { x, y }); + }; + + endDraw = (): void => { + this.isDrawing = false; + BoundingBox.log(); + eventBus.emit(DRAWING_EVENTS.END_DRAW, null); + }; + + getTouchPosition = (e: TouchEvent): { x: number; y: number } => { + e.preventDefault(); + const touch = e.touches[0]; + const rect = this.inputCanvas.getBoundingClientRect(); + return { + x: touch.clientX - rect.left, + y: touch.clientY - rect.top, + }; + }; + + handleStartDraw = (e: MouseEvent | TouchEvent): void => { + if (e instanceof MouseEvent) { + this.startDraw(e.offsetX, e.offsetY); + } else if (e instanceof TouchEvent) { + let { x, y } = this.getTouchPosition(e); + this.startDraw(x, y); + } + }; + handleDraw = (e: MouseEvent | TouchEvent): void => { + if (e instanceof MouseEvent) { + this.draw(e.offsetX, e.offsetY); + } else if (e instanceof TouchEvent) { + let { x, y } = this.getTouchPosition(e); + this.draw(x, y); + } + }; +} + +export default DrawingEventHandler; From d7f0725b66dc927f372b43031f85e88890562acb Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 23:41:47 +0900 Subject: [PATCH 16/32] =?UTF-8?q?chore:=20=EC=84=A4=EB=AA=85=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/queryPipeline/DrawingEventHandler.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controller/queryPipeline/DrawingEventHandler.ts b/src/controller/queryPipeline/DrawingEventHandler.ts index f86439a..04c22bb 100644 --- a/src/controller/queryPipeline/DrawingEventHandler.ts +++ b/src/controller/queryPipeline/DrawingEventHandler.ts @@ -26,6 +26,7 @@ class DrawingEventHandler { }); } + // eventBus로 입력 event 전송 startDraw = (x: number, y: number): void => { this.isDrawing = true; eventBus.emit(DRAWING_EVENTS.START_DRAW, { x, y }); @@ -43,6 +44,7 @@ class DrawingEventHandler { eventBus.emit(DRAWING_EVENTS.END_DRAW, null); }; + // 캔버스에서의 터치 위치 반환 getTouchPosition = (e: TouchEvent): { x: number; y: number } => { e.preventDefault(); const touch = e.touches[0]; @@ -53,6 +55,7 @@ class DrawingEventHandler { }; }; + // 마우스 클릭, 터치 이벤트에 대한 입력 이벤트 발생 handleStartDraw = (e: MouseEvent | TouchEvent): void => { if (e instanceof MouseEvent) { this.startDraw(e.offsetX, e.offsetY); @@ -61,6 +64,7 @@ class DrawingEventHandler { this.startDraw(x, y); } }; + handleDraw = (e: MouseEvent | TouchEvent): void => { if (e instanceof MouseEvent) { this.draw(e.offsetX, e.offsetY); From a5874df9a15f5449215ce6e7d5f4ce45444576f5 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Wed, 6 Aug 2025 23:54:01 +0900 Subject: [PATCH 17/32] =?UTF-8?q?refactor:=20DrawingEventHandler=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../queryPipeline/DrawingEventHandler.ts | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/controller/queryPipeline/DrawingEventHandler.ts b/src/controller/queryPipeline/DrawingEventHandler.ts index 04c22bb..109d327 100644 --- a/src/controller/queryPipeline/DrawingEventHandler.ts +++ b/src/controller/queryPipeline/DrawingEventHandler.ts @@ -5,7 +5,6 @@ import { DRAWING_EVENTS } from '../constants/events.ts'; class DrawingEventHandler { private inputCanvas: HTMLCanvasElement | null; private isDrawing: boolean; - // TODO: 이벤트 핸들러 리팩토링 constructor() { this.inputCanvas = document.getElementById('userInputCanvas') as HTMLCanvasElement; @@ -14,16 +13,25 @@ class DrawingEventHandler { } registerEvents(): void { - this.inputCanvas.addEventListener('mousedown', this.handleStartDraw); - this.inputCanvas.addEventListener('touchstart', this.handleStartDraw); - this.inputCanvas.addEventListener('mousemove', this.handleDraw); - this.inputCanvas.addEventListener('touchmove', this.handleDraw); - this.inputCanvas.addEventListener('mouseup', this.endDraw); - this.inputCanvas.addEventListener('mouseout', this.endDraw); - this.inputCanvas.addEventListener('touchend', (e: TouchEvent): void => { - e.preventDefault(); - this.endDraw(); - }); + const bindings: [string, EventListener][] = [ + ['mousedown', this.handleStartDraw], + ['touchstart', this.handleStartDraw], + ['mousemove', this.handleDraw], + ['touchmove', this.handleDraw], + ['mouseup', this.endDraw], + ['mouseout', this.endDraw], + [ + 'touchend', + (e: TouchEvent): void => { + e.preventDefault(); + this.endDraw(); + }, + ], + ]; + + bindings.forEach(([event, handler]: [string, EventListener]): void => + this.inputCanvas.addEventListener(event, handler), + ); } // eventBus로 입력 event 전송 From a88d829eb2c4001d43cae436cb7f5ead375bfa49 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Thu, 7 Aug 2025 19:49:20 +0900 Subject: [PATCH 18/32] refactor: migration activation ops --- src/core/ops/activationOps.js | 17 ----------------- src/core/ops/activationOps.ts | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) delete mode 100644 src/core/ops/activationOps.js create mode 100644 src/core/ops/activationOps.ts diff --git a/src/core/ops/activationOps.js b/src/core/ops/activationOps.js deleted file mode 100644 index 9dfb928..0000000 --- a/src/core/ops/activationOps.js +++ /dev/null @@ -1,17 +0,0 @@ -const activationFunction = matrix => - matrix.map(array => - array.map(v => { - const value = sigmoid(v) - return parseFloat(value.toFixed(5)) //활성화 함수를 적용시킨 값을 소숫점 5자리로 반올림 - }) - ) - -const sigmoid = ($x) => { - return 1 / (1 + Math.exp(-$x)); -}; - -const ReLU = ($x) => { - return Math.max(0, $x); -} - -export default activationFunction; \ No newline at end of file diff --git a/src/core/ops/activationOps.ts b/src/core/ops/activationOps.ts new file mode 100644 index 0000000..3d92e4a --- /dev/null +++ b/src/core/ops/activationOps.ts @@ -0,0 +1,19 @@ +import { Matrix2D } from './types/OpsType.ts'; + +const activationFunction = (matrix: Matrix2D): Matrix2D => + matrix.map((array: number[]): number[] => + array.map((v: number): number => { + const value: number = sigmoid(v); + return parseFloat(value.toFixed(5)); //활성화 함수를 적용시킨 값을 소숫점 5자리로 반올림 + }), + ); + +const sigmoid = ($x: number): number => { + return 1 / (1 + Math.exp(-$x)); +}; + +const ReLU = ($x: number): number => { + return Math.max(0, $x); +}; + +export default activationFunction; From 7cc833856ffa8f1fb0c11e0e5b511eb7211224db Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Thu, 7 Aug 2025 22:15:53 +0900 Subject: [PATCH 19/32] refactor: canvas migration to Typescript --- .../userQuery/{AlignCanvas.js => AlignCanvas.ts} | 16 ++++++++-------- ...thTrackingCanvas.js => PathTrackingCanvas.ts} | 14 ++++++++------ .../{ResizeCanvas.js => ResizeCanvas.ts} | 9 ++++++--- .../{UserInputCanvas.js => UserInputCanvas.ts} | 16 ++++++++++------ 4 files changed, 32 insertions(+), 23 deletions(-) rename src/view/components/userQuery/{AlignCanvas.js => AlignCanvas.ts} (84%) rename src/view/components/userQuery/{PathTrackingCanvas.js => PathTrackingCanvas.ts} (73%) rename src/view/components/userQuery/{ResizeCanvas.js => ResizeCanvas.ts} (67%) rename src/view/components/userQuery/{UserInputCanvas.js => UserInputCanvas.ts} (82%) diff --git a/src/view/components/userQuery/AlignCanvas.js b/src/view/components/userQuery/AlignCanvas.ts similarity index 84% rename from src/view/components/userQuery/AlignCanvas.js rename to src/view/components/userQuery/AlignCanvas.ts index f84d46c..7aa43af 100644 --- a/src/view/components/userQuery/AlignCanvas.js +++ b/src/view/components/userQuery/AlignCanvas.ts @@ -1,21 +1,21 @@ import BoundingBox from '../canvasUtils/BoundingBox.ts'; class AlignCanvas { + private readonly canvas: HTMLCanvasElement | null; + private readonly ctx: CanvasRenderingContext2D; + constructor() { - // this.canvas = document.createElement('alignCanvas'); - this.canvas = document.getElementById('alignCanvas'); + this.canvas = document.createElement('canvas') as HTMLCanvasElement; this.ctx = this.canvas.getContext('2d', { willReadFrequently: true }); this.canvas.style.border = '2px solid red'; - - const { minX, minY, maxX, maxY } = BoundingBox.coordinate; this.setupCanvas(); } - setupCanvas() { + setupCanvas(): void { this.ctx.fillStyle = 'rgba(0, 0, 0)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.updateCanvasScale(); } - updateCanvasScale() { + updateCanvasScale(): void { if (BoundingBox.originalObject.width > BoundingBox.originalObject.height) { this.canvas.width = BoundingBox.originalObject.width * 1.3; this.canvas.height = BoundingBox.originalObject.width * 1.3; @@ -25,7 +25,7 @@ class AlignCanvas { } } - centralize(path) { + centralize(path: HTMLImageElement): void { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); const alignStartPosition = { x: (this.canvas.width - BoundingBox.originalObject.width) / 2, @@ -44,7 +44,7 @@ class AlignCanvas { ); } - clear() { + clear(): void { this.canvas.width = this.canvas.height = 1; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } diff --git a/src/view/components/userQuery/PathTrackingCanvas.js b/src/view/components/userQuery/PathTrackingCanvas.ts similarity index 73% rename from src/view/components/userQuery/PathTrackingCanvas.js rename to src/view/components/userQuery/PathTrackingCanvas.ts index 386a61f..f264489 100644 --- a/src/view/components/userQuery/PathTrackingCanvas.js +++ b/src/view/components/userQuery/PathTrackingCanvas.ts @@ -1,14 +1,16 @@ import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class PathTrackingCanvas { + private readonly canvas: HTMLCanvasElement | null; + private readonly ctx: CanvasRenderingContext2D; + constructor() { - // this.strokeCanvas = document.createElement('pathTrackingCanvas'); - this.canvas = document.getElementById('pathTrackingCanvas'); + this.canvas = document.createElement('canvas') as HTMLCanvasElement; this.ctx = this.canvas.getContext('2d', { willReadFrequently: true }); this.setupCanvas(); } - setupCanvas() { + setupCanvas(): void { this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight / 3; @@ -22,17 +24,17 @@ class PathTrackingCanvas { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } - startPath(x, y) { + startPath(x: number, y: number): void { this.ctx.beginPath(); this.ctx.moveTo(x, y); } - drawPath(x, y) { + drawPath(x: number, y: number): void { this.ctx.lineTo(x, y); this.ctx.stroke(); } - endPath() { + endPath(): void { this.ctx.closePath(); } } diff --git a/src/view/components/userQuery/ResizeCanvas.js b/src/view/components/userQuery/ResizeCanvas.ts similarity index 67% rename from src/view/components/userQuery/ResizeCanvas.js rename to src/view/components/userQuery/ResizeCanvas.ts index cd0a657..82b36b6 100644 --- a/src/view/components/userQuery/ResizeCanvas.js +++ b/src/view/components/userQuery/ResizeCanvas.ts @@ -1,17 +1,20 @@ class ResizeCanvas { + private readonly canvas: HTMLCanvasElement | null; + private readonly ctx: CanvasRenderingContext2D; + constructor() { - this.canvas = document.getElementById("resizeCanvas"); + this.canvas = document.createElement("canvas") as HTMLCanvasElement; this.ctx = this.canvas.getContext("2d", { willReadFrequently: true }); this.canvas.width = this.canvas.height = 28; } - downScale(path) { + downScale(path: HTMLImageElement): void { this.ctx.fillStyle = 'rgba(255,255,255)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.drawImage(path, 0, 0, path.width, path.height, 0, 0, this.canvas.width, this.canvas.height); } - clear() { + clear(): void { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } } diff --git a/src/view/components/userQuery/UserInputCanvas.js b/src/view/components/userQuery/UserInputCanvas.ts similarity index 82% rename from src/view/components/userQuery/UserInputCanvas.js rename to src/view/components/userQuery/UserInputCanvas.ts index 7ef7f26..7da0f85 100644 --- a/src/view/components/userQuery/UserInputCanvas.js +++ b/src/view/components/userQuery/UserInputCanvas.ts @@ -1,8 +1,12 @@ import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class UserInputCanvas { + private readonly canvas: HTMLCanvasElement | null; + private readonly ctx: CanvasRenderingContext2D; + private isDrawing: boolean; + constructor() { - this.canvas = document.getElementById('userInputCanvas'); + this.canvas = document.getElementById('userInputCanvas') as HTMLCanvasElement; this.ctx = this.canvas.getContext('2d'); this.isDrawing = false; this.setupCanvas(); @@ -13,12 +17,12 @@ class UserInputCanvas { this.ctx.lineJoin = CANVAS_CONFIG.lineJoin; } - clear = () => { + clear = (): void => { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.drawGridDots(); }; - setupCanvas() { + setupCanvas(): void { this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight / 3; @@ -43,17 +47,17 @@ class UserInputCanvas { } } - startPath(x, y) { + startPath(x: number, y: number): void { this.ctx.beginPath(); this.ctx.moveTo(x, y); } - drawPath(x, y) { + drawPath(x: number, y: number): void { this.ctx.lineTo(x, y); this.ctx.stroke(); } - endPath() { + endPath(): void { this.ctx.closePath(); } } From 54db197143f99f1ce724dcdafc28fb30b746df0c Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 9 Aug 2025 23:48:27 +0900 Subject: [PATCH 20/32] =?UTF-8?q?chore:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/{AppContoller.js => AppController.js} | 8 ++++---- src/main.ts | 2 +- .../perceptron/{Perceptron.js => Perceptron.ts} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename src/controller/{AppContoller.js => AppController.js} (96%) rename src/view/components/perceptron/{Perceptron.js => Perceptron.ts} (100%) diff --git a/src/controller/AppContoller.js b/src/controller/AppController.js similarity index 96% rename from src/controller/AppContoller.js rename to src/controller/AppController.js index eca5910..001b9e9 100644 --- a/src/controller/AppContoller.js +++ b/src/controller/AppController.js @@ -1,10 +1,10 @@ import WeightManager from '../core/WeightManager.ts'; import NeuralNetworkBase from '../core/NeuralNetworkBase.ts'; import QueryProcessController from './queryPipeline/QueryProcessController.ts'; -import UserInputCanvas from '../view/components/userQuery/UserInputCanvas.js'; -import PathTrackingCanvas from '../view/components/userQuery/PathTrackingCanvas.js'; -import AlignCanvas from '../view/components/userQuery/AlignCanvas.js'; -import ResizeCanvas from '../view/components/userQuery/ResizeCanvas.js'; +import UserInputCanvas from '../view/components/userQuery/UserInputCanvas.ts'; +import PathTrackingCanvas from '../view/components/userQuery/PathTrackingCanvas.ts'; +import AlignCanvas from '../view/components/userQuery/AlignCanvas.ts'; +import ResizeCanvas from '../view/components/userQuery/ResizeCanvas.ts'; import DataStore from './DataStore.ts'; import eventBus from './EventBus.ts'; diff --git a/src/main.ts b/src/main.ts index ca0bcf1..70a5ce8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import AppController from './controller/AppContoller.js'; +import AppController from './controller/AppController.js'; const App = new AppController(); await App.initialize(); diff --git a/src/view/components/perceptron/Perceptron.js b/src/view/components/perceptron/Perceptron.ts similarity index 100% rename from src/view/components/perceptron/Perceptron.js rename to src/view/components/perceptron/Perceptron.ts From 40fd0b9bd64247c3ede8a118607de15f0d0a2289 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 9 Aug 2025 23:49:05 +0900 Subject: [PATCH 21/32] =?UTF-8?q?fix:=20BoundingBox=EC=9D=98=20=EC=98=A4?= =?UTF-8?q?=EB=B8=8C=EC=A0=9D=ED=8A=B8=20=EC=A2=8C=ED=91=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=EC=97=90=EC=84=9C=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/view/components/canvasUtils/BoundingBox.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/view/components/canvasUtils/BoundingBox.ts b/src/view/components/canvasUtils/BoundingBox.ts index 089bb09..8aaac15 100644 --- a/src/view/components/canvasUtils/BoundingBox.ts +++ b/src/view/components/canvasUtils/BoundingBox.ts @@ -3,7 +3,7 @@ import { IinitialCoords, originalObject } from './types'; class BoundingBox { private readonly initialCoords: IinitialCoords; private coordinate: IinitialCoords; - private readonly originalObject: originalObject | object; + readonly originalObject: originalObject; constructor() { this.initialCoords = { @@ -13,7 +13,12 @@ class BoundingBox { maxY: -Infinity, }; this.coordinate = { ...this.initialCoords }; - this.originalObject = {}; + this.originalObject = { + x: 0, + y: 0, + width: 0, + height: 0, + }; } update(currentX: number, currentY: number): void { From 9cf8460637fb84842ffde5778728fba84d4055e7 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 15:03:25 +0900 Subject: [PATCH 22/32] =?UTF-8?q?chore:=20drawingEvent=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/queryPipeline/QueryProcessController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts index 6b3c956..00d4dfb 100644 --- a/src/controller/queryPipeline/QueryProcessController.ts +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -38,11 +38,11 @@ class QueryProcessController { this.$NN = $NN; this.$DS = $DS; - this.drawingEvent(); + this.registerDrawingEvent(); this.query(); } - drawingEvent(): void { + registerDrawingEvent(): void { eventBus.on(DRAWING_EVENTS.START_DRAW, ({ x, y }) => { this.userInputCanvas.startPath(x, y); this.trackingCanvas.startPath(x, y); From dd86942acc268358b706f6bac044ee506f116821 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 16:10:30 +0900 Subject: [PATCH 23/32] =?UTF-8?q?refactor:=20BoundingBox=EC=9D=98=20?= =?UTF-8?q?=EC=BA=A1=EC=8A=90=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=9C=20get?= =?UTF-8?q?ter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/canvasUtils/BoundingBox.ts | 6 ++++- src/view/components/userQuery/AlignCanvas.ts | 26 +++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/view/components/canvasUtils/BoundingBox.ts b/src/view/components/canvasUtils/BoundingBox.ts index 8aaac15..bd7b1b1 100644 --- a/src/view/components/canvasUtils/BoundingBox.ts +++ b/src/view/components/canvasUtils/BoundingBox.ts @@ -3,7 +3,7 @@ import { IinitialCoords, originalObject } from './types'; class BoundingBox { private readonly initialCoords: IinitialCoords; private coordinate: IinitialCoords; - readonly originalObject: originalObject; + private originalObject: originalObject; constructor() { this.initialCoords = { @@ -21,6 +21,10 @@ class BoundingBox { }; } + getOriginalObject(): Readonly { + return { ...this.originalObject }; + } + update(currentX: number, currentY: number): void { this.coordinate = { minX: Math.round(Math.min(this.coordinate.minX, currentX)), diff --git a/src/view/components/userQuery/AlignCanvas.ts b/src/view/components/userQuery/AlignCanvas.ts index 7aa43af..4809f51 100644 --- a/src/view/components/userQuery/AlignCanvas.ts +++ b/src/view/components/userQuery/AlignCanvas.ts @@ -16,31 +16,31 @@ class AlignCanvas { this.updateCanvasScale(); } updateCanvasScale(): void { - if (BoundingBox.originalObject.width > BoundingBox.originalObject.height) { - this.canvas.width = BoundingBox.originalObject.width * 1.3; - this.canvas.height = BoundingBox.originalObject.width * 1.3; + if (BoundingBox.getOriginalObject().width > BoundingBox.getOriginalObject().height) { + this.canvas.width = BoundingBox.getOriginalObject().width * 1.3; + this.canvas.height = BoundingBox.getOriginalObject().width * 1.3; } else { - this.canvas.width = BoundingBox.originalObject.height * 1.3; - this.canvas.height = BoundingBox.originalObject.height * 1.3; + this.canvas.width = BoundingBox.getOriginalObject().height * 1.3; + this.canvas.height = BoundingBox.getOriginalObject().height * 1.3; } } centralize(path: HTMLImageElement): void { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); const alignStartPosition = { - x: (this.canvas.width - BoundingBox.originalObject.width) / 2, - y: (this.canvas.height - BoundingBox.originalObject.height) / 2, + x: (this.canvas.width - BoundingBox.getOriginalObject().width) / 2, + y: (this.canvas.height - BoundingBox.getOriginalObject().height) / 2, }; this.ctx.drawImage( path, - BoundingBox.originalObject.x, - BoundingBox.originalObject.y, - BoundingBox.originalObject.width, - BoundingBox.originalObject.height, + BoundingBox.getOriginalObject().x, + BoundingBox.getOriginalObject().y, + BoundingBox.getOriginalObject().width, + BoundingBox.getOriginalObject().height, alignStartPosition.x, alignStartPosition.y, - BoundingBox.originalObject.width, - BoundingBox.originalObject.height, + BoundingBox.getOriginalObject().width, + BoundingBox.getOriginalObject().height, ); } From fcd057d5e5acb845d0e3b7559201abc78ee93120 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 16:10:47 +0900 Subject: [PATCH 24/32] chore: js to ts --- src/view/{ViewHandler.js => ViewHandler.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/view/{ViewHandler.js => ViewHandler.ts} (100%) diff --git a/src/view/ViewHandler.js b/src/view/ViewHandler.ts similarity index 100% rename from src/view/ViewHandler.js rename to src/view/ViewHandler.ts From 9911f1dd78ac682414d861eee0cd765384924ac3 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 16:11:53 +0900 Subject: [PATCH 25/32] =?UTF-8?q?refactor:=20entryPoint=EC=9D=98=20?= =?UTF-8?q?=EC=9D=BC=EA=B4=80=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=B4=20Dra?= =?UTF-8?q?wingEventHandler=EC=9D=98=20=EC=84=A0=EC=96=B8=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/AppController.js | 2 ++ src/controller/queryPipeline/QueryProcessController.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/AppController.js b/src/controller/AppController.js index 001b9e9..b1c3eb9 100644 --- a/src/controller/AppController.js +++ b/src/controller/AppController.js @@ -10,12 +10,14 @@ import DataStore from './DataStore.ts'; import eventBus from './EventBus.ts'; import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.ts'; import { NETWORK_CONFIG } from './constants/networkConfig.ts'; +import DrawingEventHandler from './queryPipeline/DrawingEventHandler.js'; class AppController { async initialize() { const $WM = new WeightManager(NETWORK_CONFIG); const $NN = new NeuralNetworkBase(await $WM.getWeights()); const $DS = new DataStore(); + new DrawingEventHandler(); const $QC = new QueryProcessController({ userInputCanvas: new UserInputCanvas(), trackingCanvas: new PathTrackingCanvas(), diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts index 00d4dfb..55499f5 100644 --- a/src/controller/queryPipeline/QueryProcessController.ts +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -1,6 +1,5 @@ import eventBus from '../EventBus.js'; import { DATA_EVENTS, DRAWING_EVENTS } from '../constants/events.js'; -import DrawingEventHandler from './DrawingEventHandler.js'; import { pixelExtractor } from './pixelExtractor.js'; import { throttle } from './throttle'; import { IQueryProcessControllerProps } from './types/QueryProcessController.js'; @@ -30,7 +29,6 @@ class QueryProcessController { $NN, $DS, }: IQueryProcessControllerProps) { - new DrawingEventHandler(); this.userInputCanvas = userInputCanvas; this.trackingCanvas = trackingCanvas; this.alignCanvas = alignCanvas; From ec63410692ef346eeab345d14b795f71da7e57be Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 16:33:26 +0900 Subject: [PATCH 26/32] =?UTF-8?q?refactor:=20jsconfig=20path=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jsconfig.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/jsconfig.json b/jsconfig.json index ec6c9e9..0afe90a 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "baseUrl": "src", "paths": { - "@controller/*": ["controller/*"], - "@core/*": ["core/*"], - "@view/*": ["view/*"] + "@/*": ["./*"] } }, "include": ["src"] From 848c866b57e028ff59de3a84b96a639ce64e3903 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 22:45:32 +0900 Subject: [PATCH 27/32] =?UTF-8?q?feat:=20canvas=20clear=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 +--- src/controller/queryPipeline/DrawingEventHandler.ts | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 7f8501c..3e0130a 100644 --- a/index.html +++ b/index.html @@ -20,9 +20,7 @@
- - - +
diff --git a/src/controller/queryPipeline/DrawingEventHandler.ts b/src/controller/queryPipeline/DrawingEventHandler.ts index 109d327..44905ff 100644 --- a/src/controller/queryPipeline/DrawingEventHandler.ts +++ b/src/controller/queryPipeline/DrawingEventHandler.ts @@ -4,10 +4,12 @@ import { DRAWING_EVENTS } from '../constants/events.ts'; class DrawingEventHandler { private inputCanvas: HTMLCanvasElement | null; + private clearButton: HTMLButtonElement | null; private isDrawing: boolean; constructor() { this.inputCanvas = document.getElementById('userInputCanvas') as HTMLCanvasElement; + this.clearButton = document.getElementById('clear') as HTMLButtonElement; this.isDrawing = false; this.registerEvents(); } @@ -32,6 +34,10 @@ class DrawingEventHandler { bindings.forEach(([event, handler]: [string, EventListener]): void => this.inputCanvas.addEventListener(event, handler), ); + + this.clearButton.addEventListener('click', () => { + eventBus.emit(DRAWING_EVENTS.CLEAR_DRAW, null); + }); } // eventBus로 입력 event 전송 From 75a8e5f3da696248f7294548ff734ce7fec94fb3 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 22:47:19 +0900 Subject: [PATCH 28/32] =?UTF-8?q?feat:=20type=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9E=98=EB=AA=BB=EB=90=9C=20type=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/DataStore.ts | 5 +-- src/controller/types/eventBus.ts | 3 +- src/core/WeightManager.ts | 2 +- src/core/types/NeuralNetworkBase.ts | 10 ++++-- src/view/components/userQuery/AlignCanvas.ts | 8 ++--- .../userQuery/PathTrackingCanvas.ts | 8 +++-- src/view/components/userQuery/ResizeCanvas.ts | 33 ++++++++++++++----- .../components/userQuery/UserInputCanvas.ts | 5 +-- src/view/components/userQuery/types/canvas.ts | 2 +- 9 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/controller/DataStore.ts b/src/controller/DataStore.ts index eecdd50..0b0d47c 100644 --- a/src/controller/DataStore.ts +++ b/src/controller/DataStore.ts @@ -2,11 +2,12 @@ import eventBus from './EventBus.js'; import { DATA_EVENTS } from './constants/events.js'; import { nodeState } from './types/DataStore'; +import { Matrix2D } from '../core/ops/types/OpsType.ts'; class DataStore { private queryInfo: number[] | null = null; private nodeState: nodeState | null = null; - private queryResult: number[] | null = null; + private queryResult: Matrix2D | null = null; constructor() { this.queryInfo = null; @@ -31,7 +32,7 @@ class DataStore { return this.nodeState; } - setQueryResult(queryResult: number[]): void { + setQueryResult(queryResult: Matrix2D): void { if (queryResult === null) throw new Error('No query result found'); this.queryResult = queryResult; eventBus.emit(DATA_EVENTS.RESULT_CHANGED, queryResult); diff --git a/src/controller/types/eventBus.ts b/src/controller/types/eventBus.ts index f3ad0a7..0697741 100644 --- a/src/controller/types/eventBus.ts +++ b/src/controller/types/eventBus.ts @@ -4,12 +4,13 @@ export interface eventPayloads { // Data handling event 'query:changed': number[]; 'node:changed': { inputNodes: number[]; hiddenNodes: number[]; outputNodes: number[] }; - 'result:changed': number[]; + 'result:changed': Matrix2D; // Canvas handling event 'draw:start': { x: number; y: number }; 'draw:drawing': { x: number; y: number }; 'draw:end': void; + 'draw:clear': void; 'bondingbox:update': { X: number; y: number }; 'node:update': { hiddenInputs: Matrix2D; hiddenOutputs: Matrix2D; finalOutputs: Matrix2D }; diff --git a/src/core/WeightManager.ts b/src/core/WeightManager.ts index 12f4710..1c42a93 100644 --- a/src/core/WeightManager.ts +++ b/src/core/WeightManager.ts @@ -5,7 +5,7 @@ import { networkConfig } from '../controller/constants/types/networkConfig'; import { weights } from '../controller/types/weights'; class WeightManager { - _cache: null | weights = null; + private _cache: null | weights = null; private config: networkConfig; private readonly path: string; diff --git a/src/core/types/NeuralNetworkBase.ts b/src/core/types/NeuralNetworkBase.ts index 7035612..98a66e9 100644 --- a/src/core/types/NeuralNetworkBase.ts +++ b/src/core/types/NeuralNetworkBase.ts @@ -1,4 +1,10 @@ +import { Matrix2D } from '../ops/types/OpsType.ts'; + export interface INeuralNetworkBase { - feedForward(inputs: number[]): { hiddenInputs: number[]; hiddenOutputs: number[] }; - query(inputs: number[]): number[]; + feedForward(inputs: number[]): { + hiddenInputs: Matrix2D; + hiddenOutputs: Matrix2D; + finalOutputs: Matrix2D; + }; + query(inputs: number[]): Matrix2D; } diff --git a/src/view/components/userQuery/AlignCanvas.ts b/src/view/components/userQuery/AlignCanvas.ts index 4809f51..691f45c 100644 --- a/src/view/components/userQuery/AlignCanvas.ts +++ b/src/view/components/userQuery/AlignCanvas.ts @@ -1,8 +1,8 @@ import BoundingBox from '../canvasUtils/BoundingBox.ts'; class AlignCanvas { - private readonly canvas: HTMLCanvasElement | null; - private readonly ctx: CanvasRenderingContext2D; + public readonly canvas: HTMLCanvasElement | null; + public readonly ctx: CanvasRenderingContext2D; constructor() { this.canvas = document.createElement('canvas') as HTMLCanvasElement; @@ -25,7 +25,7 @@ class AlignCanvas { } } - centralize(path: HTMLImageElement): void { + centralize(path: HTMLCanvasElement): void { this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); const alignStartPosition = { x: (this.canvas.width - BoundingBox.getOriginalObject().width) / 2, @@ -46,7 +46,7 @@ class AlignCanvas { clear(): void { this.canvas.width = this.canvas.height = 1; - this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.setupCanvas(); } } diff --git a/src/view/components/userQuery/PathTrackingCanvas.ts b/src/view/components/userQuery/PathTrackingCanvas.ts index f264489..72a4e07 100644 --- a/src/view/components/userQuery/PathTrackingCanvas.ts +++ b/src/view/components/userQuery/PathTrackingCanvas.ts @@ -1,8 +1,8 @@ import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class PathTrackingCanvas { - private readonly canvas: HTMLCanvasElement | null; - private readonly ctx: CanvasRenderingContext2D; + public readonly canvas: HTMLCanvasElement | null; + public readonly ctx: CanvasRenderingContext2D; constructor() { this.canvas = document.createElement('canvas') as HTMLCanvasElement; @@ -37,6 +37,10 @@ class PathTrackingCanvas { endPath(): void { this.ctx.closePath(); } + + clear(): void { + this.setupCanvas(); + } } export default PathTrackingCanvas; diff --git a/src/view/components/userQuery/ResizeCanvas.ts b/src/view/components/userQuery/ResizeCanvas.ts index 82b36b6..96a4275 100644 --- a/src/view/components/userQuery/ResizeCanvas.ts +++ b/src/view/components/userQuery/ResizeCanvas.ts @@ -1,22 +1,37 @@ class ResizeCanvas { - private readonly canvas: HTMLCanvasElement | null; - private readonly ctx: CanvasRenderingContext2D; + public readonly canvas: HTMLCanvasElement | null; + public readonly ctx: CanvasRenderingContext2D; constructor() { - this.canvas = document.createElement("canvas") as HTMLCanvasElement; - this.ctx = this.canvas.getContext("2d", { willReadFrequently: true }); - this.canvas.width = this.canvas.height = 28; + this.canvas = document.createElement('canvas') as HTMLCanvasElement; + this.ctx = this.canvas.getContext('2d', { willReadFrequently: true }); + this.setupCanvas(); } - downScale(path: HTMLImageElement): void { + setupCanvas(): void { + this.canvas.width = this.canvas.height = 28; this.ctx.fillStyle = 'rgba(255,255,255)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); - this.ctx.drawImage(path, 0, 0, path.width, path.height, 0, 0, this.canvas.width, this.canvas.height); + } + + downScale(path: HTMLCanvasElement): void { + this.ctx.drawImage( + path, + 0, + 0, + path.width, + path.height, + 0, + 0, + this.canvas.width, + this.canvas.height, + ); } clear(): void { - this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); + this.setupCanvas(); + // this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); } } -export default ResizeCanvas; \ No newline at end of file +export default ResizeCanvas; diff --git a/src/view/components/userQuery/UserInputCanvas.ts b/src/view/components/userQuery/UserInputCanvas.ts index 7da0f85..1c57361 100644 --- a/src/view/components/userQuery/UserInputCanvas.ts +++ b/src/view/components/userQuery/UserInputCanvas.ts @@ -1,8 +1,8 @@ import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; class UserInputCanvas { - private readonly canvas: HTMLCanvasElement | null; - private readonly ctx: CanvasRenderingContext2D; + public readonly canvas: HTMLCanvasElement | null; + public readonly ctx: CanvasRenderingContext2D; private isDrawing: boolean; constructor() { @@ -18,6 +18,7 @@ class UserInputCanvas { } clear = (): void => { + this.ctx.fillStyle = 'rgba(40,40,40)'; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.drawGridDots(); }; diff --git a/src/view/components/userQuery/types/canvas.ts b/src/view/components/userQuery/types/canvas.ts index 446c51c..7d0936a 100644 --- a/src/view/components/userQuery/types/canvas.ts +++ b/src/view/components/userQuery/types/canvas.ts @@ -20,4 +20,4 @@ export interface IAlignCanvas { export interface IResizeCanvas { downScale(path: HTMLCanvasElement): void; -} \ No newline at end of file +} From 43fae54acd772c8ec2f9338bcebfa27853474588 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 22:48:01 +0900 Subject: [PATCH 29/32] refactor: migration to Typescript --- src/controller/{AppController.js => AppController.ts} | 11 +++++++++-- src/core/types/WeightManager.ts | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) rename src/controller/{AppController.js => AppController.ts} (77%) create mode 100644 src/core/types/WeightManager.ts diff --git a/src/controller/AppController.js b/src/controller/AppController.ts similarity index 77% rename from src/controller/AppController.js rename to src/controller/AppController.ts index b1c3eb9..58a55ba 100644 --- a/src/controller/AppController.js +++ b/src/controller/AppController.ts @@ -11,8 +11,16 @@ import eventBus from './EventBus.ts'; import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.ts'; import { NETWORK_CONFIG } from './constants/networkConfig.ts'; import DrawingEventHandler from './queryPipeline/DrawingEventHandler.js'; +import { IWeightManager } from '../core/types/WeightManager.ts'; +import { INeuralNetworkBase } from '../core/types/NeuralNetworkBase.ts'; +import { IDataStore } from './types/DataStore.ts'; +import { Matrix2D } from '../core/ops/types/OpsType.ts'; class AppController { + private $WM: IWeightManager; + private $NN: INeuralNetworkBase; + private $DS: IDataStore; + async initialize() { const $WM = new WeightManager(NETWORK_CONFIG); const $NN = new NeuralNetworkBase(await $WM.getWeights()); @@ -26,8 +34,7 @@ class AppController { $NN: $NN, $DS: $DS, }); - eventBus.emit(HANDLER_EVENTS.APP_READY, this.dataStore); - eventBus.on(DATA_EVENTS.RESULT_CHANGED, (data) => { + eventBus.on(DATA_EVENTS.RESULT_CHANGED, (data: Matrix2D): void => { console.log('RESULT CHANGED', data); }); } diff --git a/src/core/types/WeightManager.ts b/src/core/types/WeightManager.ts new file mode 100644 index 0000000..5473e62 --- /dev/null +++ b/src/core/types/WeightManager.ts @@ -0,0 +1,9 @@ +import { weights } from '../../controller/types/weights.ts'; +import { networkConfig } from '../../controller/constants/types/networkConfig.ts'; + +export interface IWeightManager { + _cache: null | weights; + config: networkConfig; + path: string; + getWeights(): Promise; +} From 22e7c40f71db14d6a44ad82bd63cd9e3c37668d3 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 22:48:57 +0900 Subject: [PATCH 30/32] =?UTF-8?q?chore:=20canvas=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/constants/events.ts | 1 + .../queryPipeline/QueryProcessController.ts | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/controller/constants/events.ts b/src/controller/constants/events.ts index 7c6ad31..bf0e08c 100644 --- a/src/controller/constants/events.ts +++ b/src/controller/constants/events.ts @@ -17,6 +17,7 @@ export const DRAWING_EVENTS = Object.freeze({ START_DRAW: 'draw:start', DRAW: 'draw:drawing', END_DRAW: 'draw:end', + CLEAR_DRAW: 'draw:clear', BOUNDINGBOX_UPDATE: 'boundingbox:update', } as const); diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts index 55499f5..c33bc52 100644 --- a/src/controller/queryPipeline/QueryProcessController.ts +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -12,6 +12,8 @@ import { } from '../../view/components/userQuery/types/canvas'; import { INeuralNetworkBase } from '../../core/types/NeuralNetworkBase'; import { IDataStore } from '../types/DataStore'; +import { Matrix2D } from '../../core/ops/types/OpsType.ts'; +import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; class QueryProcessController { private readonly userInputCanvas: ICanvasBase & IUserInputCanvas; @@ -20,6 +22,8 @@ class QueryProcessController { private readonly resizeCanvas: ICanvasBase & IResizeCanvas; private readonly $NN: INeuralNetworkBase; private readonly $DS: IDataStore; + private readonly queryFrequencyMs: number; + //TODO: Canvas clear시 Skeleton 에니메이션 적용하기 constructor({ userInputCanvas, @@ -38,6 +42,7 @@ class QueryProcessController { this.$DS = $DS; this.registerDrawingEvent(); this.query(); + this.queryFrequencyMs = 200; } registerDrawingEvent(): void { @@ -57,13 +62,20 @@ class QueryProcessController { this.userInputCanvas.endPath(); this.trackingCanvas.endPath(); }); + eventBus.on(DRAWING_EVENTS.CLEAR_DRAW, () => { + this.userInputCanvas.clear(); + this.trackingCanvas.clear(); + this.alignCanvas.clear(); + this.resizeCanvas.clear(); + BoundingBox.reset(); + }); } query() { const throttleQuery = throttle((inputs) => { - const result: number[] = this.$NN.query(inputs); + const result: Matrix2D = this.$NN.query(inputs); if (result) eventBus.emit(DATA_EVENTS.RESULT_CHANGED, result); - }, 100); + }, this.queryFrequencyMs); eventBus.on(DATA_EVENTS.QUERY_CHANGED, (inputs: number[]) => throttleQuery(inputs)); // TODO: type interface 추가하기, 이벤트버스 구조와 쿼리 구조 다시 생각해보기, TS 마이그레이션 From c73fbc6251e82c6f393a0d5974b2ded614bf45d2 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sat, 16 Aug 2025 22:49:22 +0900 Subject: [PATCH 31/32] =?UTF-8?q?fix:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20type?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/types/DataStore.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/controller/types/DataStore.ts b/src/controller/types/DataStore.ts index e6b04f6..1d04382 100644 --- a/src/controller/types/DataStore.ts +++ b/src/controller/types/DataStore.ts @@ -1,3 +1,5 @@ +import { Matrix2D } from '../../core/ops/types/OpsType.ts'; + export interface IDataStore { setQueryInfo(queryInfo: number[]): void; getQueryInfo(): number[]; @@ -5,8 +7,8 @@ export interface IDataStore { setNodeState(nodeState: nodeState): void; getNodeState(): nodeState; - setQueryResult(queryResult: number[]): void; - getQueryResult(): number[]; + setQueryResult(queryResult: Matrix2D): void; + getQueryResult(): Matrix2D; } export interface nodeState { From c07e7483977165283ff720d62e02487a011e69a6 Mon Sep 17 00:00:00 2001 From: Sunwoo Ha Date: Sun, 17 Aug 2025 00:22:48 +0900 Subject: [PATCH 32/32] =?UTF-8?q?chore:=20path=20alias=20=EC=A7=80?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jsconfig.json | 4 ++-- src/controller/AppController.ts | 18 +++++++++--------- src/controller/DataStore.ts | 2 +- .../queryPipeline/DrawingEventHandler.ts | 2 +- .../queryPipeline/QueryProcessController.ts | 8 ++++---- src/controller/queryPipeline/pixelExtractor.ts | 2 +- .../types/QueryProcessController.ts | 6 +++--- src/controller/types/DataStore.ts | 2 +- src/controller/types/eventBus.ts | 2 +- src/core/NeuralNetworkBase.ts | 6 +++--- src/core/WeightManager.ts | 4 ++-- src/core/types/NeuralNetworkBase.ts | 2 +- src/core/types/WeightManager.ts | 4 ++-- src/core/utils/loadPretrainedWeights.ts | 2 +- .../components/userQuery/PathTrackingCanvas.ts | 2 +- .../components/userQuery/UserInputCanvas.ts | 2 +- tsconfig.json | 6 +++++- vite.config.ts | 5 ++++- 18 files changed, 43 insertions(+), 36 deletions(-) diff --git a/jsconfig.json b/jsconfig.json index 0afe90a..1286948 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "baseUrl": "src", + "baseUrl": "./src", "paths": { - "@/*": ["./*"] + "@/*": ["*"] } }, "include": ["src"] diff --git a/src/controller/AppController.ts b/src/controller/AppController.ts index 58a55ba..1d24875 100644 --- a/src/controller/AppController.ts +++ b/src/controller/AppController.ts @@ -1,20 +1,20 @@ -import WeightManager from '../core/WeightManager.ts'; -import NeuralNetworkBase from '../core/NeuralNetworkBase.ts'; +import WeightManager from '@/core/WeightManager.ts'; +import NeuralNetworkBase from '@/core/NeuralNetworkBase.ts'; import QueryProcessController from './queryPipeline/QueryProcessController.ts'; -import UserInputCanvas from '../view/components/userQuery/UserInputCanvas.ts'; -import PathTrackingCanvas from '../view/components/userQuery/PathTrackingCanvas.ts'; -import AlignCanvas from '../view/components/userQuery/AlignCanvas.ts'; -import ResizeCanvas from '../view/components/userQuery/ResizeCanvas.ts'; +import UserInputCanvas from '@/view/components/userQuery/UserInputCanvas.ts'; +import PathTrackingCanvas from '@/view/components/userQuery/PathTrackingCanvas.ts'; +import AlignCanvas from '@/view/components/userQuery/AlignCanvas.ts'; +import ResizeCanvas from '@/view/components/userQuery/ResizeCanvas.ts'; import DataStore from './DataStore.ts'; import eventBus from './EventBus.ts'; import { DATA_EVENTS, HANDLER_EVENTS } from './constants/events.ts'; import { NETWORK_CONFIG } from './constants/networkConfig.ts'; import DrawingEventHandler from './queryPipeline/DrawingEventHandler.js'; -import { IWeightManager } from '../core/types/WeightManager.ts'; -import { INeuralNetworkBase } from '../core/types/NeuralNetworkBase.ts'; +import { IWeightManager } from '@/core/types/WeightManager.ts'; +import { INeuralNetworkBase } from '@/core/types/NeuralNetworkBase.ts'; import { IDataStore } from './types/DataStore.ts'; -import { Matrix2D } from '../core/ops/types/OpsType.ts'; +import { Matrix2D } from '@/core/ops/types/OpsType.ts'; class AppController { private $WM: IWeightManager; diff --git a/src/controller/DataStore.ts b/src/controller/DataStore.ts index 0b0d47c..556ab6c 100644 --- a/src/controller/DataStore.ts +++ b/src/controller/DataStore.ts @@ -2,7 +2,7 @@ import eventBus from './EventBus.js'; import { DATA_EVENTS } from './constants/events.js'; import { nodeState } from './types/DataStore'; -import { Matrix2D } from '../core/ops/types/OpsType.ts'; +import { Matrix2D } from '@/core/ops/types/OpsType.ts'; class DataStore { private queryInfo: number[] | null = null; diff --git a/src/controller/queryPipeline/DrawingEventHandler.ts b/src/controller/queryPipeline/DrawingEventHandler.ts index 44905ff..d64076c 100644 --- a/src/controller/queryPipeline/DrawingEventHandler.ts +++ b/src/controller/queryPipeline/DrawingEventHandler.ts @@ -1,4 +1,4 @@ -import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; +import BoundingBox from '@/view/components/canvasUtils/BoundingBox.ts'; import eventBus from '../EventBus.ts'; import { DRAWING_EVENTS } from '../constants/events.ts'; diff --git a/src/controller/queryPipeline/QueryProcessController.ts b/src/controller/queryPipeline/QueryProcessController.ts index c33bc52..eddbb2f 100644 --- a/src/controller/queryPipeline/QueryProcessController.ts +++ b/src/controller/queryPipeline/QueryProcessController.ts @@ -9,11 +9,11 @@ import { IPathTrackingCanvas, IAlignCanvas, IResizeCanvas, -} from '../../view/components/userQuery/types/canvas'; -import { INeuralNetworkBase } from '../../core/types/NeuralNetworkBase'; +} from '@/view/components/userQuery/types/canvas'; +import { INeuralNetworkBase } from '@/core/types/NeuralNetworkBase'; import { IDataStore } from '../types/DataStore'; -import { Matrix2D } from '../../core/ops/types/OpsType.ts'; -import BoundingBox from '../../view/components/canvasUtils/BoundingBox.ts'; +import { Matrix2D } from '@/core/ops/types/OpsType.ts'; +import BoundingBox from '@/view/components/canvasUtils/BoundingBox.ts'; class QueryProcessController { private readonly userInputCanvas: ICanvasBase & IUserInputCanvas; diff --git a/src/controller/queryPipeline/pixelExtractor.ts b/src/controller/queryPipeline/pixelExtractor.ts index 1f43ba4..3e37ef1 100644 --- a/src/controller/queryPipeline/pixelExtractor.ts +++ b/src/controller/queryPipeline/pixelExtractor.ts @@ -1,4 +1,4 @@ -import { IResizeCanvas, ICanvasBase } from '../../view/components/userQuery/types/canvas'; +import { IResizeCanvas, ICanvasBase } from '@/view/components/userQuery/types/canvas'; export const pixelExtractor = (path: IResizeCanvas & ICanvasBase) => { const pathToMatrix = (width: number, height: number, data: Uint8ClampedArray): object[] => { diff --git a/src/controller/queryPipeline/types/QueryProcessController.ts b/src/controller/queryPipeline/types/QueryProcessController.ts index b549161..e43c0bb 100644 --- a/src/controller/queryPipeline/types/QueryProcessController.ts +++ b/src/controller/queryPipeline/types/QueryProcessController.ts @@ -4,9 +4,9 @@ import { IPathTrackingCanvas, IAlignCanvas, IResizeCanvas, -} from '../../../view/components/userQuery/types/canvas'; -import { INeuralNetworkBase } from '../../../core/types/NeuralNetworkBase'; -import { IDataStore } from '../../types/DataStore'; +} from '@/view/components/userQuery/types/canvas'; +import { INeuralNetworkBase } from '@/core/types/NeuralNetworkBase'; +import { IDataStore } from '@/controller/types/DataStore'; export interface IQueryProcessControllerProps { userInputCanvas: ICanvasBase & IUserInputCanvas; diff --git a/src/controller/types/DataStore.ts b/src/controller/types/DataStore.ts index 1d04382..cff00ae 100644 --- a/src/controller/types/DataStore.ts +++ b/src/controller/types/DataStore.ts @@ -1,4 +1,4 @@ -import { Matrix2D } from '../../core/ops/types/OpsType.ts'; +import { Matrix2D } from '@/core/ops/types/OpsType.ts'; export interface IDataStore { setQueryInfo(queryInfo: number[]): void; diff --git a/src/controller/types/eventBus.ts b/src/controller/types/eventBus.ts index 0697741..7c302ac 100644 --- a/src/controller/types/eventBus.ts +++ b/src/controller/types/eventBus.ts @@ -1,4 +1,4 @@ -import { Matrix2D } from '../../core/ops/types/OpsType'; +import { Matrix2D } from '@/core/ops/types/OpsType'; export interface eventPayloads { // Data handling event diff --git a/src/core/NeuralNetworkBase.ts b/src/core/NeuralNetworkBase.ts index 9796c0f..3f1cc6e 100644 --- a/src/core/NeuralNetworkBase.ts +++ b/src/core/NeuralNetworkBase.ts @@ -1,9 +1,9 @@ import activationFunction from './ops/activationOps.js'; import { matrixMultiply } from './ops/matrixOps.js'; -import eventBus from '../controller/EventBus.js'; -import { DATA_EVENTS } from '../controller/constants/events.js'; +import eventBus from '@/controller/EventBus.js'; +import { DATA_EVENTS } from '@/controller/constants/events.js'; -import { weights } from '../controller/types/weights'; +import { weights } from '@/controller/types/weights'; import { Matrix2D } from './ops/types/OpsType'; class NeuralNetworkBase { diff --git a/src/core/WeightManager.ts b/src/core/WeightManager.ts index 1c42a93..29aa62d 100644 --- a/src/core/WeightManager.ts +++ b/src/core/WeightManager.ts @@ -1,8 +1,8 @@ import { createRandomWeight } from './utils/createRandomWeights.js'; import { loadPretrainedWeights } from './utils/loadPretrainedWeights.js'; -import { networkConfig } from '../controller/constants/types/networkConfig'; +import { networkConfig } from '@/controller/constants/types/networkConfig'; -import { weights } from '../controller/types/weights'; +import { weights } from '@/controller/types/weights'; class WeightManager { private _cache: null | weights = null; diff --git a/src/core/types/NeuralNetworkBase.ts b/src/core/types/NeuralNetworkBase.ts index 98a66e9..0c15bab 100644 --- a/src/core/types/NeuralNetworkBase.ts +++ b/src/core/types/NeuralNetworkBase.ts @@ -1,4 +1,4 @@ -import { Matrix2D } from '../ops/types/OpsType.ts'; +import { Matrix2D } from '@/core/ops/types/OpsType.ts'; export interface INeuralNetworkBase { feedForward(inputs: number[]): { diff --git a/src/core/types/WeightManager.ts b/src/core/types/WeightManager.ts index 5473e62..5fd417f 100644 --- a/src/core/types/WeightManager.ts +++ b/src/core/types/WeightManager.ts @@ -1,5 +1,5 @@ -import { weights } from '../../controller/types/weights.ts'; -import { networkConfig } from '../../controller/constants/types/networkConfig.ts'; +import { weights } from '@/controller/types/weights.ts'; +import { networkConfig } from '@/controller/constants/types/networkConfig.ts'; export interface IWeightManager { _cache: null | weights; diff --git a/src/core/utils/loadPretrainedWeights.ts b/src/core/utils/loadPretrainedWeights.ts index d10d0e1..3e89e03 100644 --- a/src/core/utils/loadPretrainedWeights.ts +++ b/src/core/utils/loadPretrainedWeights.ts @@ -1,4 +1,4 @@ -import { weights } from '../../controller/types/weights'; +import { weights } from '@/controller/types/weights'; export async function loadPretrainedWeights(path: string): Promise { const response: Response = await fetch(path); diff --git a/src/view/components/userQuery/PathTrackingCanvas.ts b/src/view/components/userQuery/PathTrackingCanvas.ts index 72a4e07..bd2b4b2 100644 --- a/src/view/components/userQuery/PathTrackingCanvas.ts +++ b/src/view/components/userQuery/PathTrackingCanvas.ts @@ -1,4 +1,4 @@ -import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; +import { CANVAS_CONFIG } from '@/controller/constants/canvasConfig.ts'; class PathTrackingCanvas { public readonly canvas: HTMLCanvasElement | null; diff --git a/src/view/components/userQuery/UserInputCanvas.ts b/src/view/components/userQuery/UserInputCanvas.ts index 1c57361..564819a 100644 --- a/src/view/components/userQuery/UserInputCanvas.ts +++ b/src/view/components/userQuery/UserInputCanvas.ts @@ -1,4 +1,4 @@ -import { CANVAS_CONFIG } from '../../../controller/constants/canvasConfig.ts'; +import { CANVAS_CONFIG } from '@/controller/constants/canvasConfig.ts'; class UserInputCanvas { public readonly canvas: HTMLCanvasElement | null; diff --git a/tsconfig.json b/tsconfig.json index 592c17f..e5e1ea1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,11 @@ "strict": false, "allowJs": true, "checkJs": false, - "esModuleInterop": true + "esModuleInterop": true, + "baseUrl": "./src", + "paths": { + "@/*": ["*"] + } }, "include": ["src/**/*"] } diff --git a/vite.config.ts b/vite.config.ts index 58a9b50..1f6b4b0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,10 @@ import { defineConfig } from 'vite'; export default defineConfig({ - root: '.', // 기본값, 생략 가능 + root: './src', + resolve: { + alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }], + }, publicDir: 'public', build: { outDir: 'dist',