diff --git a/cognee-frontend/package-lock.json b/cognee-frontend/package-lock.json index 18f3b0e25..8b39a240c 100644 --- a/cognee-frontend/package-lock.json +++ b/cognee-frontend/package-lock.json @@ -12,11 +12,14 @@ "classnames": "^2.5.1", "culori": "^4.0.1", "d3-force-3d": "^3.0.6", - "next": "^16.1.0", - "react": "^19.2.3", - "react-dom": "^19.2.3", + "next": "15.3.3", + "ngraph.forcelayout": "^3.3.1", + "ngraph.graph": "^20.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", "react-force-graph-2d": "^1.27.1", - "react-markdown": "^10.1.0", + "three": "^0.175.0", + "troika-three-text": "^0.52.4", "uuid": "^9.0.1" }, "devDependencies": { @@ -24,8 +27,9 @@ "@tailwindcss/postcss": "^4.1.7", "@types/culori": "^4.0.0", "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/three": "^0.175.0", "@types/uuid": "^9.0.8", "eslint": "^9", "eslint-config-next": "^16.0.4", @@ -1678,11 +1682,31 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "dev": true + }, + "node_modules/@types/three": { + "version": "0.175.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.175.0.tgz", + "integrity": "sha512-ldMSBgtZOZ3g9kJ3kOZSEtZIEITmJOzu8eKVpkhf036GuNkM4mt0NXecrjCn5tMm1OblOF7dZehlaDypBfNokw==", + "dev": true, + "dependencies": { + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": "*", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~0.18.1" + } + }, + "node_modules/@types/three/node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "dev": true }, "node_modules/@types/uuid": { "version": "9.0.8", @@ -1691,6 +1715,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.48.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", @@ -2237,6 +2267,12 @@ "win32" ] }, + "node_modules/@webgpu/types": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.66.tgz", + "integrity": "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA==", + "dev": true + }, "node_modules/accessor-fn": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz", @@ -2569,6 +2605,14 @@ "url": "https://github.com/Pomax/bezierjs/blob/master/FUNDING.md" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -4031,6 +4075,12 @@ "reusify": "^1.0.4" } }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -5763,447 +5813,11 @@ "node": ">= 8" } }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" + "node_modules/meshoptimizer": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz", + "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==", + "dev": true }, "node_modules/micromatch": { "version": "4.0.8", @@ -6371,12 +5985,38 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" + "node_modules/ngraph.events": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.4.0.tgz", + "integrity": "sha512-NeDGI4DSyjBNBRtA86222JoYietsmCXbs8CEB0dZ51Xeh4lhVl1y3wpWLumczvnha8sFQIW4E0vvVWwgmX2mGw==" + }, + "node_modules/ngraph.forcelayout": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ngraph.forcelayout/-/ngraph.forcelayout-3.3.1.tgz", + "integrity": "sha512-MKBuEh1wujyQHFTW57y5vd/uuEOK0XfXYxm3lC7kktjJLRdt/KEKEknyOlc6tjXflqBKEuYBBcu7Ax5VY+S6aw==", + "dependencies": { + "ngraph.events": "^1.0.0", + "ngraph.merge": "^1.0.0", + "ngraph.random": "^1.0.0" + } + }, + "node_modules/ngraph.graph": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/ngraph.graph/-/ngraph.graph-20.1.0.tgz", + "integrity": "sha512-1jorNgIc0Kg0L9bTNN4+RCrVvbZ+4pqGVMrbhX3LLyqYcRdLvAQRRnxddmfj9l5f6Eq59SUTfbYZEm8cktiE7Q==", + "dependencies": { + "ngraph.events": "^1.2.1" + } + }, + "node_modules/ngraph.merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ngraph.merge/-/ngraph.merge-1.0.0.tgz", + "integrity": "sha512-5J8YjGITUJeapsomtTALYsw7rFveYkM+lBj3QiYZ79EymQcuri65Nw3knQtFxQBU1r5iOaVRXrSwMENUPK62Vg==" + }, + "node_modules/ngraph.random": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ngraph.random/-/ngraph.random-1.2.0.tgz", + "integrity": "sha512-4EUeAGbB2HWX9njd6bP6tciN6ByJfoaAvmVL9QTaZSeXrW46eNGA9GajiXiPBbvFqxUWFkEbyo6x5qsACUuVfA==" }, "node_modules/oauth4webapi": { "version": "3.8.3", @@ -6917,37 +6557,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "license": "MIT", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/resolve": { @@ -7594,6 +7209,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/three": { + "version": "0.175.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.175.0.tgz", + "integrity": "sha512-nNE3pnTHxXN/Phw768u0Grr7W4+rumGg/H6PgeseNJojkJtmeHJfZWi41Gp2mpXl1pg1pf1zjwR4McM1jTqkpg==", + "license": "MIT" + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -7662,26 +7283,33 @@ "node": ">=8.0" } }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/troika-three-text": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz", + "integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==", + "dependencies": { + "bidi-js": "^1.0.2", + "troika-three-utils": "^0.52.4", + "troika-worker-utils": "^0.52.0", + "webgl-sdf-generator": "1.1.1" + }, + "peerDependencies": { + "three": ">=0.125.0" } }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/troika-three-utils": { + "version": "0.52.4", + "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz", + "integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==", + "peerDependencies": { + "three": ">=0.125.0" } }, + "node_modules/troika-worker-utils": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz", + "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==" + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -8068,33 +7696,10 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "node_modules/webgl-sdf-generator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", + "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" }, "node_modules/which": { "version": "2.0.2", diff --git a/cognee-frontend/package.json b/cognee-frontend/package.json index d1ac82f6f..1a28ac7bb 100644 --- a/cognee-frontend/package.json +++ b/cognee-frontend/package.json @@ -13,11 +13,14 @@ "classnames": "^2.5.1", "culori": "^4.0.1", "d3-force-3d": "^3.0.6", - "next": "^16.1.7", - "react": "^19.2.3", - "react-dom": "^19.2.3", + "next": "15.3.3", + "ngraph.forcelayout": "^3.3.1", + "ngraph.graph": "^20.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", "react-force-graph-2d": "^1.27.1", - "react-markdown": "^10.1.0", + "three": "^0.175.0", + "troika-three-text": "^0.52.4", "uuid": "^9.0.1" }, "devDependencies": { @@ -25,8 +28,9 @@ "@tailwindcss/postcss": "^4.1.7", "@types/culori": "^4.0.0", "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/three": "^0.175.0", "@types/uuid": "^9.0.8", "eslint": "^9", "eslint-config-next": "^16.0.4", diff --git a/cognee-frontend/src/app/dashboard/DatasetsAccordion.tsx b/cognee-frontend/src/app/dashboard/DatasetsAccordion.tsx index 69cdbc277..3ce125fc8 100644 --- a/cognee-frontend/src/app/dashboard/DatasetsAccordion.tsx +++ b/cognee-frontend/src/app/dashboard/DatasetsAccordion.tsx @@ -1,5 +1,6 @@ "use client"; +import Link from "next/link"; import { ChangeEvent, useCallback, useEffect, useState } from "react"; import { useBoolean } from "@/utils"; import { Accordion, CTAButton, GhostButton, IconButton, Input, Modal, PopupMenu } from "@/ui/elements"; @@ -258,15 +259,12 @@ export default function DatasetsAccordion({ tools={( -
-
- - add data -
-
-
-
handleDatasetRemove(dataset)} className="hover:bg-gray-100 w-full text-left px-2 cursor-pointer">delete
+
+ + add data
+ visualize +
handleDatasetRemove(dataset)} className="hover:bg-gray-100 w-full text-left px-2 cursor-pointer">delete
)} diff --git a/cognee-frontend/src/app/visualize/[datasetId]/page.tsx b/cognee-frontend/src/app/visualize/[datasetId]/page.tsx new file mode 100644 index 000000000..7936320b3 --- /dev/null +++ b/cognee-frontend/src/app/visualize/[datasetId]/page.tsx @@ -0,0 +1,95 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { fetch } from "@/utils"; +import { adaptCogneeGraphData, validateCogneeGraphResponse } from "@/lib/adaptCogneeGraphData"; +import { CogneeGraphResponse } from "@/types/CogneeAPI"; +import MemoryGraphVisualization from "@/ui/elements/MemoryGraphVisualization"; +import { Edge, Node } from "@/ui/rendering/graph/types"; + +interface VisualizePageProps { + params: { datasetId: string }; +} + +export default function Page({ params }: VisualizePageProps) { + const [graphData, setGraphData] = useState<{ nodes: Node[], edges: Edge[] } | null>(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function getData() { + try { + setLoading(true); + setError(null); + + const datasetId = (await params).datasetId; + const response = await fetch(`/v1/datasets/${datasetId}/graph`); + + if (!response.ok) { + throw new Error(`Failed to fetch graph data: ${response.statusText}`); + } + + const apiData = await response.json(); + + // Validate API response + if (!validateCogneeGraphResponse(apiData)) { + throw new Error("Invalid graph data format from API"); + } + + // Adapt Cognee API format to visualization format + const adaptedData = adaptCogneeGraphData(apiData as CogneeGraphResponse); + setGraphData(adaptedData); + } catch (err) { + console.error("Error loading graph data:", err); + setError(err instanceof Error ? err.message : "Unknown error"); + } finally { + setLoading(false); + } + } + getData(); + }, [params]); + + if (loading) { + return ( +
+
+
βš›οΈ
+
Loading graph data...
+
+
+ ); + } + + if (error) { + return ( +
+
+
⚠️
+
Error Loading Graph
+
{error}
+
+
+ ); + } + + if (!graphData || graphData.nodes.length === 0) { + return ( +
+
+
πŸ“Š
+
No Graph Data
+
This dataset has no graph data to visualize.
+
+
+ ); + } + + return ( + + ); +} diff --git a/cognee-frontend/src/app/visualize/demo/README.md b/cognee-frontend/src/app/visualize/demo/README.md new file mode 100644 index 000000000..ea5fa304e --- /dev/null +++ b/cognee-frontend/src/app/visualize/demo/README.md @@ -0,0 +1,184 @@ +# Graph Visualization Demo + +An isolated, interactive demo of Cognee's Three.js-based graph visualization with a rich AI/ML knowledge graph dataset. + +## Features + +### 🎨 Visual Design +- **Vibrant Color Palette**: 10 distinct colors for different node types +- **Dark Theme**: Optimized background (#0a0a0f) for maximum contrast +- **Metaball Rendering**: Smooth, organic blob visualization of node clusters +- **Responsive Labels**: Context-aware labels that appear on hover and zoom + +### 🎯 Interactive Controls +- **Pan**: Click and drag to move around the graph +- **Zoom**: Scroll to zoom in (6x max) or out (0.5x min) +- **Hover**: Mouse over nodes to see labels and connections +- **Click**: Select nodes to highlight their relationships +- **Smooth Animation**: Fluid camera motion with optimized damping + +### πŸ“Š UI Components +- **Legend Panel**: Categorizes nodes by type with color coding +- **Statistics**: Real-time graph metrics (nodes, edges, connections) +- **Instructions Overlay**: Quick reference for interaction methods +- **Toggle Controls**: Show/hide legend and stats as needed + +## Dataset + +The demo includes a comprehensive **AI/ML Knowledge Graph** with: + +### Node Types (52 total) +- **Concepts** (6): AI, Machine Learning, Deep Learning, NLP, CV, RL +- **Algorithms** (10): SVM, Decision Trees, K-Means, Q-Learning, etc. +- **Architectures** (12): CNN, RNN, Transformer, GAN, VAE, etc. +- **Technologies** (9): BERT, GPT, ResNet, YOLO, Word2Vec, etc. +- **Applications** (5): Chatbots, Autonomous Vehicles, Medical Imaging, etc. +- **Data** (4): Datasets, Feature Engineering, Augmentation, Normalization +- **Optimization** (5): Gradient Descent, Adam, Backprop, Regularization, Dropout + +### Relationships (56 edges) +- Hierarchical: "is subfield of", "type of", "variant of" +- Functional: "implements", "uses", "powered by", "trains" +- Application: "application of", "task in", "used in" + +## Technical Implementation + +### Architecture +``` +GraphVisualization Component + ↓ +animate.ts (Main Render Loop) + ↓ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Graph Layout β”‚ Rendering β”‚ Interaction β”‚ +β”‚ (ngraph) β”‚ (Three.js) β”‚ (Picking) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β€’ Force layout β”‚ β€’ Node swarm β”‚ β€’ Mouse hover β”‚ +β”‚ β€’ 800 iterationsβ”‚ β€’ Edge mesh β”‚ β€’ Click select β”‚ +β”‚ β€’ Spring physicsβ”‚ β€’ Metaballs β”‚ β€’ Label display β”‚ +β”‚ β”‚ β€’ Density cloud β”‚ β€’ Pan/Zoom β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Performance Optimizations +- **GPU-Accelerated**: All rendering uses WebGL shaders +- **Instanced Rendering**: Nodes rendered in a single draw call +- **Texture-Based Positions**: Node positions stored in GPU texture +- **Culling**: Labels only shown for visible/hovered nodes +- **Adaptive Layout**: Physics stabilizes after initial iterations + +### Scalability +The implementation is designed to handle: +- βœ… **100+ nodes**: Excellent performance +- βœ… **500+ nodes**: Good performance with metaballs +- βœ… **1000+ nodes**: Recommended to reduce metaball density +- ⚠️ **5000+ nodes**: Consider simplified rendering mode + +## Configuration Options + +The visualization accepts a `config` prop: + +```typescript +config={{ + fontSize: 12, // Label font size (default: 10) +}} +``` + +### Force Layout Parameters (in animate.ts) +```typescript +{ + dragCoefficient: 0.8, // Node movement resistance + springLength: 180, // Ideal distance between connected nodes + springCoefficient: 0.25, // Connection strength + gravity: -1200, // Repulsion force +} +``` + +### Camera Controls +```typescript +{ + minZoom: 0.5, // Maximum zoom out + maxZoom: 6, // Maximum zoom in + dampingFactor: 0.08, // Camera smoothness +} +``` + +## How to Use in Development + +1. **Start the frontend**: + ```bash + cd cognee-frontend + npm run dev + ``` + +2. **Navigate to the demo**: + ``` + http://localhost:3000/visualize/demo + ``` + +3. **Interact with the graph**: + - Hover over nodes to see labels + - Zoom in to see more connections + - Click to select nodes + - Toggle legend/stats panels + +## Extending the Demo + +### Add More Nodes +```typescript +mockNodes.push({ + id: "new-concept", + label: "New Concept", + type: "Concept" +}); +``` + +### Add Connections +```typescript +mockEdges.push({ + id: "e-new", + source: "new-concept", + target: "ai", + label: "related to" +}); +``` + +### Customize Colors +Update the `typeColors` mapping in the demo page: +```typescript +const typeColors: Record = { + "YourType": "#YOUR_COLOR", + // ... +}; +``` + +## Future Enhancements + +Potential improvements: +- [ ] Search functionality to find and highlight nodes +- [ ] Filter nodes by type +- [ ] Export graph as image/SVG +- [ ] Node clustering by community detection +- [ ] Time-based animation of graph evolution +- [ ] 3D visualization mode +- [ ] Multi-graph comparison view + +## Related Files + +- `src/ui/elements/GraphVisualization.tsx` - Main component wrapper +- `src/ui/rendering/animate.ts` - Render loop and Three.js setup +- `src/ui/rendering/graph/createGraph.ts` - Graph creation from data +- `src/ui/rendering/materials/` - Shader materials for visual effects +- `src/ui/rendering/meshes/` - Mesh generation for nodes/edges/labels + +## Performance Tips + +For large graphs (1000+ nodes): +1. Reduce `densityCloudTarget` resolution (line 135 in animate.ts) +2. Decrease label display limit (line 372) +3. Consider disabling metaball rendering for very large graphs +4. Use node clustering/aggregation for massive datasets + +## License + +Part of the Cognee project - Apache 2.0 License diff --git a/cognee-frontend/src/app/visualize/demo/page.tsx b/cognee-frontend/src/app/visualize/demo/page.tsx new file mode 100644 index 000000000..58af7700b --- /dev/null +++ b/cognee-frontend/src/app/visualize/demo/page.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { useState, useMemo } from "react"; +import { generateOntologyGraph } from "@/lib/generateOntologyGraph"; +import MemoryGraphVisualization from "@/ui/elements/MemoryGraphVisualization"; + +type GraphMode = "small" | "medium" | "large"; + +export default function VisualizationDemoPage() { + const [graphMode, setGraphMode] = useState("medium"); + const [isGenerating, setIsGenerating] = useState(false); + + // Generate graph based on mode + const { nodes, edges } = useMemo(() => { + console.log(`Generating ${graphMode} ontology graph...`); + setIsGenerating(true); + + let result; + switch (graphMode) { + case "small": + result = { ...generateOntologyGraph("simple"), clusters: new Map() }; + break; + case "medium": + result = generateOntologyGraph("medium"); + break; + case "large": + result = generateOntologyGraph("complex"); + break; + } + + setTimeout(() => setIsGenerating(false), 500); + return result; + }, [graphMode]); + + return ( +
+ {isGenerating ? ( +
+
+
+
βš›οΈ
+
βš›οΈ
+
+
+ Building Knowledge Graph... +
+
+ Creating { + graphMode === "small" ? "~500" : + graphMode === "medium" ? "~1,000" : + "~1,500" + } interconnected nodes +
+
+
+ ) : null} + + {/* Mode Selector Overlay */} +
+
+ {(["small", "medium", "large"] as GraphMode[]).map((mode) => ( + + ))} +
+
+ + +
+ ); +} diff --git a/cognee-frontend/src/types/CogneeAPI.ts b/cognee-frontend/src/types/CogneeAPI.ts new file mode 100644 index 000000000..71a6e95ae --- /dev/null +++ b/cognee-frontend/src/types/CogneeAPI.ts @@ -0,0 +1,45 @@ +/** + * Type definitions for Cognee API responses + * Based on Cognee SDK data point model and graph API + */ + +/** + * Cognee DataPoint representation from API + * Corresponds to: cognee/infrastructure/engine/models/DataPoint.py + */ +export interface CogneeDataPoint { + id: string; // UUID + label: string; // Display name + type: string; // Node type (Entity, EntityType, DocumentChunk, etc.) + properties?: Record; // Additional metadata +} + +/** + * Cognee Edge representation from API + * Corresponds to: cognee/infrastructure/engine/models/Edge.py + */ +export interface CogneeEdge { + source: string; // Source node UUID + target: string; // Target node UUID + label: string; // Relationship type + weight?: number; // Optional weight + weights?: Record; // Optional multiple weights + properties?: Record; // Additional properties +} + +/** + * Cognee Graph API response format + * From: /api/v1/datasets/{dataset_id}/graph + */ +export interface CogneeGraphResponse { + nodes: CogneeDataPoint[]; + edges: CogneeEdge[]; +} + +/** + * Cognee API error response + */ +export interface CogneeAPIError { + detail: string; + status_code: number; +} diff --git a/cognee-frontend/src/types/NodeSet.ts b/cognee-frontend/src/types/NodeSet.ts new file mode 100644 index 000000000..1e06961db --- /dev/null +++ b/cognee-frontend/src/types/NodeSet.ts @@ -0,0 +1,165 @@ +/** + * Node Sets: The primary abstraction for grouping nodes + * Replaces fixed types with dynamic, inferred, overlapping groups + */ + +export type NodeSetSource = + | "model-inferred" // Created by AI/ML model + | "user-defined" // Manually created by user + | "query-result" // Result of a search query + | "imported" // From external source + | "set-algebra"; // Created by combining other sets + +export type NodeSetStability = + | "stable" // Won't change often + | "evolving" // Changes gradually + | "ephemeral"; // Temporary, will be removed + +export interface NodeSet { + id: string; + name: string; + description?: string; + + // Required properties + nodeIds: string[]; // Member node IDs + size: number; // Number of nodes + definition: string; // How it was created (e.g., "semantic cluster around 'AI'") + stability: NodeSetStability; + source: NodeSetSource; + lastUpdated: Date; + + // Confidence metrics + confidence?: number; // 0-1, how confident we are in this grouping + cohesion?: number; // 0-1, how tightly connected members are + + // Set algebra metadata + parentSets?: string[]; // If created from other sets + operation?: "union" | "intersect" | "diff"; + + // Retrieval metadata + retrievalScore?: number; // If this set was retrieved + retrievalSignals?: string[]; // Why it was retrieved + + // Visual properties (for rendering) + color?: string; + visible?: boolean; +} + +/** + * Set operations + */ +export function unionSets(sets: NodeSet[], name: string): NodeSet { + const allNodeIds = new Set(); + sets.forEach(set => set.nodeIds.forEach(id => allNodeIds.add(id))); + + return { + id: `union_${Date.now()}`, + name, + nodeIds: Array.from(allNodeIds), + size: allNodeIds.size, + definition: `Union of: ${sets.map(s => s.name).join(", ")}`, + stability: "ephemeral", + source: "set-algebra", + lastUpdated: new Date(), + parentSets: sets.map(s => s.id), + operation: "union", + }; +} + +export function intersectSets(sets: NodeSet[], name: string): NodeSet { + if (sets.length === 0) { + return { + id: `intersect_${Date.now()}`, + name, + nodeIds: [], + size: 0, + definition: "Empty intersection", + stability: "ephemeral", + source: "set-algebra", + lastUpdated: new Date(), + }; + } + + const intersection = new Set(sets[0].nodeIds); + sets.slice(1).forEach(set => { + const setIds = new Set(set.nodeIds); + intersection.forEach(id => { + if (!setIds.has(id)) intersection.delete(id); + }); + }); + + return { + id: `intersect_${Date.now()}`, + name, + nodeIds: Array.from(intersection), + size: intersection.size, + definition: `Intersection of: ${sets.map(s => s.name).join(", ")}`, + stability: "ephemeral", + source: "set-algebra", + lastUpdated: new Date(), + parentSets: sets.map(s => s.id), + operation: "intersect", + }; +} + +export function diffSets(setA: NodeSet, setB: NodeSet, name: string): NodeSet { + const diff = new Set(setA.nodeIds); + setB.nodeIds.forEach(id => diff.delete(id)); + + return { + id: `diff_${Date.now()}`, + name, + nodeIds: Array.from(diff), + size: diff.size, + definition: `${setA.name} minus ${setB.name}`, + stability: "ephemeral", + source: "set-algebra", + lastUpdated: new Date(), + parentSets: [setA.id, setB.id], + operation: "diff", + }; +} + +/** + * Retrieval result with explanation + */ +export interface RetrievalResult { + type: "node" | "nodeSet" | "suggestedSet"; + + // For nodes + nodeId?: string; + nodeLabel?: string; + + // For node sets + nodeSet?: NodeSet; + + // For suggested sets + suggestedSetDefinition?: string; + suggestedNodeIds?: string[]; + + // Explanation (critical for trust) + why: string; // Human-readable explanation + similarityScore: number; // 0-1 + signals: { + name: string; // e.g., "semantic", "recency", "provenance" + weight: number; // Contribution to final score + value: string | number; // The actual value + }[]; + + // Confidence + confidence: number; // 0-1, how confident we are in this retrieval +} + +/** + * Recall simulation: "If the agent were asked X, what would be retrieved?" + */ +export interface RecallSimulation { + query: string; + rankedMemories: RetrievalResult[]; + activatedSets: NodeSet[]; + conflicts?: { + nodeId: string; + reason: string; + conflictingSets: string[]; + }[]; +} diff --git a/cognee-frontend/src/ui/elements/GraphVisualization.tsx b/cognee-frontend/src/ui/elements/GraphVisualization.tsx new file mode 100644 index 000000000..cd1793bae --- /dev/null +++ b/cognee-frontend/src/ui/elements/GraphVisualization.tsx @@ -0,0 +1,61 @@ +"use client"; + +import classNames from 'classnames'; +import { useEffect, useRef } from "react"; + +import { Edge, Node } from "@/ui/rendering/graph/types"; +import animate from "@/ui/rendering/animate"; + +// IMPROVEMENT #8: Extended config for layered view controls +interface GraphVisualizationProps { + nodes: Node[]; + edges: Edge[]; + className?: string; + config?: { + fontSize?: number; + showNodes?: boolean; // Toggle node visibility + showEdges?: boolean; // Toggle edge/path visibility + showMetaballs?: boolean; // Toggle density cloud visibility + highlightedNodeIds?: Set; // Nodes to highlight (neutral-by-default) + }; +} + +export default function GraphVisualization({ + nodes, + edges, + className, + config, +}: GraphVisualizationProps) { + const visualizationRef = useRef(null); + const cleanupRef = useRef<(() => void) | null>(null); + + useEffect(() => { + const visualizationContainer = visualizationRef.current; + + if (visualizationContainer) { + // Clean up previous visualization + if (cleanupRef.current) { + cleanupRef.current(); + } + + // Clear the container + while (visualizationContainer.firstChild) { + visualizationContainer.removeChild(visualizationContainer.firstChild); + } + + // Create new visualization + const cleanup = animate(nodes, edges, visualizationContainer, config); + cleanupRef.current = cleanup; + } + + return () => { + if (cleanupRef.current) { + cleanupRef.current(); + } + }; + }, [config, edges, nodes]); + + return ( +
+ ); +} diff --git a/cognee-frontend/src/ui/elements/MemoryGraphVisualization.tsx b/cognee-frontend/src/ui/elements/MemoryGraphVisualization.tsx new file mode 100644 index 000000000..0a024b3dd --- /dev/null +++ b/cognee-frontend/src/ui/elements/MemoryGraphVisualization.tsx @@ -0,0 +1,374 @@ +/** + * Memory Graph Visualization + * + * Reusable visualization component with retrieval-first features: + * - Node set inference and display + * - Retrieval search with explanations + * - Neutral-by-default highlighting + * - Type attributes vs. inferred sets separation + * + * Works with any graph data (mock or real Cognee API data) + */ + +"use client"; + +import { useState, useMemo } from "react"; +import GraphVisualization from "@/ui/elements/GraphVisualization"; +import { Edge, Node } from "@/ui/rendering/graph/types"; +import { NodeSet } from "@/types/NodeSet"; +import { inferNodeSets, mockRetrievalSearch } from "@/lib/inferNodeSets"; +import type { RetrievalResult } from "@/types/NodeSet"; + +interface MemoryGraphVisualizationProps { + nodes: Node[]; + edges: Edge[]; + title?: string; + showControls?: boolean; +} + +export default function MemoryGraphVisualization({ + nodes, + edges, + title = "Memory Retrieval Debugger", + showControls = true, +}: MemoryGraphVisualizationProps) { + const [showLegend, setShowLegend] = useState(true); + + // Retrieval-first: search replaces static filtering + const [searchQuery, setSearchQuery] = useState(""); + const [retrievalResults, setRetrievalResults] = useState([]); + + // Node sets: primary abstraction + const [selectedNodeSet, setSelectedNodeSet] = useState(null); + + // Layer visibility controls + const [showNodes, setShowNodes] = useState(true); + const [showEdges, setShowEdges] = useState(true); + const [showMetaballs, setShowMetaballs] = useState(false); + + // Node Attributes section collapsed by default (secondary concern) + const [showNodeAttributes, setShowNodeAttributes] = useState(false); + + // Infer node sets from graph structure (CRITICAL: separate attributes from sets) + const { typeAttributes, inferredSets } = useMemo(() => { + return inferNodeSets(nodes, edges, { + minSetSize: 5, + maxSets: 15, + }); + }, [nodes, edges]); + + // Neutral-by-default: only highlight nodes that are selected or retrieved + const highlightedNodeIds = useMemo(() => { + const ids = new Set(); + + // Nodes from retrieval results + retrievalResults.forEach(result => { + if (result.type === "node" && result.nodeId) { + ids.add(result.nodeId); + } else if (result.type === "nodeSet" && result.nodeSet) { + result.nodeSet.nodeIds.forEach(id => ids.add(id)); + } + }); + + // Nodes from selected set + if (selectedNodeSet) { + selectedNodeSet.nodeIds.forEach(id => ids.add(id)); + } + + return ids; + }, [retrievalResults, selectedNodeSet]); + + // Handle retrieval search + const handleSearch = (query: string) => { + setSearchQuery(query); + if (query.trim()) { + const results = mockRetrievalSearch(query, nodes, inferredSets); + setRetrievalResults(results); + } else { + setRetrievalResults([]); + } + }; + + const handleReset = () => { + setSearchQuery(""); + setRetrievalResults([]); + setSelectedNodeSet(null); + }; + + return ( +
+ {/* Main Visualization */} +
+ + + {/* Header */} +
+

+ {title} +

+

+ {highlightedNodeIds.size > 0 ? ( + <> + {highlightedNodeIds.size} retrieved + {" / "} + {nodes.length.toLocaleString()} total + {" β€’ "} + {inferredSets.length} inferred sets + + ) : ( + <> + {nodes.length.toLocaleString()} nodes + {" β€’ "} + {inferredSets.length} inferred sets + {" β€’ "} + Search to retrieve + + )} +

+
+ + {showControls && ( +
+ {/* Retrieval Search */} +
+ handleSearch(e.target.value)} + className="w-full px-4 py-2 bg-black/70 backdrop-blur-md border border-purple-500/30 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:border-purple-500 focus:ring-2 focus:ring-purple-500/20" + /> + {searchQuery && ( + + )} +
+ + {/* View Controls */} +
+ + {(searchQuery || selectedNodeSet || retrievalResults.length > 0) && ( + + )} +
+ + {/* Layer Visibility Controls */} +
+
Layers
+
+ + + +
+
+
+ )} +
+ + {/* Side Panel */} + {showLegend && ( +
+
+ {/* Retrieval Results */} + {retrievalResults.length > 0 && ( +
+

+ Retrieved Memories +

+
+ {retrievalResults.slice(0, 10).map((result, idx) => ( +
+
+
+ {result.type === "node" ? result.nodeLabel : result.nodeSet?.name} +
+
+ {(result.similarityScore * 100).toFixed(0)}% +
+
+
+ {result.why} +
+
+ {result.signals.map((signal, sidx) => ( + + {signal.name}: {(signal.weight * 100).toFixed(0)}% + + ))} +
+
+ ))} +
+
+ )} + + {/* Node Attributes - Secondary (NOT sets, just metadata) */} +
+ + {showNodeAttributes && ( +
+ {Array.from(typeAttributes.entries()) + .sort((a, b) => b[1] - a[1]) + .map(([type, count]) => ( +
+ type: {type} + ({count}) +
+ ))} +
+ )} +
+ + {/* Inferred Node Sets - PRIMARY ABSTRACTION */} +
+

+ + Node Sets + + {selectedNodeSet && ( + + )} +

+
+ {inferredSets.map((nodeSet) => { + const isSelected = selectedNodeSet?.id === nodeSet.id; + return ( + + ); + })} +
+
+ + {/* Enhanced explanatory section with explicit semantics */} +
+

Visual Elements

+
+
+ ● +
+ Node Size = Importance: +
Larger = Domain/Field (structural), Smaller = Application (leaf)
+
+
+
+ ─ +
+ Paths (zoom to see): +
Relationships β€’ Hover node to highlight connections
+
+
+
+ β—‰ +
+ Background Clouds: +
Conceptual Density β€’ Visible at far zoom for cluster overview
+
+
+
+ β—‹ +
+ Boundary Rings: +
Type Clusters β€’ Spatial grouping by semantic category
+
+
+
+
+
+
+ )} +
+ ); +} diff --git a/cognee-frontend/src/ui/elements/Notebook/Notebook.tsx b/cognee-frontend/src/ui/elements/Notebook/Notebook.tsx index 3ddafe728..1da50ce05 100644 --- a/cognee-frontend/src/ui/elements/Notebook/Notebook.tsx +++ b/cognee-frontend/src/ui/elements/Notebook/Notebook.tsx @@ -14,6 +14,7 @@ import GraphVisualization, { GraphVisualizationAPI } from "@/app/(graph)/GraphVi import NotebookCellHeader from "./NotebookCellHeader"; import MarkdownPreview from "./MarkdownPreview"; import { Cell, Notebook as NotebookType } from "./types"; +import GraphVisualization from "../GraphVisualization"; interface NotebookProps { notebook: NotebookType; @@ -371,14 +372,18 @@ function CellResult({ content }: { content: [] }) { if (Array.isArray(line)) { // Insights search returns uncommon graph data structure if (Array.from(line).length > 0 && Array.isArray(line[0]) && line[0][1]["relationship_name"]) { + const data = transformInsightsGraphData(line); + parsedContent.push( -
+
reasoning graph } - graphControls={graphControls} - className="min-h-80" + nodes={data.nodes} + edges={data.edges} + className="flex-1" + config={{ + fontSize: 24, + }} />
); @@ -420,13 +425,15 @@ function CellResult({ content }: { content: [] }) { if (typeof item === "object" && item["graphs"] && typeof item["graphs"] === "object") { Object.entries<{ nodes: []; edges: []; }>(item["graphs"]).forEach(([datasetName, graph]) => { parsedContent.push( -
+
reasoning graph (datasets: {datasetName}) } - graphControls={graphControls} - className="min-h-80" + nodes={graph.nodes} + edges={graph.edges} + className="flex-1" + config={{ + fontSize: 24, + }} />
); @@ -501,13 +508,6 @@ function CellResult({ content }: { content: [] }) { )); }; -function transformToVisualizationData(graph: { nodes: [], edges: [] }) { - return { - nodes: graph.nodes, - links: graph.edges, - }; -} - type Triplet = [{ id: string, name: string, @@ -528,8 +528,9 @@ function transformInsightsGraphData(triplets: Triplet[]) { type: string, } } = {}; - const links: { + const edges: { [key: string]: { + id: string, source: string, target: string, label: string, @@ -548,7 +549,8 @@ function transformInsightsGraphData(triplets: Triplet[]) { type: triplet[2].type, }; const linkKey = `${triplet[0]["id"]}_${triplet[1]["relationship_name"]}_${triplet[2]["id"]}`; - links[linkKey] = { + edges[linkKey] = { + id: linkKey, source: triplet[0].id, target: triplet[2].id, label: triplet[1]["relationship_name"], @@ -557,6 +559,6 @@ function transformInsightsGraphData(triplets: Triplet[]) { return { nodes: Object.values(nodes), - links: Object.values(links), + edges: Object.values(edges), }; } diff --git a/cognee-frontend/src/ui/rendering/animate.ts b/cognee-frontend/src/ui/rendering/animate.ts new file mode 100644 index 000000000..761748fa3 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/animate.ts @@ -0,0 +1,643 @@ +import { Graph, Node as GraphNode, Link as GraphLink } from "ngraph.graph"; +import * as three from "three"; +import { + Color, + DataTexture, + OrthographicCamera, + RGBAFormat, + Scene, + UnsignedByteType, + Vector2, + WebGLRenderer, + WebGLRenderTarget, +} from "three"; +import { OrbitControls } from "three/examples/jsm/Addons.js"; +import createForceLayout, { Layout } from "ngraph.forcelayout"; + +import { Edge, Node } from "./graph/types"; +import createGraph from "./graph/createGraph"; + +import createLabel from "./meshes/createLabel"; +import pickNodeIndex from "./picking/pickNodeIndex"; +import createEdgeMesh from "./meshes/createEdgeMesh"; +import createPickingMesh from "./meshes/createPickingMesh"; +import createNodeSwarmMesh from "./meshes/createNodeSwarmMesh"; +import createNodePositionsTexture from "./textures/createNodePositionsTexture"; +import createDensityRenderTarget from "./render-targets/createDensityRenderTarget"; +import createDensityAccumulatorMesh from "./meshes/createDensityAccumulatorMesh"; +import createMetaballMesh from "./meshes/createMetaballMesh"; +import createClusterBoundaryMesh, { ClusterInfo } from "./meshes/createClusterBoundaryMesh"; + +const INITIAL_CAMERA_DISTANCE = 2000; + +// Extended config for layered view controls + zoom semantics +interface Config { + fontSize?: number; + showNodes?: boolean; + showEdges?: boolean; + showMetaballs?: boolean; + pathFilterMode?: "all" | "hoverOnly" | "strongOnly"; // Path filtering + zoomLevel?: "far" | "mid" | "near"; // Zoom-based semantics + highlightedNodeIds?: Set; // Nodes to highlight (neutral-by-default) +} + +export default function animate( + nodes: Node[], + edges: Edge[], + parentElement: HTMLElement, + config?: Config +): () => void { + const nodeLabelMap = new Map(); + const edgeLabelMap = new Map(); + + // Semantic color encoding: hierarchy drives saturation + brightness + const typeColorMap: Record = { + "Domain": "#C4B5FD", // Bright Purple - Highest importance + "Field": "#67E8F9", // Bright Cyan - High importance + "Subfield": "#A78BFA", // Medium Purple - Medium-high importance + "Concept": "#5EEAD4", // Teal - Medium importance + "Method": "#6EE7B7", // Green - Medium importance + "Theory": "#F9A8D4", // Pink - Medium importance + "Technology": "#FCA5A5", // Soft Red - Lower importance + "Application": "#71717A", // Desaturated Gray - Background/lowest importance + }; + + // Size hierarchy: more important = larger + const typeSizeMap: Record = { + "Domain": 2.5, // Largest + "Field": 2.0, + "Subfield": 1.6, + "Concept": 1.2, + "Method": 1.1, + "Theory": 1.0, + "Technology": 0.9, + "Application": 0.6, // Smallest + }; + + function getColorForType(nodeType: string): Color { + const colorHex = typeColorMap[nodeType]; + if (colorHex) { + return new Color(colorHex); + } + // Fallback for unknown types + return new Color("#9CA3AF"); // Gray for unknown types + } + + const mousePosition = new Vector2(); + + // Node related data + const nodeColors = new Float32Array(nodes.length * 3); + const nodeSizes = new Float32Array(nodes.length); // Size per node for hierarchy + const nodeHighlights = new Float32Array(nodes.length); // 1.0 = highlighted, 0.3 = dimmed + const nodeIndices = new Map(); + const textureSize = Math.ceil(Math.sqrt(nodes.length)); + const nodePositionsData = new Float32Array(textureSize * textureSize * 4); + + // Determine which nodes are highlighted + const highlightedIds = config?.highlightedNodeIds; + const hasHighlights = highlightedIds && highlightedIds.size > 0; + + let nodeIndex = 0; + function forNode(node: Node) { + const color = getColorForType(node.type); + nodeColors[nodeIndex * 3 + 0] = color.r; + nodeColors[nodeIndex * 3 + 1] = color.g; + nodeColors[nodeIndex * 3 + 2] = color.b; + + // Set highlight state: if no highlights, all at 1.0; if highlights exist, dim non-highlighted + if (hasHighlights) { + nodeHighlights[nodeIndex] = highlightedIds!.has(node.id) ? 1.0 : 0.3; + } else { + nodeHighlights[nodeIndex] = 1.0; // All visible when no highlights + } + + // Store size multiplier based on type + nodeSizes[nodeIndex] = typeSizeMap[node.type] || 1.0; + + nodePositionsData[nodeIndex * 4 + 0] = 0.0; + nodePositionsData[nodeIndex * 4 + 1] = 0.0; + nodePositionsData[nodeIndex * 4 + 2] = 0.0; + nodePositionsData[nodeIndex * 4 + 3] = 1.0; + + nodeIndices.set(node.id, nodeIndex); + + nodeIndex += 1; + } + + // Node related data + const edgeIndices = new Float32Array(edges.length * 2); + + let edgeIndex = 0; + function forEdge(edge: Edge) { + const fromIndex = nodeIndices.get(edge.source); + const toIndex = nodeIndices.get(edge.target); + edgeIndices[edgeIndex * 2 + 0] = fromIndex; + edgeIndices[edgeIndex * 2 + 1] = toIndex; + + edgeIndex += 1; + } + + // Graph creation and layout + const graph = createGraph(nodes, edges, forNode, forEdge); + + // Adaptive layout parameters based on graph size + const nodeCount = nodes.length; + const isLargeGraph = nodeCount > 5000; + const isMassiveGraph = nodeCount > 15000; + + // Apple embedding atlas style: stronger repulsion for clear cluster separation + const graphLayout = createForceLayout(graph, { + dragCoefficient: isMassiveGraph ? 0.95 : 0.85, + springLength: isMassiveGraph ? 120 : isLargeGraph ? 180 : 220, // Longer springs for spacing + springCoefficient: isMassiveGraph ? 0.12 : isLargeGraph ? 0.15 : 0.18, // Weaker springs + gravity: isMassiveGraph ? -1200 : isLargeGraph ? -1500 : -1800, // Stronger repulsion + }); + + // Node Mesh + const nodePositionsTexture = createNodePositionsTexture( + nodes, + nodePositionsData + ); + + const nodeSwarmMesh = createNodeSwarmMesh( + nodes, + nodePositionsTexture, + nodeColors, + nodeSizes, + nodeHighlights, + INITIAL_CAMERA_DISTANCE + ); + + const edgeMesh = createEdgeMesh( + edges, + nodePositionsTexture, + edgeIndices, + INITIAL_CAMERA_DISTANCE + ); + + // Density cloud setup - adaptive resolution for performance + const densityCloudScene = new Scene(); + const densityResolution = isMassiveGraph ? 256 : isLargeGraph ? 384 : 512; + const densityCloudTarget = createDensityRenderTarget(densityResolution); + + const densityAccumulatorMesh = createDensityAccumulatorMesh( + nodes, + nodeColors, + nodePositionsTexture, + INITIAL_CAMERA_DISTANCE + ); + + const metaballMesh = createMetaballMesh(densityCloudTarget); + + // const densityCloudDebugMesh = createDebugViewMesh(densityCloudTarget); + // Density cloud setup end + + let pickedNodeIndex = -1; + const lastPickedNodeIndex = -1; + const pickNodeFromScene = (event: unknown) => { + pickedNodeIndex = pickNodeIndexFromScene(event as MouseEvent); + }; + + parentElement.addEventListener("mousemove", (event) => { + const rect = parentElement.getBoundingClientRect(); + mousePosition.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; + mousePosition.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; + + pickNodeFromScene(event); + }); + + // Group nodes by type for cluster boundaries + const nodesByType = new Map(); + nodes.forEach(node => { + if (!nodesByType.has(node.type)) { + nodesByType.set(node.type, []); + } + nodesByType.get(node.type)!.push(node); + }); + + const scene = new Scene(); + // Apple embedding atlas style: pure black background + scene.background = new Color("#000000"); + const renderer = new WebGLRenderer({ antialias: true }); + + renderer.setPixelRatio(window.devicePixelRatio); + renderer.setSize(parentElement.clientWidth, parentElement.clientHeight); + if (parentElement.children.length === 0) { + parentElement.appendChild(renderer.domElement); + } + + // Setup camera + const aspect = parentElement.clientWidth / parentElement.clientHeight; + const frustumSize = INITIAL_CAMERA_DISTANCE; + + const camera = new OrthographicCamera( + (-frustumSize * aspect) / 2, + (frustumSize * aspect) / 2, + frustumSize / 2, + -frustumSize / 2, + 1, + 5000 + ); + + camera.position.set(0, 0, INITIAL_CAMERA_DISTANCE); + camera.lookAt(0, 0, 0); + + // Setup controls + const controls = new OrbitControls(camera, renderer.domElement); + controls.enableRotate = false; + controls.enablePan = true; + controls.enableZoom = true; + controls.screenSpacePanning = true; + controls.minZoom = 0.5; // Allow zooming out more + controls.maxZoom = 6; // Allow closer zoom for detail + controls.enableDamping = true; + controls.dampingFactor = 0.08; // Smoother, more fluid motion + controls.target.set(0, 0, 0); + + controls.update(); + + // Handle resizing + window.addEventListener("resize", () => { + const aspect = parentElement.clientWidth / parentElement.clientHeight; + camera.left = (-frustumSize * aspect) / 2; + camera.right = (frustumSize * aspect) / 2; + camera.top = frustumSize / 2; + camera.bottom = -frustumSize / 2; + camera.updateProjectionMatrix(); + renderer.setSize(parentElement.clientWidth, parentElement.clientHeight); + }); + + // Node picking setup + const pickingTarget = new WebGLRenderTarget( + window.innerWidth, + window.innerHeight, + { + format: RGBAFormat, + type: UnsignedByteType, + depthBuffer: true, + stencilBuffer: false, + } + ); + const pickingScene = new Scene(); + + function pickNodeIndexFromScene(event: MouseEvent): number { + pickingScene.add(pickingMesh); + + const pickedNodeIndex = pickNodeIndex( + event, + renderer, + pickingScene, + camera, + pickingTarget + ); + + return pickedNodeIndex; + } + + const pickingMesh = createPickingMesh( + nodes, + nodePositionsTexture, + nodeColors, + INITIAL_CAMERA_DISTANCE + ); + + renderer.domElement.addEventListener("mousedown", (event) => { + const pickedNodeIndex = pickNodeIndexFromScene(event); + console.log("Picked node index: ", pickedNodeIndex); + }); + // Node picking setup end + + // Adaptive layout iterations based on graph size + const layoutIterations = isMassiveGraph ? 300 : isLargeGraph ? 500 : 800; + console.log(`Running ${layoutIterations} layout iterations for ${nodeCount} nodes...`); + + for (let i = 0; i < layoutIterations; i++) { + graphLayout.step(); + + // Progress logging for large graphs + if (isMassiveGraph && i % 50 === 0) { + console.log(`Layout progress: ${((i / layoutIterations) * 100).toFixed(0)}%`); + } + } + console.log("Layout complete!"); + + let visibleLabels: unknown[] = []; + + // Only create entity type labels for smaller graphs (performance optimization) + const entityTypeLabels: [string, unknown][] = []; + if (!isMassiveGraph) { + for (const node of nodes) { + if (node.type === "EntityType") { + const label = createLabel(node.label, config?.fontSize); + entityTypeLabels.push([node.id, label]); + } + } + } + + // const processingStep = 0; + + // Performance monitoring + let frameCount = 0; + let lastFpsUpdate = performance.now(); + let currentFps = 60; + + // Cluster boundaries + let clusterBoundariesCreated = false; + const clusterBoundaryMeshes: three.Mesh[] = []; + + function calculateClusterBoundaries(): ClusterInfo[] { + const clusters: ClusterInfo[] = []; + + nodesByType.forEach((typeNodes, nodeType) => { + if (typeNodes.length < 3) return; // Skip small clusters + + // Calculate center and radius from actual node positions + let sumX = 0; + let sumY = 0; + typeNodes.forEach(node => { + const pos = graphLayout.getNodePosition(node.id); + sumX += pos.x; + sumY += pos.y; + }); + + const center = { + x: sumX / typeNodes.length, + y: sumY / typeNodes.length + }; + + // Calculate radius as max distance from center + padding + let maxDist = 0; + typeNodes.forEach(node => { + const pos = graphLayout.getNodePosition(node.id); + const dist = Math.sqrt( + Math.pow(pos.x - center.x, 2) + Math.pow(pos.y - center.y, 2) + ); + maxDist = Math.max(maxDist, dist); + }); + + clusters.push({ + center, + radius: maxDist + 350, // Apple style: more spacing between clusters + color: getColorForType(nodeType) + }); + }); + + return clusters; + } + + // Render loop + function render() { + // Adaptive physics updates - skip for large graphs after stabilization + if (!isMassiveGraph || frameCount < 100) { + graphLayout.step(); + } else if (frameCount % 2 === 0) { + // Update physics every other frame for massive graphs + graphLayout.step(); + } + + // FPS monitoring + frameCount++; + const now = performance.now(); + if (now - lastFpsUpdate > 1000) { + currentFps = Math.round((frameCount * 1000) / (now - lastFpsUpdate)); + frameCount = 0; + lastFpsUpdate = now; + if (isMassiveGraph && currentFps < 30) { + console.warn(`Low FPS detected: ${currentFps} fps`); + } + } + + controls.update(); + + // Create cluster boundaries after layout stabilizes + if (!clusterBoundariesCreated && frameCount === 60) { + const clusters = calculateClusterBoundaries(); + clusters.forEach(cluster => { + const mesh = createClusterBoundaryMesh(cluster); + clusterBoundaryMeshes.push(mesh); + scene.add(mesh); + }); + clusterBoundariesCreated = true; + } + + updateNodePositions( + nodes, + graphLayout, + nodePositionsData, + nodePositionsTexture + ); + const textScale = Math.max(1, 4 / camera.zoom); + + nodeSwarmMesh.material.uniforms.camDist.value = Math.floor( + camera.zoom * 500 + ); + nodeSwarmMesh.material.uniforms.mousePos.value.set( + mousePosition.x, + mousePosition.y + ); + // @ts-expect-error uniforms does exist on material + edgeMesh.material.uniforms.camDist.value = Math.floor(camera.zoom * 500); + // @ts-expect-error uniforms does exist on material + edgeMesh.material.uniforms.mousePos.value.set( + mousePosition.x, + mousePosition.y + ); + + // @ts-expect-error uniforms does exist on material + pickingMesh.material.uniforms.camDist.value = Math.floor(camera.zoom * 500); + + // Zoom-level semantics: determine what to show based on zoom + let zoomLevel: "far" | "mid" | "near" = "mid"; + if (camera.zoom < 1.0) { + zoomLevel = "far"; // Show clusters, domains, density + } else if (camera.zoom > 3.0) { + zoomLevel = "near"; // Show applications, paths, labels + } + + edgeMesh.renderOrder = 1; + nodeSwarmMesh.renderOrder = 2; + + // IMPROVEMENT #8: Conditional layer rendering based on config and zoom + const showEdges = config?.showEdges !== false && zoomLevel !== "far"; // Hide edges when far + const showNodes = config?.showNodes !== false; // Always show nodes + const showMetaballs = config?.showMetaballs !== false && zoomLevel === "far"; // Only show at far zoom + + // Path filtering based on hover + const pathFilterMode = config?.pathFilterMode || "all"; + const shouldShowPath = pathFilterMode === "all" || (pathFilterMode === "hoverOnly" && pickedNodeIndex >= 0); + + if (showEdges) { + scene.add(edgeMesh); + } + if (showNodes) { + scene.add(nodeSwarmMesh); + } + + // Metaball rendering - reduce frequency for massive graphs + const shouldRenderMetaballs = showMetaballs && (!isMassiveGraph || frameCount % 2 === 0); + + if (shouldRenderMetaballs) { + // Pass 1: draw points into density texture + renderer.setRenderTarget(densityCloudTarget); + renderer.clear(); + densityCloudScene.clear(); + densityCloudScene.add(densityAccumulatorMesh); + renderer.render(densityCloudScene, camera); + + // Pass 2: render density map to screen + renderer.setRenderTarget(null); + renderer.clear(); + metaballMesh.renderOrder = 0; + scene.add(metaballMesh); + } else { + renderer.setRenderTarget(null); + renderer.clear(); + } + + for (const [nodeId, label] of entityTypeLabels) { + const nodePosition = graphLayout.getNodePosition(nodeId); + // @ts-expect-error label is Text from troika-three-text + label.position.set(nodePosition.x, nodePosition.y, 1.0); + // @ts-expect-error label is Text from troika-three-text + label.scale.setScalar(textScale); + // @ts-expect-error label is Text from troika-three-text + scene.add(label); + } + + if (pickedNodeIndex >= 0) { + if (pickedNodeIndex !== lastPickedNodeIndex) { + for (const label of visibleLabels) { + // @ts-expect-error label is Text from troika-three-text + label.visible = false; + } + visibleLabels = []; + } + + const pickedNode = nodes[pickedNodeIndex]; + + parentElement.style.cursor = "pointer"; + + const pickedNodePosition = graphLayout.getNodePosition(pickedNode.id); + + let pickedNodeLabel = nodeLabelMap.get(pickedNode.id); + if (!pickedNodeLabel) { + pickedNodeLabel = createLabel(pickedNode.label, config?.fontSize); + nodeLabelMap.set(pickedNode.id, pickedNodeLabel); + } + pickedNodeLabel.position.set( + pickedNodePosition.x, + pickedNodePosition.y, + 1.0 + ); + pickedNodeLabel.scale.setScalar(textScale); + + // Adaptive label display based on graph size and zoom + const minZoomForLabels = isMassiveGraph ? 4 : isLargeGraph ? 3 : 2; + const maxLabels = isMassiveGraph ? 5 : isLargeGraph ? 10 : 15; + + if (camera.zoom > minZoomForLabels) { + graph.forEachLinkedNode( + pickedNode.id, + (otherNode: GraphNode, edge: GraphLink) => { + if (visibleLabels.length > maxLabels) { + return; + } + + let otherNodeLabel = nodeLabelMap.get(otherNode.id); + if (!otherNodeLabel) { + otherNodeLabel = createLabel(otherNode.data.label, config?.fontSize); + nodeLabelMap.set(otherNode.id, otherNodeLabel); + } + const otherNodePosition = graphLayout.getNodePosition(otherNode.id); + otherNodeLabel.position.set( + otherNodePosition.x, + otherNodePosition.y, + 1.0 + ); + + let linkLabel = edgeLabelMap.get(edge.id); + if (!linkLabel) { + linkLabel = createLabel(edge.data.label, config?.fontSize); + edgeLabelMap.set(edge.id, linkLabel); + } + const linkPosition = graphLayout.getLinkPosition(edge.id); + const middleLinkPosition = new Vector2( + (linkPosition.from.x + linkPosition.to.x) / 2, + (linkPosition.from.y + linkPosition.to.y) / 2 + ); + linkLabel.position.set( + middleLinkPosition.x, + middleLinkPosition.y, + 1.0 + ); + + linkLabel.visible = true; + linkLabel.scale.setScalar(textScale); + visibleLabels.push(linkLabel); + otherNodeLabel.visible = true; + otherNodeLabel.scale.setScalar(textScale); + visibleLabels.push(otherNodeLabel); + + scene.add(linkLabel); + scene.add(otherNodeLabel); + } + ); + } + + pickedNodeLabel.visible = true; + visibleLabels.push(pickedNodeLabel); + + scene.add(pickedNodeLabel); + } else { + parentElement.style.cursor = "default"; + + for (const label of visibleLabels) { + // @ts-expect-error label is Text from troika-three-text + label.visible = false; + } + + visibleLabels = []; + } + + renderer.render(scene, camera); + + animationFrameId = requestAnimationFrame(render); + } + + let animationFrameId: number; + render(); + + // Return cleanup function + return () => { + if (animationFrameId) { + cancelAnimationFrame(animationFrameId); + } + // Clean up cluster boundaries + clusterBoundaryMeshes.forEach(mesh => { + scene.remove(mesh); + mesh.geometry.dispose(); + if (mesh.material instanceof three.Material) { + mesh.material.dispose(); + } + }); + graphLayout.dispose(); + renderer.dispose(); + controls.dispose(); + }; +} + +function updateNodePositions( + nodes: Node[], + graphLayout: Layout, + nodePositionsData: Float32Array, + nodePositionsTexture: DataTexture +) { + for (let i = 0; i < nodes.length; i++) { + const p = graphLayout.getNodePosition(nodes[i].id); + nodePositionsData[i * 4 + 0] = p.x; + nodePositionsData[i * 4 + 1] = p.y; + nodePositionsData[i * 4 + 2] = 0.0; + nodePositionsData[i * 4 + 3] = 1.0; + } + nodePositionsTexture.needsUpdate = true; +} diff --git a/cognee-frontend/src/ui/rendering/graph/createGraph.ts b/cognee-frontend/src/ui/rendering/graph/createGraph.ts new file mode 100644 index 000000000..b2cd4a5f4 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/graph/createGraph.ts @@ -0,0 +1,28 @@ +import createNgraph, { Graph } from "ngraph.graph"; +import { Edge, Node } from "./types"; + +export default function createGraph( + nodes: Node[], + edges: Edge[], + forNode?: (node: Node) => void, + forEdge?: (node: Edge) => void +): Graph { + const graph = createNgraph(); + + for (const node of nodes) { + graph.addNode(node.id, { + id: node.id, + label: node.label, + }); + forNode?.(node); + } + for (const edge of edges) { + graph.addLink(edge.source, edge.target, { + id: edge.id, + label: edge.label, + }); + forEdge?.(edge); + } + + return graph; +} diff --git a/cognee-frontend/src/ui/rendering/graph/types.ts b/cognee-frontend/src/ui/rendering/graph/types.ts new file mode 100644 index 000000000..bd7f9d48e --- /dev/null +++ b/cognee-frontend/src/ui/rendering/graph/types.ts @@ -0,0 +1,12 @@ +export interface Node { + id: string; + label: string; + type: string; +} + +export interface Edge { + id: string; + label: string; + source: string; + target: string; +} diff --git a/cognee-frontend/src/ui/rendering/materials/createBlurPassMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createBlurPassMaterial.ts new file mode 100644 index 000000000..86e70aec9 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createBlurPassMaterial.ts @@ -0,0 +1,46 @@ +import { ShaderMaterial, Texture, Vector2 } from "three"; + +export function createBlurPassMaterial( + texture: Texture, + direction = new Vector2(1.0, 0.0) +) { + return new ShaderMaterial({ + uniforms: { + densityTex: { value: texture }, + direction: { value: direction }, // (1,0) = horizontal, (0,1) = vertical + texSize: { value: new Vector2(512, 512) }, + }, + vertexShader: ` + varying vec2 vUv; + void main() { + vUv = uv; + gl_Position = vec4(position.xy, 0.0, 1.0); + } + `, + fragmentShader: ` + precision highp float; + uniform sampler2D densityTex; + uniform vec2 direction; + uniform vec2 texSize; + varying vec2 vUv; + + void main() { + vec2 texel = direction / texSize; + float kernel[5]; + kernel[0] = 0.204164; + kernel[1] = 0.304005; + kernel[2] = 0.193783; + kernel[3] = 0.072184; + kernel[4] = 0.025864; + + vec4 sum = texture2D(densityTex, vUv) * kernel[0]; + for (int i = 1; i < 5; i++) { + sum += texture2D(densityTex, vUv + texel * float(i)) * kernel[i]; + sum += texture2D(densityTex, vUv - texel * float(i)) * kernel[i]; + } + + gl_FragColor = sum; + } + `, + }); +} diff --git a/cognee-frontend/src/ui/rendering/materials/createClusterBoundaryMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createClusterBoundaryMaterial.ts new file mode 100644 index 000000000..d8f8d5129 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createClusterBoundaryMaterial.ts @@ -0,0 +1,48 @@ +import * as three from "three"; + +export default function createClusterBoundaryMaterial( + clusterColor: three.Color +): three.ShaderMaterial { + const material = new three.ShaderMaterial({ + transparent: true, + depthWrite: false, + side: three.DoubleSide, + uniforms: { + clusterColor: { value: clusterColor }, + }, + vertexShader: ` + varying vec2 vUv; + + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + uniform vec3 clusterColor; + varying vec2 vUv; + + void main() { + // Apple embedding atlas style: soft circular regions + vec2 center = vec2(0.5, 0.5); + float dist = length(vUv - center); + + // Soft radial gradient background + float alpha = smoothstep(0.5, 0.25, dist) * 0.12; // More visible background + + // Prominent boundary ring (Apple style) + float ring = smoothstep(0.49, 0.47, dist) - smoothstep(0.51, 0.49, dist); + alpha += ring * 0.25; // More prominent border + + // Lighter, more vibrant colors for Apple aesthetic + vec3 bgColor = clusterColor * 1.1; + + gl_FragColor = vec4(bgColor, alpha); + } + `, + }); + + return material; +} diff --git a/cognee-frontend/src/ui/rendering/materials/createDebugViewMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createDebugViewMaterial.ts new file mode 100644 index 000000000..6854093e2 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createDebugViewMaterial.ts @@ -0,0 +1,37 @@ +import { ShaderMaterial, Texture } from "three"; + +export function createDebugViewMaterial(fieldTexture: Texture) { + return new ShaderMaterial({ + uniforms: { + fieldTex: { value: fieldTexture }, + }, + vertexShader: ` + // void main() { + // gl_Position = vec4(position, 1.0); + // } + varying vec2 vUv; + void main() { vUv = uv; gl_Position = vec4(position.xy, 0.0, 1.0); } + `, + fragmentShader: ` + uniform sampler2D fieldTex; + varying vec2 vUv; + void main() { + // gl_FragColor = texture2D(fieldTex, vUv); + + float field = texture2D(fieldTex, vUv).r; + field = pow(field * 2.0, 0.5); // optional tone mapping + gl_FragColor = vec4(vec3(field), 1.0); + } + + // precision highp float; + // uniform sampler2D fieldTex; + + // void main() { + // vec2 uv = gl_FragCoord.xy / vec2(textureSize(fieldTex, 0)); + // float field = texture2D(fieldTex, uv).r; + // // visualize the field as grayscale + // gl_FragColor = vec4(vec3(field), 1.0); + // } + `, + }); +} diff --git a/cognee-frontend/src/ui/rendering/materials/createDensityAccumulatorMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createDensityAccumulatorMaterial.ts new file mode 100644 index 000000000..4a316e300 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createDensityAccumulatorMaterial.ts @@ -0,0 +1,81 @@ +import { AdditiveBlending, DataTexture, ShaderMaterial } from "three"; + +export default function createDensityAccumulatorMaterial( + nodePositionsTexture: DataTexture, + initialCameraDistance: number +) { + const densityCloudMaterial = new ShaderMaterial({ + depthWrite: false, + depthTest: false, + transparent: true, + blending: AdditiveBlending, + uniforms: { + nodePositionsTexture: { + value: nodePositionsTexture, + }, + textureSize: { + value: nodePositionsTexture.image.width, + }, + camDist: { + value: initialCameraDistance, + }, + radius: { value: 0.05 }, + }, + vertexShader: ` + uniform sampler2D nodePositionsTexture; + uniform float textureSize; + uniform float camDist; + attribute vec3 nodeColor; + varying vec3 vColor; + varying vec2 vUv; + varying float nodeSize; + + vec3 getNodePos(float idx) { + float fx = mod(idx, textureSize); + float fy = floor(idx / textureSize); + vec2 uv = (vec2(fx, fy) + 0.5) / textureSize; + return texture2D(nodePositionsTexture, uv).xyz; + } + + void main() { + vUv = uv; + vColor = nodeColor; + vec3 nodePos = getNodePos(float(gl_InstanceID)); + + float baseNodeSize = 8.0; + + // Normalize camera distance into [0,1] + float t = clamp((camDist - 500.0) / (2000.0 - 500.0), 0.0, 1.0); + nodeSize = baseNodeSize * mix(10.0, 12.0, t); + + vec3 transformed = nodePos + position * nodeSize; + gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + varying vec2 vUv; + varying float nodeSize; + varying vec3 vColor; + + void main() { + vec2 pCoord = vUv - 0.5; + float distSq = dot(pCoord, pCoord) * 4.0; + + if (distSq > 1.0) { + discard; + } + + float radiusSq = (nodeSize / 2.0) * (nodeSize / 2.0); + float falloff = max(0.0, 1.0 - distSq); + float influence = radiusSq * falloff * falloff; + vec3 accumulatedColor = vColor * influence; + + gl_FragColor = vec4(accumulatedColor, influence); + } + `, + }); + + return densityCloudMaterial; +} diff --git a/cognee-frontend/src/ui/rendering/materials/createEdgeMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createEdgeMaterial.ts new file mode 100644 index 000000000..f2b513bac --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createEdgeMaterial.ts @@ -0,0 +1,87 @@ +import * as three from "three"; + +export default function createEdgeMaterial( + texture: three.DataTexture, + initialCameraDistance: number +): three.ShaderMaterial { + const material = new three.ShaderMaterial({ + transparent: true, + depthWrite: false, + blending: three.AdditiveBlending, + uniforms: { + nodePosTex: { value: texture }, + textureSize: { value: texture.image.width }, + camDist: { value: initialCameraDistance }, + mousePos: { value: new three.Vector2(9999, 9999) }, // start offscreen + // Apple embedding atlas style: soft pastel edges + color: { value: new three.Color("#FCD34D") }, // Soft amber for minimalist aesthetic + }, + vertexShader: ` + attribute vec2 edgeIndices; + uniform sampler2D nodePosTex; + uniform float textureSize; + uniform float camDist; + uniform vec2 mousePos; + + varying float vFade; + varying float vHighlight; + varying float vEdgePosition; // IMPROVEMENT #2: For directional gradient + + vec3 getNodePos(float idx) { + float x = mod(idx, textureSize); + float y = floor(idx / textureSize); + vec2 uv = (vec2(x, y) + 0.5) / textureSize; + return texture2D(nodePosTex, uv).xyz; + } + + void main() { + vec3 start = getNodePos(edgeIndices.x); + vec3 end = getNodePos(edgeIndices.y); + vec3 nodePos = mix(start, end, position.x); + + // IMPROVEMENT #2: Pass edge position for gradient + vEdgePosition = position.x; + + // Project world-space position to clip-space + vec4 clipPos = projectionMatrix * modelViewMatrix * vec4(nodePos, 1.0); + vec3 ndc = clipPos.xyz / clipPos.w; // normalized device coordinates [-1,1] + + float distanceFromMouse = length(ndc.xy - mousePos); + vHighlight = smoothstep(0.2, 0.0, distanceFromMouse); + + // Apple embedding atlas style: subtle edge opacity + vFade = smoothstep(500.0, 1500.0, camDist); + vFade = 0.25 * clamp(vFade, 0.0, 1.0); // Subtle for clean aesthetic + + gl_Position = projectionMatrix * modelViewMatrix * vec4(nodePos, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + uniform vec3 color; + varying float vFade; + varying float vHighlight; + varying float vEdgePosition; // IMPROVEMENT #2: For directional gradient + + void main() { + // IMPROVEMENT #2: Directional gradient from start to end + // Brighter at start, slightly darker at end for flow direction + float gradientFactor = 1.0 - (vEdgePosition * 0.3); // 30% dimming from start to end + + // IMPROVEMENT #2: Add subtle glow effect + vec3 glowColor = vec3(1.0, 0.9, 0.7); // Warm white glow + vec3 baseColor = color * gradientFactor; + vec3 finalColor = mix(baseColor, glowColor, vHighlight * 0.9); + + // IMPROVEMENT #2: Increased visibility and glow + float baseAlpha = vFade * 1.5; // Increased visibility + float alpha = mix(baseAlpha, 0.95, vHighlight); // Stronger highlight + + gl_FragColor = vec4(finalColor, alpha); + } + `, + }); + + return material; +} diff --git a/cognee-frontend/src/ui/rendering/materials/createMetaballMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createMetaballMaterial.ts new file mode 100644 index 000000000..0f07cc4d1 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createMetaballMaterial.ts @@ -0,0 +1,50 @@ +import { ShaderMaterial, Texture } from "three"; + +export function createMetaballMaterial(fieldTexture: Texture) { + return new ShaderMaterial({ + transparent: true, + uniforms: { + fieldTex: { value: fieldTexture }, + threshold: { value: 25000.0 }, + smoothing: { value: 5000.0 }, + }, + vertexShader: ` + varying vec2 vUv; + + void main() { + vUv = uv; + gl_Position = vec4(position, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + varying vec2 vUv; + uniform float threshold; + uniform float smoothing; + uniform sampler2D fieldTex; + + void main() { + vec4 fieldData = texture2D(fieldTex, vUv); + vec3 accumulatedColor = fieldData.rgb; + float totalInfluence = fieldData.a; + + vec3 finalColor = vec3(0.0); + + if (totalInfluence > 0.0) { + finalColor = accumulatedColor / totalInfluence; + } + + // Apple embedding atlas style: very subtle density clouds + float alphaEdge = smoothstep(threshold - smoothing, threshold + smoothing, totalInfluence); + float alpha = alphaEdge * 0.08; // Very subtle for clean Apple aesthetic + + if (alpha < 0.01) { + discard; + } + + gl_FragColor = vec4(finalColor, alpha); + } + `, + }); +} diff --git a/cognee-frontend/src/ui/rendering/materials/createNodeSwarmMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createNodeSwarmMaterial.ts new file mode 100644 index 000000000..9d0b6be5b --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createNodeSwarmMaterial.ts @@ -0,0 +1,104 @@ +import * as three from "three"; + +export default function createNodeSwarmMaterial( + nodePositionsTexture: three.DataTexture, + initialCameraDistance: number +) { + const material = new three.ShaderMaterial({ + transparent: true, + uniforms: { + nodePosTex: { value: nodePositionsTexture }, + textureSize: { value: nodePositionsTexture.image.width }, + camDist: { value: initialCameraDistance }, + mousePos: { value: new three.Vector2(9999, 9999) }, // start offscreen + }, + vertexShader: ` + precision highp float; + + uniform sampler2D nodePosTex; + uniform float textureSize; + uniform float camDist; + uniform vec2 mousePos; + attribute vec3 nodeColor; + attribute float nodeSize; // Hierarchy-based size multiplier + attribute float nodeHighlight; // Selection-based highlight (1.0 = selected, 0.3 = dimmed) + varying vec3 vColor; + varying float vHighlight; + varying float vSelectionHighlight; + varying vec2 vUv; // IMPROVEMENT #4: For radial halo effect + + vec3 getNodePos(float idx) { + float size = textureSize; + float fx = mod(idx, size); + float fy = floor(idx / size); + vec2 uv = (vec2(fx, fy) + 0.5) / size; + return texture2D(nodePosTex, uv).xyz; + } + + void main() { + vColor = nodeColor; + vSelectionHighlight = nodeHighlight; + vec3 nodePos = getNodePos(float(gl_InstanceID)); + + // IMPROVEMENT #4: Pass UV coordinates for halo effect + vUv = position.xy * 0.5 + 0.5; // Convert from [-1,1] to [0,1] + + // Project world-space position to clip-space + vec4 clipPos = projectionMatrix * modelViewMatrix * vec4(nodePos, 1.0); + vec3 ndc = clipPos.xyz / clipPos.w; // normalized device coordinates [-1,1] + + float distanceFromMouse = length(ndc.xy - mousePos); + vHighlight = smoothstep(0.2, 0.0, distanceFromMouse); + + // Hierarchy-based sizing: base size * type size multiplier + float baseNodeSize = 7.0; + + // Normalize camera distance into [0,1] + float t = clamp((camDist - 500.0) / (2000.0 - 500.0), 0.0, 1.0); + float finalSize = baseNodeSize * nodeSize * mix(1.0, 1.2, t); // Apply hierarchy multiplier + + vec3 transformed = nodePos + position * finalSize; + gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + varying vec3 vColor; + varying float vHighlight; + varying float vSelectionHighlight; + varying vec2 vUv; // IMPROVEMENT #4: For radial halo effect + + void main() { + // Apple embedding atlas style: subtle radial glow + vec2 center = vec2(0.5, 0.5); + float distFromCenter = length(vUv - center) * 2.0; + + // Create sharp node with very subtle glow + float coreRadius = 0.75; // Slightly larger core + float haloRadius = 1.0; + + // Core node (solid) + float core = 1.0 - smoothstep(0.0, coreRadius, distFromCenter); + + // Very subtle outer glow (Apple aesthetic) + float halo = smoothstep(haloRadius, coreRadius, distFromCenter); + + // Subtle color mixing + vec3 haloColor = vColor * 1.15; // Subtle brightness increase + vec3 baseColor = mix(vColor, vec3(1.0), vHighlight * 0.4); + vec3 finalColor = mix(haloColor, baseColor, core); + + // Alpha with subtle glow + float alpha = mix(halo * 0.4, 1.0, core); // Reduced halo opacity + + // Apply selection-based dimming (neutral-by-default) + alpha *= vSelectionHighlight; + + gl_FragColor = vec4(finalColor, alpha); + } + `, + }); + + return material; +} diff --git a/cognee-frontend/src/ui/rendering/materials/createPickingMaterial.ts b/cognee-frontend/src/ui/rendering/materials/createPickingMaterial.ts new file mode 100644 index 000000000..19aa3f176 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/materials/createPickingMaterial.ts @@ -0,0 +1,65 @@ +import * as three from "three"; + +export default function createPickingMaterial( + nodePositionsTexture: three.DataTexture, + initialCameraDistance: number +) { + const pickingMaterial = new three.ShaderMaterial({ + depthTest: true, + depthWrite: true, + transparent: false, + blending: three.NoBlending, + uniforms: { + nodePosTex: { value: nodePositionsTexture }, + textureSize: { value: nodePositionsTexture.image.width }, + camDist: { value: initialCameraDistance }, + }, + vertexShader: ` + precision highp float; + + uniform sampler2D nodePosTex; + uniform float textureSize; + uniform float camDist; + varying vec3 vColor; + + vec3 getNodePos(float idx) { + float size = textureSize; + float fx = mod(idx, size); + float fy = floor(idx / size); + vec2 uv = (vec2(fx, fy) + 0.5) / size; + return texture2D(nodePosTex, uv).xyz; + } + + void main() { + float id = float(gl_InstanceID); + vec3 nodePos = getNodePos(id); + vColor = vec3( + mod(id, 256.0) / 255.0, + mod(floor(id / 256.0), 256.0) / 255.0, + floor(id / 65536.0) / 255.0 + ); + // vColor = vec3(fract(sin(id * 12.9898) * 43758.5453)); + + float baseNodeSize = 4.0; + + // Normalize camera distance into [0,1] + float t = clamp((camDist - 500.0) / (2000.0 - 500.0), 0.0, 1.0); + float nodeSize = baseNodeSize * mix(1.0, 2.0, t); + + vec3 transformed = nodePos + position * nodeSize; + gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0); + } + `, + fragmentShader: ` + precision highp float; + + varying vec3 vColor; + + void main() { + gl_FragColor = vec4(vColor, 1.0); + } + `, + }); + + return pickingMaterial; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createClusterBoundaryMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createClusterBoundaryMesh.ts new file mode 100644 index 000000000..b5d033d32 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createClusterBoundaryMesh.ts @@ -0,0 +1,27 @@ +import * as three from "three"; +import createClusterBoundaryMaterial from "../materials/createClusterBoundaryMaterial"; + +export interface ClusterInfo { + center: { x: number; y: number }; + radius: number; + color: three.Color; +} + +export default function createClusterBoundaryMesh( + cluster: ClusterInfo +): three.Mesh { + // Create a circle geometry for the cluster boundary + const geometry = new three.PlaneGeometry( + cluster.radius * 2.5, // Make it larger to encompass the cluster + cluster.radius * 2.5 + ); + + const material = createClusterBoundaryMaterial(cluster.color); + const mesh = new three.Mesh(geometry, material); + + // Position the mesh at the cluster center + mesh.position.set(cluster.center.x, cluster.center.y, -100); // Behind everything else + mesh.renderOrder = -1; + + return mesh; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createDebugViewMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createDebugViewMesh.ts new file mode 100644 index 000000000..f5119070c --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createDebugViewMesh.ts @@ -0,0 +1,13 @@ +import { Mesh, PlaneGeometry, WebGLRenderTarget } from "three"; +import { createDebugViewMaterial } from "../materials/createDebugViewMaterial"; + +export default function createDebugViewMesh(renderTarget: WebGLRenderTarget) { + const debugQuad = new Mesh( + new PlaneGeometry(2, 2), + createDebugViewMaterial(renderTarget.texture) + ); + + debugQuad.frustumCulled = false; + + return debugQuad; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createDensityAccumulatorMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createDensityAccumulatorMesh.ts new file mode 100644 index 000000000..4ee44f460 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createDensityAccumulatorMesh.ts @@ -0,0 +1,33 @@ +import { + InstancedBufferAttribute, + InstancedMesh, + DataTexture, + PlaneGeometry, +} from "three"; +import { Node } from "../graph/types"; +import createDensityAccumulatorMaterial from "../materials/createDensityAccumulatorMaterial"; + +export default function createDensityAccumulatorMesh( + nodes: Node[], + nodeColors: Float32Array, + nodePositionsTexture: DataTexture, + initialCameraDistance: number +) { + const geometry = new PlaneGeometry(2, 2); + + const material = createDensityAccumulatorMaterial( + nodePositionsTexture, + initialCameraDistance + ); + + geometry.setAttribute( + "nodeColor", + new InstancedBufferAttribute(nodeColors, 3) + ); + + const mesh = new InstancedMesh(geometry, material, nodes.length); + + mesh.frustumCulled = false; + + return mesh; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createEdgeMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createEdgeMesh.ts new file mode 100644 index 000000000..0b299f498 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createEdgeMesh.ts @@ -0,0 +1,35 @@ +import * as three from "three"; +import createEdgeMaterial from "../materials/createEdgeMaterial"; +import { Edge } from "../graph/types"; + +export default function createEdgeMesh( + edges: Edge[], + nodePositionTexture: three.DataTexture, + edgeIndices: Float32Array, + initialCameraDistance: number +): three.LineSegments { + const numberOfEdges = edges.length; + + const instGeom = new three.InstancedBufferGeometry(); + instGeom.setAttribute( + "position", + new three.BufferAttribute(new Float32Array([0, 0, 0, 1, 0, 0]), 3) + ); + // instGeom.index = baseGeom.index; + instGeom.instanceCount = numberOfEdges; + + instGeom.setAttribute( + "edgeIndices", + new three.InstancedBufferAttribute(edgeIndices, 2) + ); + + const material = createEdgeMaterial( + nodePositionTexture, + initialCameraDistance + ); + + const edgeMesh = new three.LineSegments(instGeom, material); + edgeMesh.frustumCulled = false; + + return edgeMesh; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createLabel.ts b/cognee-frontend/src/ui/rendering/meshes/createLabel.ts new file mode 100644 index 000000000..1bce02f8e --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createLabel.ts @@ -0,0 +1,24 @@ +import { Color } from "three"; +import { Text } from "troika-three-text"; + +const LABEL_FONT_SIZE = 14; + +export default function createLabel(text = "", fontSize = LABEL_FONT_SIZE): Text { + const label = new Text(); + label.text = text; + label.fontSize = fontSize; + label.color = new Color("#ffffff"); + label.strokeColor = new Color("#ffffff"); + label.outlineWidth = 2; + label.outlineColor = new Color("#000000"); + label.outlineOpacity = 0.5; + label.anchorX = "center"; + label.anchorY = "middle"; + label.visible = true; + label.frustumCulled = false; + label.renderOrder = 5; + label.maxWidth = 200; + label.sync(); + + return label; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createMetaballMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createMetaballMesh.ts new file mode 100644 index 000000000..56faa25f5 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createMetaballMesh.ts @@ -0,0 +1,15 @@ +import { Mesh, PlaneGeometry, WebGLRenderTarget } from "three"; +import { createMetaballMaterial } from "../materials/createMetaballMaterial"; + +export default function createMetaballMesh( + fieldRenderTarget: WebGLRenderTarget +) { + const quadGeo = new PlaneGeometry(2, 2); + + const metaballMat = createMetaballMaterial(fieldRenderTarget.texture); + + const quad = new Mesh(quadGeo, metaballMat); + quad.frustumCulled = false; + + return quad; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createNodeSwarmMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createNodeSwarmMesh.ts new file mode 100644 index 000000000..9fe493046 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createNodeSwarmMesh.ts @@ -0,0 +1,39 @@ +import { + Mesh, + DataTexture, + CircleGeometry, + InstancedBufferAttribute, + InstancedBufferGeometry, +} from "three"; +import { Node } from "../graph/types"; +import createNodeSwarmMaterial from "../materials/createNodeSwarmMaterial"; + +export default function createNodeSwarmMesh( + nodes: Node[], + nodePositionsTexture: DataTexture, + nodeColors: Float32Array, + nodeSizes: Float32Array, + nodeHighlights: Float32Array, + initialCameraDistance: number +) { + const nodeGeom = new CircleGeometry(2, 16); + const geom = new InstancedBufferGeometry(); + geom.index = nodeGeom.index; + geom.instanceCount = nodes.length; + + geom.setAttribute("position", nodeGeom.attributes.position); + geom.setAttribute("uv", nodeGeom.attributes.uv); + geom.setAttribute("nodeColor", new InstancedBufferAttribute(nodeColors, 3)); + geom.setAttribute("nodeSize", new InstancedBufferAttribute(nodeSizes, 1)); + geom.setAttribute("nodeHighlight", new InstancedBufferAttribute(nodeHighlights, 1)); + + const material = createNodeSwarmMaterial( + nodePositionsTexture, + initialCameraDistance + ); + + const nodeSwarmMesh = new Mesh(geom, material); + nodeSwarmMesh.frustumCulled = false; + + return nodeSwarmMesh; +} diff --git a/cognee-frontend/src/ui/rendering/meshes/createPickingMesh.ts b/cognee-frontend/src/ui/rendering/meshes/createPickingMesh.ts new file mode 100644 index 000000000..90ca9e854 --- /dev/null +++ b/cognee-frontend/src/ui/rendering/meshes/createPickingMesh.ts @@ -0,0 +1,35 @@ +import { + Mesh, + DataTexture, + CircleGeometry, + InstancedBufferGeometry, + InstancedBufferAttribute, +} from "three"; +import { Node } from "../graph/types"; +import createPickingMaterial from "../materials/createPickingMaterial"; + +export default function createPickingMesh( + nodes: Node[], + nodePositionsTexture: DataTexture, + nodeColors: Float32Array, + initialCameraDistance: number +): Mesh { + const nodeGeom = new CircleGeometry(2, 16); + const geom = new InstancedBufferGeometry(); + geom.index = nodeGeom.index; + geom.instanceCount = nodes.length; + + geom.setAttribute("position", nodeGeom.attributes.position); + geom.setAttribute("uv", nodeGeom.attributes.uv); + geom.setAttribute("nodeColor", new InstancedBufferAttribute(nodeColors, 3)); + + const pickingMaterial = createPickingMaterial( + nodePositionsTexture, + initialCameraDistance + ); + + const pickingMesh = new Mesh(geom, pickingMaterial); + pickingMesh.frustumCulled = false; + + return pickingMesh; +} diff --git a/cognee-frontend/src/ui/rendering/picking/pickNodeIndex.ts b/cognee-frontend/src/ui/rendering/picking/pickNodeIndex.ts new file mode 100644 index 000000000..5c63100fa --- /dev/null +++ b/cognee-frontend/src/ui/rendering/picking/pickNodeIndex.ts @@ -0,0 +1,40 @@ +import { + OrthographicCamera, + Scene, + WebGLRenderer, + WebGLRenderTarget, +} from "three"; + +const pixelBuffer = new Uint8Array(4); + +export default function pickNodeIndex( + event: MouseEvent, + renderer: WebGLRenderer, + pickingScene: Scene, + camera: OrthographicCamera, + pickingRenderTarget: WebGLRenderTarget +) { + const rect = renderer.domElement.getBoundingClientRect(); + // Convert from client coords to pixel coords in render target + const x = + ((event.clientX - rect.left) / rect.width) * pickingRenderTarget.width; + const y = + pickingRenderTarget.height - + ((event.clientY - rect.top) / rect.height) * pickingRenderTarget.height; + + renderer.setRenderTarget(pickingRenderTarget); + renderer.clear(); + renderer.render(pickingScene, camera); + renderer.readRenderTargetPixels( + pickingRenderTarget, + Math.floor(x), + Math.floor(y), + 1, + 1, + pixelBuffer + ); + renderer.setRenderTarget(null); + + const id = pixelBuffer[0] + pixelBuffer[1] * 256 + pixelBuffer[2] * 256 * 256; + return id || -1; +} diff --git a/cognee-frontend/src/ui/rendering/render-targets/createDensityRenderTarget.ts b/cognee-frontend/src/ui/rendering/render-targets/createDensityRenderTarget.ts new file mode 100644 index 000000000..5a339c34c --- /dev/null +++ b/cognee-frontend/src/ui/rendering/render-targets/createDensityRenderTarget.ts @@ -0,0 +1,12 @@ +import { FloatType, LinearFilter, RGBAFormat, WebGLRenderTarget } from "three"; + +export default function createDensityRenderTarget(size = 512) { + return new WebGLRenderTarget(size, size, { + format: RGBAFormat, + type: FloatType, + minFilter: LinearFilter, + magFilter: LinearFilter, + depthBuffer: false, + stencilBuffer: false, + }); +} diff --git a/cognee-frontend/src/ui/rendering/textures/createNodePositionsTexture.ts b/cognee-frontend/src/ui/rendering/textures/createNodePositionsTexture.ts new file mode 100644 index 000000000..9ecc6d8bf --- /dev/null +++ b/cognee-frontend/src/ui/rendering/textures/createNodePositionsTexture.ts @@ -0,0 +1,28 @@ +import * as three from "three"; +import { Node } from "../graph/types"; + +export default function createNodePositionsTexture( + nodes: Node[], + nodePositionData: Float32Array +): three.DataTexture { + const textureSize = Math.ceil(Math.sqrt(nodes.length)); + + for (let i = 0; i < nodes.length; i++) { + nodePositionData[i * 4 + 0] = 0.0; + nodePositionData[i * 4 + 1] = 0.0; + nodePositionData[i * 4 + 2] = 0.0; + nodePositionData[i * 4 + 3] = 1.0; + } + + const texture = new three.DataTexture( + nodePositionData, + textureSize, + textureSize, + three.RGBAFormat, + three.FloatType + ); + texture.needsUpdate = true; + texture.minFilter = three.NearestFilter; + texture.magFilter = three.NearestFilter; + return texture; +} diff --git a/cognee-frontend/types/troika-three-text.d.ts b/cognee-frontend/types/troika-three-text.d.ts new file mode 100644 index 000000000..3ea9ba05a --- /dev/null +++ b/cognee-frontend/types/troika-three-text.d.ts @@ -0,0 +1,465 @@ +// /* eslint-disable @typescript-eslint/no-explicit-any */ +declare module "troika-three-text"; + +// import type { Color, Material, Object3D, Object3DEventMap } from "three"; + +// export class BatchedText { +// constructor(...args: any[]); + +// add(...args: any[]): void; + +// addText(...args: any[]): void; + +// copy(...args: any[]): void; + +// createDerivedMaterial(...args: any[]): void; + +// dispose(...args: any[]): void; + +// hasOutline(...args: any[]): void; + +// remove(...args: any[]): void; + +// removeText(...args: any[]): void; + +// sync(...args: any[]): void; + +// updateBounds(...args: any[]): void; + +// updateMatrixWorld(...args: any[]): void; + +// static DEFAULT_MATRIX_AUTO_UPDATE: boolean; + +// static DEFAULT_MATRIX_WORLD_AUTO_UPDATE: boolean; +// } + +// export class GlyphsGeometry { +// constructor(...args: any[]); + +// applyClipRect(...args: any[]): void; + +// computeBoundingBox(...args: any[]): void; + +// computeBoundingSphere(...args: any[]): void; + +// updateAttributeData(...args: any[]): void; + +// updateGlyphs(...args: any[]): void; +// } + +// export class Text extends Object3D { +// public text: string; +// public fontSize: number; +// public color: Color; +// public anchorX; +// public anchorY; +// public font: string; +// public material: Material; + +// constructor(...args: any[]): Object3D; + +// clone(...args: any[]): Object3D; + +// copy(...args: any[]): Object3D; + +// createDerivedMaterial(...args: any[]): void; + +// dispose(...args: any[]): void; + +// hasOutline(...args: any[]): void; + +// localPositionToTextCoords(...args: any[]): void; + +// onBeforeRender(...args: any[]): void; + +// raycast(...args: any[]): void; + +// sync(...args: any[]): void; + +// worldPositionToTextCoords(...args: any[]): void; + +// static DEFAULT_MATRIX_AUTO_UPDATE: boolean; + +// static DEFAULT_MATRIX_WORLD_AUTO_UPDATE: boolean; +// } + +// export function configureTextBuilder(config: any): void; + +// export function createTextDerivedMaterial(baseMaterial: any): any; + +// export function dumpSDFTextures(): void; + +// export function fontResolverWorkerModule(...args: any[]): any; + +// export function getCaretAtPoint(textRenderInfo: any, x: any, y: any): any; + +// export function getSelectionRects( +// textRenderInfo: any, +// start: any, +// end: any +// ): any; + +// export function getTextRenderInfo(args: any, callback: any): any; + +// export function preloadFont( +// { font, characters, sdfGlyphSize }: any, +// callback: any +// ): void; + +// export function typesetterWorkerModule(...args: any[]): any; + +// export namespace BatchedText { +// namespace DEFAULT_UP { +// const isVector3: boolean; + +// const x: number; + +// const y: number; + +// const z: number; + +// function add(...args: any[]): void; + +// function addScalar(...args: any[]): void; + +// function addScaledVector(...args: any[]): void; + +// function addVectors(...args: any[]): void; + +// function angleTo(...args: any[]): void; + +// function applyAxisAngle(...args: any[]): void; + +// function applyEuler(...args: any[]): void; + +// function applyMatrix3(...args: any[]): void; + +// function applyMatrix4(...args: any[]): void; + +// function applyNormalMatrix(...args: any[]): void; + +// function applyQuaternion(...args: any[]): void; + +// function ceil(...args: any[]): void; + +// function clamp(...args: any[]): void; + +// function clampLength(...args: any[]): void; + +// function clampScalar(...args: any[]): void; + +// function clone(...args: any[]): void; + +// function copy(...args: any[]): void; + +// function cross(...args: any[]): void; + +// function crossVectors(...args: any[]): void; + +// function distanceTo(...args: any[]): void; + +// function distanceToSquared(...args: any[]): void; + +// function divide(...args: any[]): void; + +// function divideScalar(...args: any[]): void; + +// function dot(...args: any[]): void; + +// function equals(...args: any[]): void; + +// function floor(...args: any[]): void; + +// function fromArray(...args: any[]): void; + +// function fromBufferAttribute(...args: any[]): void; + +// function getComponent(...args: any[]): void; + +// function length(...args: any[]): void; + +// function lengthSq(...args: any[]): void; + +// function lerp(...args: any[]): void; + +// function lerpVectors(...args: any[]): void; + +// function manhattanDistanceTo(...args: any[]): void; + +// function manhattanLength(...args: any[]): void; + +// function max(...args: any[]): void; + +// function min(...args: any[]): void; + +// function multiply(...args: any[]): void; + +// function multiplyScalar(...args: any[]): void; + +// function multiplyVectors(...args: any[]): void; + +// function negate(...args: any[]): void; + +// function normalize(...args: any[]): void; + +// function project(...args: any[]): void; + +// function projectOnPlane(...args: any[]): void; + +// function projectOnVector(...args: any[]): void; + +// function random(...args: any[]): void; + +// function randomDirection(...args: any[]): void; + +// function reflect(...args: any[]): void; + +// function round(...args: any[]): void; + +// function roundToZero(...args: any[]): void; + +// function set(...args: any[]): void; + +// function setComponent(...args: any[]): void; + +// function setFromColor(...args: any[]): void; + +// function setFromCylindrical(...args: any[]): void; + +// function setFromCylindricalCoords(...args: any[]): void; + +// function setFromEuler(...args: any[]): void; + +// function setFromMatrix3Column(...args: any[]): void; + +// function setFromMatrixColumn(...args: any[]): void; + +// function setFromMatrixPosition(...args: any[]): void; + +// function setFromMatrixScale(...args: any[]): void; + +// function setFromSpherical(...args: any[]): void; + +// function setFromSphericalCoords(...args: any[]): void; + +// function setLength(...args: any[]): void; + +// function setScalar(...args: any[]): void; + +// function setX(...args: any[]): void; + +// function setY(...args: any[]): void; + +// function setZ(...args: any[]): void; + +// function sub(...args: any[]): void; + +// function subScalar(...args: any[]): void; + +// function subVectors(...args: any[]): void; + +// function toArray(...args: any[]): void; + +// function transformDirection(...args: any[]): void; + +// function unproject(...args: any[]): void; +// } +// } + +// export namespace Text { +// namespace DEFAULT_UP { +// const isVector3: boolean; + +// const x: number; + +// const y: number; + +// const z: number; + +// function add(...args: any[]): void; + +// function addScalar(...args: any[]): void; + +// function addScaledVector(...args: any[]): void; + +// function addVectors(...args: any[]): void; + +// function angleTo(...args: any[]): void; + +// function applyAxisAngle(...args: any[]): void; + +// function applyEuler(...args: any[]): void; + +// function applyMatrix3(...args: any[]): void; + +// function applyMatrix4(...args: any[]): void; + +// function applyNormalMatrix(...args: any[]): void; + +// function applyQuaternion(...args: any[]): void; + +// function ceil(...args: any[]): void; + +// function clamp(...args: any[]): void; + +// function clampLength(...args: any[]): void; + +// function clampScalar(...args: any[]): void; + +// function clone(...args: any[]): void; + +// function copy(...args: any[]): void; + +// function cross(...args: any[]): void; + +// function crossVectors(...args: any[]): void; + +// function distanceTo(...args: any[]): void; + +// function distanceToSquared(...args: any[]): void; + +// function divide(...args: any[]): void; + +// function divideScalar(...args: any[]): void; + +// function dot(...args: any[]): void; + +// function equals(...args: any[]): void; + +// function floor(...args: any[]): void; + +// function fromArray(...args: any[]): void; + +// function fromBufferAttribute(...args: any[]): void; + +// function getComponent(...args: any[]): void; + +// function length(...args: any[]): void; + +// function lengthSq(...args: any[]): void; + +// function lerp(...args: any[]): void; + +// function lerpVectors(...args: any[]): void; + +// function manhattanDistanceTo(...args: any[]): void; + +// function manhattanLength(...args: any[]): void; + +// function max(...args: any[]): void; + +// function min(...args: any[]): void; + +// function multiply(...args: any[]): void; + +// function multiplyScalar(...args: any[]): void; + +// function multiplyVectors(...args: any[]): void; + +// function negate(...args: any[]): void; + +// function normalize(...args: any[]): void; + +// function project(...args: any[]): void; + +// function projectOnPlane(...args: any[]): void; + +// function projectOnVector(...args: any[]): void; + +// function random(...args: any[]): void; + +// function randomDirection(...args: any[]): void; + +// function reflect(...args: any[]): void; + +// function round(...args: any[]): void; + +// function roundToZero(...args: any[]): void; + +// function set(...args: any[]): void; + +// function setComponent(...args: any[]): void; + +// function setFromColor(...args: any[]): void; + +// function setFromCylindrical(...args: any[]): void; + +// function setFromCylindricalCoords(...args: any[]): void; + +// function setFromEuler(...args: any[]): void; + +// function setFromMatrix3Column(...args: any[]): void; + +// function setFromMatrixColumn(...args: any[]): void; + +// function setFromMatrixPosition(...args: any[]): void; + +// function setFromMatrixScale(...args: any[]): void; + +// function setFromSpherical(...args: any[]): void; + +// function setFromSphericalCoords(...args: any[]): void; + +// function setLength(...args: any[]): void; + +// function setScalar(...args: any[]): void; + +// function setX(...args: any[]): void; + +// function setY(...args: any[]): void; + +// function setZ(...args: any[]): void; + +// function sub(...args: any[]): void; + +// function subScalar(...args: any[]): void; + +// function subVectors(...args: any[]): void; + +// function toArray(...args: any[]): void; + +// function transformDirection(...args: any[]): void; + +// function unproject(...args: any[]): void; +// } +// } + +// export namespace fontResolverWorkerModule { +// const workerModuleData: { +// dependencies: { +// dependencies: any; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }[]; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }; + +// function onMainThread(...args: any[]): any; +// } + +// export namespace typesetterWorkerModule { +// const workerModuleData: { +// dependencies: { +// dependencies: any; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }[]; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }; + +// function onMainThread(...args: any[]): any; +// } diff --git a/cognee-frontend/types/troika-three-utils.d.ts b/cognee-frontend/types/troika-three-utils.d.ts new file mode 100644 index 000000000..80b0e9473 --- /dev/null +++ b/cognee-frontend/types/troika-three-utils.d.ts @@ -0,0 +1,465 @@ +// /* eslint-disable @typescript-eslint/no-explicit-any */ +declare module "troika-three-utils"; + +// import type { Color, Material, Object3D, Object3DEventMap } from "three"; + +// export class BatchedText { +// constructor(...args: any[]); + +// add(...args: any[]): void; + +// addText(...args: any[]): void; + +// copy(...args: any[]): void; + +// createDerivedMaterial(...args: any[]): void; + +// dispose(...args: any[]): void; + +// hasOutline(...args: any[]): void; + +// remove(...args: any[]): void; + +// removeText(...args: any[]): void; + +// sync(...args: any[]): void; + +// updateBounds(...args: any[]): void; + +// updateMatrixWorld(...args: any[]): void; + +// static DEFAULT_MATRIX_AUTO_UPDATE: boolean; + +// static DEFAULT_MATRIX_WORLD_AUTO_UPDATE: boolean; +// } + +// export class GlyphsGeometry { +// constructor(...args: any[]); + +// applyClipRect(...args: any[]): void; + +// computeBoundingBox(...args: any[]): void; + +// computeBoundingSphere(...args: any[]): void; + +// updateAttributeData(...args: any[]): void; + +// updateGlyphs(...args: any[]): void; +// } + +// export class Text extends Object3D { +// public text: string; +// public fontSize: number; +// public color: Color; +// public anchorX; +// public anchorY; +// public font: string; +// public material: Material; + +// constructor(...args: any[]): Object3D; + +// clone(...args: any[]): Object3D; + +// copy(...args: any[]): Object3D; + +// createDerivedMaterial(...args: any[]): void; + +// dispose(...args: any[]): void; + +// hasOutline(...args: any[]): void; + +// localPositionToTextCoords(...args: any[]): void; + +// onBeforeRender(...args: any[]): void; + +// raycast(...args: any[]): void; + +// sync(...args: any[]): void; + +// worldPositionToTextCoords(...args: any[]): void; + +// static DEFAULT_MATRIX_AUTO_UPDATE: boolean; + +// static DEFAULT_MATRIX_WORLD_AUTO_UPDATE: boolean; +// } + +// export function configureTextBuilder(config: any): void; + +// export function createTextDerivedMaterial(baseMaterial: any): any; + +// export function dumpSDFTextures(): void; + +// export function fontResolverWorkerModule(...args: any[]): any; + +// export function getCaretAtPoint(textRenderInfo: any, x: any, y: any): any; + +// export function getSelectionRects( +// textRenderInfo: any, +// start: any, +// end: any +// ): any; + +// export function getTextRenderInfo(args: any, callback: any): any; + +// export function preloadFont( +// { font, characters, sdfGlyphSize }: any, +// callback: any +// ): void; + +// export function typesetterWorkerModule(...args: any[]): any; + +// export namespace BatchedText { +// namespace DEFAULT_UP { +// const isVector3: boolean; + +// const x: number; + +// const y: number; + +// const z: number; + +// function add(...args: any[]): void; + +// function addScalar(...args: any[]): void; + +// function addScaledVector(...args: any[]): void; + +// function addVectors(...args: any[]): void; + +// function angleTo(...args: any[]): void; + +// function applyAxisAngle(...args: any[]): void; + +// function applyEuler(...args: any[]): void; + +// function applyMatrix3(...args: any[]): void; + +// function applyMatrix4(...args: any[]): void; + +// function applyNormalMatrix(...args: any[]): void; + +// function applyQuaternion(...args: any[]): void; + +// function ceil(...args: any[]): void; + +// function clamp(...args: any[]): void; + +// function clampLength(...args: any[]): void; + +// function clampScalar(...args: any[]): void; + +// function clone(...args: any[]): void; + +// function copy(...args: any[]): void; + +// function cross(...args: any[]): void; + +// function crossVectors(...args: any[]): void; + +// function distanceTo(...args: any[]): void; + +// function distanceToSquared(...args: any[]): void; + +// function divide(...args: any[]): void; + +// function divideScalar(...args: any[]): void; + +// function dot(...args: any[]): void; + +// function equals(...args: any[]): void; + +// function floor(...args: any[]): void; + +// function fromArray(...args: any[]): void; + +// function fromBufferAttribute(...args: any[]): void; + +// function getComponent(...args: any[]): void; + +// function length(...args: any[]): void; + +// function lengthSq(...args: any[]): void; + +// function lerp(...args: any[]): void; + +// function lerpVectors(...args: any[]): void; + +// function manhattanDistanceTo(...args: any[]): void; + +// function manhattanLength(...args: any[]): void; + +// function max(...args: any[]): void; + +// function min(...args: any[]): void; + +// function multiply(...args: any[]): void; + +// function multiplyScalar(...args: any[]): void; + +// function multiplyVectors(...args: any[]): void; + +// function negate(...args: any[]): void; + +// function normalize(...args: any[]): void; + +// function project(...args: any[]): void; + +// function projectOnPlane(...args: any[]): void; + +// function projectOnVector(...args: any[]): void; + +// function random(...args: any[]): void; + +// function randomDirection(...args: any[]): void; + +// function reflect(...args: any[]): void; + +// function round(...args: any[]): void; + +// function roundToZero(...args: any[]): void; + +// function set(...args: any[]): void; + +// function setComponent(...args: any[]): void; + +// function setFromColor(...args: any[]): void; + +// function setFromCylindrical(...args: any[]): void; + +// function setFromCylindricalCoords(...args: any[]): void; + +// function setFromEuler(...args: any[]): void; + +// function setFromMatrix3Column(...args: any[]): void; + +// function setFromMatrixColumn(...args: any[]): void; + +// function setFromMatrixPosition(...args: any[]): void; + +// function setFromMatrixScale(...args: any[]): void; + +// function setFromSpherical(...args: any[]): void; + +// function setFromSphericalCoords(...args: any[]): void; + +// function setLength(...args: any[]): void; + +// function setScalar(...args: any[]): void; + +// function setX(...args: any[]): void; + +// function setY(...args: any[]): void; + +// function setZ(...args: any[]): void; + +// function sub(...args: any[]): void; + +// function subScalar(...args: any[]): void; + +// function subVectors(...args: any[]): void; + +// function toArray(...args: any[]): void; + +// function transformDirection(...args: any[]): void; + +// function unproject(...args: any[]): void; +// } +// } + +// export namespace Text { +// namespace DEFAULT_UP { +// const isVector3: boolean; + +// const x: number; + +// const y: number; + +// const z: number; + +// function add(...args: any[]): void; + +// function addScalar(...args: any[]): void; + +// function addScaledVector(...args: any[]): void; + +// function addVectors(...args: any[]): void; + +// function angleTo(...args: any[]): void; + +// function applyAxisAngle(...args: any[]): void; + +// function applyEuler(...args: any[]): void; + +// function applyMatrix3(...args: any[]): void; + +// function applyMatrix4(...args: any[]): void; + +// function applyNormalMatrix(...args: any[]): void; + +// function applyQuaternion(...args: any[]): void; + +// function ceil(...args: any[]): void; + +// function clamp(...args: any[]): void; + +// function clampLength(...args: any[]): void; + +// function clampScalar(...args: any[]): void; + +// function clone(...args: any[]): void; + +// function copy(...args: any[]): void; + +// function cross(...args: any[]): void; + +// function crossVectors(...args: any[]): void; + +// function distanceTo(...args: any[]): void; + +// function distanceToSquared(...args: any[]): void; + +// function divide(...args: any[]): void; + +// function divideScalar(...args: any[]): void; + +// function dot(...args: any[]): void; + +// function equals(...args: any[]): void; + +// function floor(...args: any[]): void; + +// function fromArray(...args: any[]): void; + +// function fromBufferAttribute(...args: any[]): void; + +// function getComponent(...args: any[]): void; + +// function length(...args: any[]): void; + +// function lengthSq(...args: any[]): void; + +// function lerp(...args: any[]): void; + +// function lerpVectors(...args: any[]): void; + +// function manhattanDistanceTo(...args: any[]): void; + +// function manhattanLength(...args: any[]): void; + +// function max(...args: any[]): void; + +// function min(...args: any[]): void; + +// function multiply(...args: any[]): void; + +// function multiplyScalar(...args: any[]): void; + +// function multiplyVectors(...args: any[]): void; + +// function negate(...args: any[]): void; + +// function normalize(...args: any[]): void; + +// function project(...args: any[]): void; + +// function projectOnPlane(...args: any[]): void; + +// function projectOnVector(...args: any[]): void; + +// function random(...args: any[]): void; + +// function randomDirection(...args: any[]): void; + +// function reflect(...args: any[]): void; + +// function round(...args: any[]): void; + +// function roundToZero(...args: any[]): void; + +// function set(...args: any[]): void; + +// function setComponent(...args: any[]): void; + +// function setFromColor(...args: any[]): void; + +// function setFromCylindrical(...args: any[]): void; + +// function setFromCylindricalCoords(...args: any[]): void; + +// function setFromEuler(...args: any[]): void; + +// function setFromMatrix3Column(...args: any[]): void; + +// function setFromMatrixColumn(...args: any[]): void; + +// function setFromMatrixPosition(...args: any[]): void; + +// function setFromMatrixScale(...args: any[]): void; + +// function setFromSpherical(...args: any[]): void; + +// function setFromSphericalCoords(...args: any[]): void; + +// function setLength(...args: any[]): void; + +// function setScalar(...args: any[]): void; + +// function setX(...args: any[]): void; + +// function setY(...args: any[]): void; + +// function setZ(...args: any[]): void; + +// function sub(...args: any[]): void; + +// function subScalar(...args: any[]): void; + +// function subVectors(...args: any[]): void; + +// function toArray(...args: any[]): void; + +// function transformDirection(...args: any[]): void; + +// function unproject(...args: any[]): void; +// } +// } + +// export namespace fontResolverWorkerModule { +// const workerModuleData: { +// dependencies: { +// dependencies: any; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }[]; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }; + +// function onMainThread(...args: any[]): any; +// } + +// export namespace typesetterWorkerModule { +// const workerModuleData: { +// dependencies: { +// dependencies: any; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }[]; +// getTransferables: any; +// id: string; +// init: string; +// isWorkerModule: boolean; +// name: string; +// }; + +// function onMainThread(...args: any[]): any; +// } diff --git a/cognee/api/v1/datasets/routers/get_datasets_router.py b/cognee/api/v1/datasets/routers/get_datasets_router.py index afd2b2cce..dce6e7f41 100644 --- a/cognee/api/v1/datasets/routers/get_datasets_router.py +++ b/cognee/api/v1/datasets/routers/get_datasets_router.py @@ -58,6 +58,7 @@ class DataDTO(OutDTO): class GraphNodeDTO(OutDTO): id: UUID label: str + type: str properties: dict