diff --git a/package-lock.json b/package-lock.json
index e6e89ee..2f259f9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,18 @@
{
- "name": "ajaayc.github.io_n",
+ "name": "ajaayc.github.io",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "ajaayc.github.io_n",
+ "name": "ajaayc.github.io",
"version": "0.1.0",
"dependencies": {
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^13.5.0",
- "framer-motion": "^12.23.26",
+ "framer-motion": "^12.26.2",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-icons": "^5.5.0",
@@ -21,6 +21,7 @@
"web-vitals": "^2.1.4"
},
"devDependencies": {
+ "gh-pages": "^6.3.0",
"tailwindcss": "^3.4.19"
}
},
@@ -70,7 +71,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -720,7 +720,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1604,7 +1603,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.1",
"@babel/helper-module-imports": "^7.27.1",
@@ -3334,7 +3332,6 @@
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -3812,7 +3809,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.62.0",
@@ -3866,7 +3862,6 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@@ -4236,7 +4231,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4335,7 +4329,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -5243,7 +5236,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6771,6 +6763,13 @@
"integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
"license": "ISC"
},
+ "node_modules/email-addresses": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
+ "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/emittery": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
@@ -7092,7 +7091,6 @@
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -7999,6 +7997,34 @@
"node": ">=10"
}
},
+ "node_modules/filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/filenamify": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+ "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.1",
+ "trim-repeated": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/filesize": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz",
@@ -8274,13 +8300,13 @@
}
},
"node_modules/framer-motion": {
- "version": "12.23.26",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.26.tgz",
- "integrity": "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==",
+ "version": "12.26.2",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.26.2.tgz",
+ "integrity": "sha512-lflOQEdjquUi9sCg5Y1LrsZDlsjrHw7m0T9Yedvnk7Bnhqfkc89/Uha10J3CFhkL+TCZVCRw9eUGyM/lyYhXQA==",
"license": "MIT",
"dependencies": {
- "motion-dom": "^12.23.23",
- "motion-utils": "^12.23.6",
+ "motion-dom": "^12.26.2",
+ "motion-utils": "^12.24.10",
"tslib": "^2.4.0"
},
"peerDependencies": {
@@ -8495,6 +8521,54 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gh-pages": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.3.0.tgz",
+ "integrity": "sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.2.4",
+ "commander": "^13.0.0",
+ "email-addresses": "^5.0.0",
+ "filenamify": "^4.3.0",
+ "find-cache-dir": "^3.3.1",
+ "fs-extra": "^11.1.1",
+ "globby": "^11.1.0"
+ },
+ "bin": {
+ "gh-pages": "bin/gh-pages.js",
+ "gh-pages-clean": "bin/gh-pages-clean.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/gh-pages/node_modules/commander": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
+ "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/gh-pages/node_modules/fs-extra": {
+ "version": "11.3.3",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz",
+ "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -9866,7 +9940,6 @@
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@jest/core": "^27.5.1",
"import-local": "^3.0.2",
@@ -10752,7 +10825,6 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"license": "MIT",
- "peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -11385,18 +11457,18 @@
}
},
"node_modules/motion-dom": {
- "version": "12.23.23",
- "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
- "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
+ "version": "12.26.2",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.26.2.tgz",
+ "integrity": "sha512-KLMT1BroY8oKNeliA3JMNJ+nbCIsTKg6hJpDb4jtRAJ7nCKnnpg/LTq/NGqG90Limitz3kdAnAVXecdFVGlWTw==",
"license": "MIT",
"dependencies": {
- "motion-utils": "^12.23.6"
+ "motion-utils": "^12.24.10"
}
},
"node_modules/motion-utils": {
- "version": "12.23.6",
- "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
- "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "version": "12.24.10",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.24.10.tgz",
+ "integrity": "sha512-x5TFgkCIP4pPsRLpKoI86jv/q8t8FQOiM/0E8QKBzfMozWHfkKap2gA1hOki+B5g3IsBNpxbUnfOum1+dgvYww==",
"license": "MIT"
},
"node_modules/ms": {
@@ -12114,7 +12186,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -13249,7 +13320,6 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -13597,7 +13667,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -13729,7 +13798,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -13769,7 +13837,6 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -14216,7 +14283,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"license": "MIT",
- "peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -14459,7 +14525,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -15443,6 +15508,29 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-outer/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/style-loader": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz",
@@ -16038,7 +16126,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -16109,6 +16196,29 @@
"node": ">=8"
}
},
+ "node_modules/trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/trim-repeated/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/tryer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
@@ -16311,9 +16421,9 @@
}
},
"node_modules/typescript": {
- "version": "5.9.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"license": "Apache-2.0",
"peer": true,
"bin": {
@@ -16321,7 +16431,7 @@
"tsserver": "bin/tsserver"
},
"engines": {
- "node": ">=14.17"
+ "node": ">=4.2.0"
}
},
"node_modules/unbox-primitive": {
@@ -16636,7 +16746,6 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
"integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.8",
@@ -17120,7 +17229,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
diff --git a/src/RRTPromptPanel.jsx b/src/RRTPromptPanel.jsx
index 7c9bb6c..d08a966 100644
--- a/src/RRTPromptPanel.jsx
+++ b/src/RRTPromptPanel.jsx
@@ -1,55 +1,131 @@
// RRTPromptPanel.jsx
import React, { useState, useEffect, useRef } from "react";
+// Constants defined outside component to avoid re-creation
+const RAW_PROMPT_TEXT = [
+ "ajaay@SPECTRAL-PC ~ > \\",
+ "cat something_cool.txt",
+ "",
+ "The bidirectional RRT-connect algorithm is my personal favorite.",
+ "",
+ "It elicits a spectacular probabilistic dance...two rapidly expanding trees of nodes in the configuration space.",
+ "",
+ "Reaching towards each other to find a connection... a collision-free path from start to end.",
+ "",
+ "Want to see it live in action?",
+ "",
+ "ajaay@SPECTRAL-PC ~ > \\",
+ "bazel build //main:rrt_runner",
+ "",
+ "INFO: Build completed successfully, 2 total actions",
+ "",
+ "ajaay@SPECTRAL-PC ~ > \\",
+ "bazel run ///main:rrt_runner",
+ "------------------------------------",
+ " Press ENTER to run ",
+ " the bidirectional RRT ",
+ "------------------------------------"
+];
+
+const HIGHLIGHT_LINES = [
+ "------------------------------------",
+ " Press ENTER to run ",
+ " the bidirectional RRT ",
+ "------------------------------------"
+];
+
export default function RRTPromptPanel({ onEnter, height = 755 }) {
const canvasRef = useRef(null);
const [showCursor, setShowCursor] = useState(true);
const [entered, setEntered] = useState(false);
const [linesToDisplay, setLinesToDisplay] = useState([]);
const [charIndex, setCharIndex] = useState(0);
+ const [promptLines, setPromptLines] = useState([]);
+
+ // Wrap text based on canvas width
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return; // Guard against null context
+
+ const width = canvas.offsetWidth;
+ const fontSize = 16;
+ const padding = fontSize * 2;
+ const font = `${fontSize}px monospace`;
+
+ function wrapText() {
+ const maxWidth = width - padding * 2;
+ ctx.font = font; // Set font for measurement
+
+ const wrappedLines = [];
+ RAW_PROMPT_TEXT.forEach((para) => {
+ // Keep empty lines as-is
+ if (para === "") {
+ wrappedLines.push("");
+ return;
+ }
+
+ // Don't wrap highlight lines
+ if (HIGHLIGHT_LINES.includes(para)) {
+ wrappedLines.push(para);
+ return;
+ }
+
+ // Wrap regular text
+ const words = para.split(" ");
+ let line = "";
+ words.forEach((word) => {
+ const testLine = line + word + " ";
+ if (ctx.measureText(testLine).width > maxWidth) {
+ if (line !== "") {
+ wrappedLines.push(line.trim());
+ line = word + " ";
+ } else {
+ // Word is too long, add it anyway
+ wrappedLines.push(word);
+ line = "";
+ }
+ } else {
+ line = testLine;
+ }
+ });
+ if (line !== "") {
+ wrappedLines.push(line.trim());
+ }
+ });
+
+ setPromptLines(wrappedLines);
+ }
+
+ // Initial wrap
+ wrapText();
+
+ // Re-wrap on resize with debouncing
+ let resizeTimeout;
+ function handleResize() {
+ clearTimeout(resizeTimeout);
+ resizeTimeout = setTimeout(() => {
+ wrapText();
+ }, 150); // Debounce resize events
+ }
- const promptLines = [
- "ajaay@SPECTRAL-PC ~ > \\",
- "cat something_cool.txt",
- "",
- "The bidirectional RRT-connect",
- "algorithm is my personal favorite.",
- "my personal favorite.",
- "",
- "It elicits a spectacular probabilistic",
- "dance...two rapidly expanding trees",
- "of nodes in the configuration space.",
- "",
- "Reaching towards each other to find a",
- "connection... a collision-free path",
- "from start to end.",
- "",
- "Want to see it live in action?",
- "",
- "ajaay@SPECTRAL-PC ~ > \\",
- "bazel build //main:rrt_runner",
- "",
- "INFO: Build completed successfully,",
- "2 total actions",
- "",
- "ajaay@SPECTRAL-PC ~ > \\",
- "bazel run ///main:rrt_runner",
- "------------------------------------",
- " Press ENTER to run ",
- " the bidirectional RRT ",
- "------------------------------------"
- ];
-
- const highlightLines = [
- "------------------------------------",
- " Press ENTER to run ",
- " the bidirectional RRT ",
- "------------------------------------"
- ];
+ window.addEventListener("resize", handleResize);
+
+ return () => {
+ clearTimeout(resizeTimeout);
+ window.removeEventListener("resize", handleResize);
+ };
+ }, [height]); // Only re-run when height changes
useEffect(() => {
const canvas = canvasRef.current;
+ if (!canvas) return;
+
const ctx = canvas.getContext("2d");
+ if (!ctx) return; // Guard against null context
+
const width = canvas.offsetWidth;
const heightPx = height;
@@ -81,7 +157,7 @@ export default function RRTPromptPanel({ onEnter, height = 755 }) {
const x = padding;
const y = padding + i * lineHeight;
- if (highlightLines.includes(line)) {
+ if (HIGHLIGHT_LINES.includes(line)) {
const pulse = !entered
? 8 + 6 * Math.sin(Date.now() * 0.004)
: 6;
@@ -105,7 +181,7 @@ export default function RRTPromptPanel({ onEnter, height = 755 }) {
const x = padding;
const y = padding + linesToDisplay.length * lineHeight;
- if (highlightLines.includes(fullLine)) {
+ if (HIGHLIGHT_LINES.includes(fullLine)) {
const pulse = 8 + 6 * Math.sin(Date.now() * 0.004);
ctx.shadowBlur = pulse;
ctx.font = boldFont;
@@ -156,8 +232,10 @@ export default function RRTPromptPanel({ onEnter, height = 755 }) {
}
loop();
- return () => cancelAnimationFrame(animationFrame);
- }, [showCursor, linesToDisplay, charIndex, entered, height]);
+ return () => {
+ cancelAnimationFrame(animationFrame);
+ };
+ }, [showCursor, linesToDisplay, charIndex, entered, height, promptLines]);
// Cursor blink
useEffect(() => {
@@ -182,7 +260,7 @@ export default function RRTPromptPanel({ onEnter, height = 755 }) {
}, 10);
return () => clearTimeout(timeout);
- }, [charIndex, linesToDisplay, entered]);
+ }, [charIndex, linesToDisplay, entered, promptLines]);
// Enter key listener
useEffect(() => {
diff --git a/src/RRTPromptPanel.test.jsx b/src/RRTPromptPanel.test.jsx
new file mode 100644
index 0000000..65525eb
--- /dev/null
+++ b/src/RRTPromptPanel.test.jsx
@@ -0,0 +1,12 @@
+import { render } from '@testing-library/react';
+import RRTPromptPanel from './RRTPromptPanel';
+
+test('renders RRTPromptPanel without crashing', () => {
+ const mockOnEnter = jest.fn();
+ render();
+});
+
+test('renders RRTPromptPanel with custom height', () => {
+ const mockOnEnter = jest.fn();
+ render();
+});