]> git.taranathan.com Git - FRC2026.git/commitdiff
wesley mirror path :) new mirror tool
authormaxwtan <100314265+MaxwellTTan20@users.noreply.github.com>
Sat, 14 Mar 2026 02:42:58 +0000 (19:42 -0700)
committermaxwtan <100314265+MaxwellTTan20@users.noreply.github.com>
Sat, 14 Mar 2026 02:42:58 +0000 (19:42 -0700)
src/main/deploy/pathplanner/autos/Right Week V1.auto [new file with mode: 0644]
src/main/deploy/pathplanner/paths/Full Right Path v3.path [new file with mode: 0644]
tools/PathPlannerMirror2026-main/.gitignore [new file with mode: 0644]
tools/PathPlannerMirror2026-main/LICENSE [new file with mode: 0644]
tools/PathPlannerMirror2026-main/README.md [new file with mode: 0644]
tools/PathPlannerMirror2026-main/index.css [new file with mode: 0644]
tools/PathPlannerMirror2026-main/index.html [new file with mode: 0644]
tools/PathPlannerMirror2026-main/index.js [new file with mode: 0644]

diff --git a/src/main/deploy/pathplanner/autos/Right Week V1.auto b/src/main/deploy/pathplanner/autos/Right Week V1.auto
new file mode 100644 (file)
index 0000000..f34456d
--- /dev/null
@@ -0,0 +1,61 @@
+{
+  "version": "2025.0",
+  "command": {
+    "type": "sequential",
+    "data": {
+      "commands": [
+        {
+          "type": "wait",
+          "data": {
+            "waitTime": 0.2
+          }
+        },
+        {
+          "type": "named",
+          "data": {
+            "name": "Extend Intake"
+          }
+        },
+        {
+          "type": "wait",
+          "data": {
+            "waitTime": 0.1
+          }
+        },
+        {
+          "type": "named",
+          "data": {
+            "name": "Start Spindexer"
+          }
+        },
+        {
+          "type": "wait",
+          "data": {
+            "waitTime": 1.0
+          }
+        },
+        {
+          "type": "named",
+          "data": {
+            "name": "Stop Spindexer"
+          }
+        },
+        {
+          "type": "named",
+          "data": {
+            "name": "Hood Down"
+          }
+        },
+        {
+          "type": "path",
+          "data": {
+            "pathName": "Full Right Path v3"
+          }
+        }
+      ]
+    }
+  },
+  "resetOdom": true,
+  "folder": null,
+  "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Full Right Path v3.path b/src/main/deploy/pathplanner/paths/Full Right Path v3.path
new file mode 100644 (file)
index 0000000..17bee8a
--- /dev/null
@@ -0,0 +1 @@
+{"version":"2025.0","waypoints":[{"anchor":{"x":3.8,"y":0.4481350154264931},"prevControl":null,"nextControl":{"x":6.993921116983211,"y":0.4481350154264931},"isLocked":false,"linkedName":null},{"anchor":{"x":7.667485172004747,"y":1.642405478054566},"prevControl":{"x":7.665365003292386,"y":1.3845651641599017},"nextControl":{"x":7.684288184321054,"y":3.6858720874587565},"isLocked":false,"linkedName":null},{"anchor":{"x":7.667485172004747,"y":3.406913188612099},"prevControl":{"x":7.722519349903317,"y":3.1630459311480665},"nextControl":{"x":7.611361211994106,"y":3.655609484776302},"isLocked":false,"linkedName":null},{"anchor":{"x":6.236512455516015,"y":2.987304647686832},"prevControl":{"x":7.118832485314941,"y":3.517259257915697},"nextControl":{"x":5.563661514586408,"y":2.583165054229189},"isLocked":false,"linkedName":null},{"anchor":{"x":6.236512455516015,"y":1.0398906500593113},"prevControl":{"x":6.607692290036552,"y":1.9733939152629345},"nextControl":{"x":5.905339551755663,"y":0.20700330474705114},"isLocked":false,"linkedName":null},{"anchor":{"x":0.6955278766310802,"y":0.4481350154264931},"prevControl":{"x":-0.09030729073703303,"y":0.4481350154264931},"nextControl":null,"isLocked":false,"linkedName":null}],"rotationTargets":[{"waypointRelativePos":1.087033747779748,"rotationDegrees":90},{"waypointRelativePos":2.5364120781527437,"rotationDegrees":-155.02674741986806},{"waypointRelativePos":3.85,"rotationDegrees":-138.60721817200425},{"waypointRelativePos":4.4,"rotationDegrees":-180},{"waypointRelativePos":4.660237388724038,"rotationDegrees":-180},{"waypointRelativePos":5,"rotationDegrees":-180}],"constraintZones":[{"name":"Depot","minWaypointRelativePos":4.953880764904385,"maxWaypointRelativePos":5.5,"constraints":{"maxVelocity":0.5,"maxAcceleration":2,"maxAngularVelocity":200,"maxAngularAcceleration":300,"nominalVoltage":12,"unlimited":false}},{"name":"Constraints Zone","minWaypointRelativePos":0.9718785151856066,"maxWaypointRelativePos":2.4701912260967447,"constraints":{"maxVelocity":0.3,"maxAcceleration":2,"maxAngularVelocity":200,"maxAngularAcceleration":300,"nominalVoltage":12,"unlimited":false}},{"name":"Constraints Zone","minWaypointRelativePos":2.767154105736777,"maxWaypointRelativePos":4.467941507311604,"constraints":{"maxVelocity":2,"maxAcceleration":1,"maxAngularVelocity":200,"maxAngularAcceleration":300,"nominalVoltage":12,"unlimited":false}},{"name":"Starting Slow","minWaypointRelativePos":0,"maxWaypointRelativePos":0.1,"constraints":{"maxVelocity":0.5,"maxAcceleration":0.5,"maxAngularVelocity":200,"maxAngularAcceleration":150,"nominalVoltage":12,"unlimited":false}}],"pointTowardsZones":[],"eventMarkers":[{"name":"Hood Down","waypointRelativePos":0,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Hood Down"}}},{"name":"Extend Intake","waypointRelativePos":0.0944881889763795,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Extend Intake"}}},{"name":"Spin Intake Rollers","waypointRelativePos":0.17547806524185328,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Spin Intake Rollers"}}},{"name":"Start Spindexer","waypointRelativePos":0.3104611923509808,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Start Spindexer"}}},{"name":"Stop Hood Down","waypointRelativePos":0.39145106861638246,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Stop Hood Down"}}},{"name":"Stop Spindexer","waypointRelativePos":2.9156355455568033,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Stop Spindexer"}}},{"name":"Hood Down","waypointRelativePos":3.3745781777277815,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Hood Down"}}},{"name":"Stop Hood Down","waypointRelativePos":4.724409448818935,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Stop Hood Down"}}},{"name":"Start Spindexer","waypointRelativePos":4.764904386951711,"endWaypointRelativePos":null,"command":{"type":"named","data":{"name":"Start Spindexer"}}}],"globalConstraints":{"maxVelocity":1.5,"maxAcceleration":1.5,"maxAngularVelocity":200,"maxAngularAcceleration":150,"nominalVoltage":12,"unlimited":false},"goalEndState":{"velocity":0,"rotation":-180},"reversed":false,"folder":"week 2 autos","idealStartingState":{"velocity":0,"rotation":0},"useDefaultConstraints":false}
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/.gitignore b/tools/PathPlannerMirror2026-main/.gitignore
new file mode 100644 (file)
index 0000000..496ee2c
--- /dev/null
@@ -0,0 +1 @@
+.DS_Store
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/LICENSE b/tools/PathPlannerMirror2026-main/LICENSE
new file mode 100644 (file)
index 0000000..226738f
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 OLIVER427
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/README.md b/tools/PathPlannerMirror2026-main/README.md
new file mode 100644 (file)
index 0000000..7608416
--- /dev/null
@@ -0,0 +1,23 @@
+# Info!
+yes info. please read.
+
+## How to use
+Hopefully this is easy enough to figure out how to use, but I can explain quick details anyway.
+- Click on the file input button and select your ".path" file
+- Click the "Process Path File"
+- you have the option of checking the Mirror Vertically and/or Horizontally boxes
+- click "Export Mirrored Path" if you'd like to download the mirrored path you are currently previewing
+- click "Export All Mirrors" to download every possible mirror of the path you inputed.
+- also, remember to put your newly downloaded files in the paths folder in your pathplanner project directory
+
+if you are using the auto mirroring part, its a pretty similar process.
+
+## Specifications (THIS IS PRETTY IMPORTANT)
+The way the site calculates where the path is in the path mirrorer, (for the naming specifically) is that it detects which corner has a at least 50% of the line inside it.
+
+If you want to use the auto mirrorer, make sure that you've already used the paths in the path mirrorer because literally the ONLY thing that the auto mirror does is rename the path names inside of it to have a prefix that fits the naming of the path mirror (for example, "TopRight New Auto").
+
+The visualization of the path in the path mirrorer just visualizes the direct lines from the startpoint to endpoint of the path because the I cannot figure out how the curved lines are supposed to come out of the path file (its so weird. They calculate it somehow in the app and the curve values you put in there are just calculated to one single number in the path file.)
+
+# well met!
+Well, thats pretty much it, Have fun mirroring!
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/index.css b/tools/PathPlannerMirror2026-main/index.css
new file mode 100644 (file)
index 0000000..8f2356c
--- /dev/null
@@ -0,0 +1,141 @@
+html {
+    color: white;
+    font-family: "SUSE" !important;
+}
+
+body {
+    background-color: #1e1f2a;
+}
+
+p {
+    font-size: 1vw;
+    text-align: center;
+}
+
+label {
+    font-size: 1vw;
+}
+
+pre {
+    font-size: 1vw;
+    width: 50%;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+button,
+#pathInput::file-selector-button,
+#autoInput::file-selector-button {
+    font-size: 1vw;
+    font-family: "SUSE";
+    border: 0.2vw solid #8089ff;
+    border-radius: 0.5vw;
+    background-color: #8089ff;
+    color: #181982;
+    transition-duration: 150ms;
+    transition-property: background-color, border;
+}
+
+button:hover,
+#pathInput::file-selector-button:hover,
+#autoInput::file-selector-button:hover {
+    cursor: pointer;
+    background-color: #6f76dc;
+    border: 0.2vw solid #6f76dc;
+}
+
+#toggleModeBtn {
+    border: 0.2vw solid #ff80f9;
+    background-color: #ff80f9;
+    color: #8c1a86;
+    margin-left: 0.7vw;
+}
+
+#toggleModeBtn:hover {
+    background-color: #cf6aca;
+    border: 0.2vw solid #cf6aca;
+}
+
+#infoText {
+    font-size: 1vw !important;
+    color: #3c3d4d;
+    transition-duration: 150ms;
+    transition-property: opacity;
+}
+
+#downloadBtn,
+#downloadAllBtn,
+#exportAuto {
+    /* transition-duration: 250ms; */
+    transition-property: opacity, background-color, border;
+    opacity: 0;
+    visibility: hidden;
+}
+
+#exportAuto {
+    transition-property: opacity, background-color, border;
+    /* opacity: 0; */
+    visibility: hidden;
+}
+
+#downloadAllBtn {
+    margin-left: 1vw;
+}
+
+#horizontal,
+#vertical {
+    width: 1vw;
+    height: auto;
+}
+
+
+#centerDiv,
+#centerDiv2 {
+    background-color: #12121d;
+    position: fixed;
+    transform: translate(-50%, -50%);
+    left: 50%;
+    top: 50%;
+    display: flex;
+    flex-direction: column;
+    justify-content: start;
+    align-items: center;
+    width: 80vw;
+    height: 40vw;
+    border-radius: 2vw;
+    box-shadow: #0e0e17 0vw 0vw 3vw;
+    transition-duration: 200ms;
+    transition-property: opacity;
+}
+
+#centerDiv>*,
+#centerDiv2>* {
+    margin-bottom: 0.7vw;
+}
+
+#centerDiv2 {
+    overflow: scroll;
+}
+
+#graph,
+#autoList {
+    background-color: #08080d;
+    border-radius: 1vw;
+    width: 41.25vw;
+    height: 20vw;
+    display:  flex;
+    align-items: start;
+    overflow-y: scroll;
+    overflow-x: hidden;
+}
+
+#pathInput,
+#autoInput {
+    color: white;
+    font-size: 1vw;
+    font-style: italic;
+    /* margin-right: -5vw; */
+    margin-right: 0vw;
+    width: 14vw;
+    font-family: "SUSE"
+}
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/index.html b/tools/PathPlannerMirror2026-main/index.html
new file mode 100644 (file)
index 0000000..7e4194d
--- /dev/null
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="stylesheet" href="index.css">
+    <link rel="icon" href="https://team2480.org/favicon.svg">
+    <link rel="preconnect" href="https://fonts.googleapis.com">
+    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+    <link rel="stylesheet"
+        href="https://fonts.googleapis.com/css2?family=Playwrite+AU+QLD:wght@100..400&family=SUSE:ital,wght@0,100..900;1,100..900&display=swap">
+    <title>2026 Path Mirrorer</title>
+</head>
+
+<body>
+    <div id="centerDiv">
+        <p id="infoText">Preview (no curved lines) of path before mirroring it</p>
+        <canvas id="graph" width="1650" height="800"></canvas>
+        <span>
+            <input type="file" id="pathInput" accept=".path">
+            <button title="Finish loading in the .path file" id="visualizeBtn"
+                onclick="if (fileLoaded){visualizePath()}"
+                style="visibility: hidden; width:0vw; font-size: 0vw;">Process Path File</button>
+            <button id="toggleModeBtn" onclick="switchModes()">Mirror Autos Instead</button>
+        </span>
+        <label>
+            <input type="checkbox" id="vertical" onclick="if (fileVisualized){visualizePath()}">
+            Mirror Vertically</label>
+        <label>
+            <input type="checkbox" id="horizontal" onclick="if (fileVisualized){visualizePath()}">Mirror
+            Horizontally</label>
+        <span>
+            <button onclick="exportPath()" id="downloadBtn"
+                title="Downloads the currently displayed mirror of the path">Export Mirrored Path</button>
+            <button onclick="exportAllMirrors()" id="downloadAllBtn"
+                title="Downloads all possible mirrors of the current path.">Export All Mirrors</button>
+        </span>
+    </div>
+    <div id="centerDiv2" style="visibility: hidden; opacity: 0;">
+        <p id="infoText">(WARNING: The auto mirrorer is experimental and will not work with autos with paths in
+            different corners)</p>
+        <div id="autoList">
+            <pre>
+
+            </pre>
+            <pre>
+
+            </pre>
+        </div>
+        <span>
+            <input type="file" id="autoInput" accept=".auto"><button title="Finish loading in the .auto file"
+                id="visualizeBtn2" onclick="if (autoLoaded){visualizeAuto()}"
+                style="visibility: hidden; width:0vw; font-size: 0vw;">Process Auto File</button><button
+                id="toggleModeBtn" onclick="switchModes()">Mirror Paths Instead</button>
+        </span>
+        <p>(you must have already used the paths in this auto in the path mirrorer and have not renamed
+            them)<br />Select the area you are
+            converting to:</p>
+        <span id="selectArea">
+            <label>
+                <input name="area" type="radio" id="bottomR" onclick="if (autoVisualized){visualizeAuto()}">Bottom
+                Right</label>
+            <label>
+                <input name="area" type="radio" id="bottomL" onclick="if (autoVisualized){visualizeAuto()}">Bottom
+                Left</label>
+            <label>
+                <input name="area" type="radio" id="topR" onclick="if (autoVisualized){visualizeAuto()}">Top
+                Right</label>
+            <label>
+                <input name="area" type="radio" id="topL" onclick="if (autoVisualized){visualizeAuto()}">Top
+                Left</label>
+        </span>
+        <button onclick="exportAuto()" id="exportAuto"
+            title="Exports the auto with all path names modified as they were from the path mirrorer">Export Modified
+            Auto</button>
+    </div>
+    <p id="input"></p>
+    <br />
+    <div id="result"></div>
+    <a id="hiddenDownloader" style="display: none;"></a>
+</body>
+<script src="index.js"></script>
+
+</html>
\ No newline at end of file
diff --git a/tools/PathPlannerMirror2026-main/index.js b/tools/PathPlannerMirror2026-main/index.js
new file mode 100644 (file)
index 0000000..ddb295b
--- /dev/null
@@ -0,0 +1,330 @@
+let pathJSON
+let autoJSON
+let importedPath
+let importedAuto
+let reader = new FileReader()
+let anotherReader = new FileReader()
+let fileLoaded = false
+let fileVisualized = false
+let autoLoaded = false
+let autoVisualized = false
+
+let firstTimeInAutos = true
+
+
+let pathMode = true
+
+let Ystatus
+let Xstatus
+
+const canvas = document.getElementById("graph");
+const ctx = canvas.getContext("2d");
+
+const fieldWidth = 8.071326
+// ctx.strokeStyle = "white";
+ctx.lineWidth = 5
+
+// ctx.beginPath();
+// ctx.moveTo(0,0);
+// ctx.lineTo(1650, 800);
+// ctx.stroke()
+
+document.getElementById("pathInput").addEventListener("change", async () => {
+    [importedPath] = document.getElementById("pathInput").files
+    reader.readAsText(importedPath)
+    fileLoaded = true
+
+    document.getElementById("visualizeBtn").style.visibility = "visible"
+    document.getElementById("visualizeBtn").style.fontSize = ""
+    document.getElementById("visualizeBtn").style.width = ""
+
+    // setTimeout(() => {
+    //     visualizePath()
+    // }, 100);
+})
+
+document.getElementById("autoInput").addEventListener("change", async () => {
+    [importedAuto] = document.getElementById("autoInput").files
+    anotherReader.readAsText(importedAuto)
+    autoLoaded = true
+
+    document.getElementById("visualizeBtn2").style.visibility = "visible"
+    document.getElementById("visualizeBtn2").style.fontSize = ""
+    document.getElementById("visualizeBtn2").style.width = ""
+})
+
+function visualizePath() {
+    if (fileVisualized == false && fileLoaded) {
+        document.getElementById("downloadBtn").style.visibility = "visible"
+        document.getElementById("downloadBtn").style.opacity = 1
+        document.getElementById("downloadAllBtn").style.visibility = "visible"
+        document.getElementById("downloadAllBtn").style.opacity = 1
+        fileVisualized = true
+    }
+    ctx.strokeStyle = "white";
+    let startX = (JSON.parse(reader.result).waypoints[0].anchor.x) * 100
+    let startY = ((1 - (Number(JSON.parse(reader.result).waypoints[0].anchor.y) / fieldWidth)) * fieldWidth) * 100
+    let endX = (JSON.parse(reader.result).waypoints[1].anchor.x) * 100
+    let endY = ((1 - (Number(JSON.parse(reader.result).waypoints[1].anchor.y) / fieldWidth)) * fieldWidth) * 100
+    ctx.clearRect(0, 0, canvas.width, canvas.height)
+
+    ctx.beginPath();
+    ctx.moveTo(startX, startY);
+    ctx.lineTo(endX, endY);
+    ctx.stroke()
+
+    if (document.getElementById("horizontal").checked) {
+        startX = ((1 - (Number(JSON.parse(reader.result).waypoints[0].anchor.x) / 16.5)) * 16.5) * 100
+        endX = ((1 - (Number(JSON.parse(reader.result).waypoints[1].anchor.x) / 16.5)) * 16.5) * 100
+    }
+    if (document.getElementById("vertical").checked) {
+        // ctx.strokeStyle = "#d934eba4";
+        startY = (JSON.parse(reader.result).waypoints[0].anchor.y) * 100
+        endY = (JSON.parse(reader.result).waypoints[1].anchor.y) * 100
+    }
+
+    if (startX < 825) {
+        ctx.strokeStyle = "#5234eba4";
+        // Xstatus = "Blue"
+        // console.log(startX)
+    } else if (startX >= 825) {
+        ctx.strokeStyle = "#eb3434a4";
+        // Xstatus = "Red"
+    }
+
+    ctx.beginPath();
+    ctx.moveTo(startX, startY);
+    ctx.lineTo(endX, endY);
+    ctx.stroke()
+}
+
+function exportPath() {
+    //"reader.result" is just the text file
+    // let [file] = document.getElementById("pathInput").files
+    // let reader = new FileReader()
+
+    //X and Y are normal for this
+    //  the X is [0, 16.5]
+    //  the Y is  [0, 8]
+    pathJSON = JSON.parse(reader.result)
+    console.log(pathJSON)
+    // document.getElementById("input").innerHTML = JSON.stringify(pathJSON)
+    console.log("START X: " + pathJSON.waypoints[0].anchor.x)
+    console.log("START Y: " + pathJSON.waypoints[0].anchor.y)
+    console.log("END X: " + pathJSON.waypoints[1].anchor.x)
+    console.log("END Y: " + pathJSON.waypoints[1].anchor.y)
+
+    //normal X and Y point flipping
+    // Loop through all waypoints
+    for (let i = 0; i < pathJSON.waypoints.length; i++) {
+        let waypoint = pathJSON.waypoints[i];
+        
+        if (document.getElementById("horizontal").checked) {
+            waypoint.anchor.x = ((1 - (Number(waypoint.anchor.x) / 16.5)) * 16.5)
+            
+            // Update nextControl if it exists
+            if (waypoint.nextControl != null) {
+                waypoint.nextControl.x = ((1 - (Number(waypoint.nextControl.x) / 16.5)) * 16.5)
+            }
+            // Update prevControl if it exists
+            if (waypoint.prevControl != null) {
+                waypoint.prevControl.x = ((1 - (Number(waypoint.prevControl.x) / 16.5)) * 16.5)
+            }
+        }
+
+        if (document.getElementById("vertical").checked) {
+            waypoint.anchor.y = ((1 - (Number(waypoint.anchor.y) / fieldWidth)) * fieldWidth)
+            
+            // Update nextControl if it exists
+            if (waypoint.nextControl != null) {
+                waypoint.nextControl.y = ((1 - (Number(waypoint.nextControl.y) / fieldWidth)) * fieldWidth)
+            }
+            // Update prevControl if it exists
+            if (waypoint.prevControl != null) {
+                waypoint.prevControl.y = ((1 - (Number(waypoint.prevControl.y) / fieldWidth)) * fieldWidth)
+            }
+        }
+    }
+
+    // next stuff is for point towards zones
+    for (let i = 0; i < pathJSON.pointTowardsZones.length; i++) {
+        if (document.getElementById("horizontal").checked) {
+            pathJSON.pointTowardsZones[i].fieldPosition.x = ((1 - (Number(pathJSON.pointTowardsZones[i].fieldPosition.x) / 16.5)) * 16.5)
+        }
+        if (document.getElementById("vertical").checked) {
+            pathJSON.pointTowardsZones[i].fieldPosition.y = ((1 - (Number(pathJSON.pointTowardsZones[i].fieldPosition.y) / fieldWidth)) * fieldWidth)
+        }
+
+        if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked == false) {
+            pathJSON.pointTowardsZones[i].rotationOffset = Number(pathJSON.pointTowardsZones[i].rotationOffset) * -1
+        } else if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked) {
+            pathJSON.pointTowardsZones[i].rotationOffset = Number(pathJSON.pointTowardsZones[i].rotationOffset)
+        } else if (document.getElementById("horizontal").checked == false && document.getElementById("vertical").checked) {
+            pathJSON.pointTowardsZones[i].rotationOffset = -Number(pathJSON.pointTowardsZones[i].rotationOffset)
+        }
+        console.log("point towards zone: " + i)
+    }
+
+    // now into the starting state and end state rotation craziness
+    if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked == false) {
+        pathJSON.idealStartingState.rotation = 180 - Number(pathJSON.idealStartingState.rotation)
+        pathJSON.goalEndState.rotation = 180 - Number(pathJSON.goalEndState.rotation)
+    } else if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked) {
+        pathJSON.idealStartingState.rotation = 180 + Number(pathJSON.idealStartingState.rotation)
+        pathJSON.goalEndState.rotation = 180 + Number(pathJSON.goalEndState.rotation)
+    } else if (document.getElementById("horizontal").checked == false && document.getElementById("vertical").checked) {
+        pathJSON.idealStartingState.rotation = -Number(pathJSON.idealStartingState.rotation)
+        pathJSON.goalEndState.rotation = -Number(pathJSON.goalEndState.rotation)
+    }
+
+    //this is for the mid-path rotations
+    for (let i = 0; i < pathJSON.rotationTargets.length; i++) {
+        if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked == false) {
+            pathJSON.rotationTargets[i].rotationDegrees = 180 - Number(pathJSON.rotationTargets[i].rotationDegrees)
+        } else if (document.getElementById("horizontal").checked && document.getElementById("vertical").checked) {
+            pathJSON.rotationTargets[i].rotationDegrees = 180 + Number(pathJSON.rotationTargets[i].rotationDegrees)
+        } else if (document.getElementById("horizontal").checked == false && document.getElementById("vertical").checked) {
+            pathJSON.rotationTargets[i].rotationDegrees = -Number(pathJSON.rotationTargets[i].rotationDegrees)
+        }
+        // console.log("rotation target: " + i)
+    }
+
+    console.log("CONVERTED START X: " + pathJSON.waypoints[0].anchor.x)
+    console.log("CONVERTED START Y: " + pathJSON.waypoints[0].anchor.y)
+    console.log("CONVERTED END X: " + pathJSON.waypoints[1].anchor.x)
+    console.log("CONVERTED END Y: " + pathJSON.waypoints[1].anchor.y)
+
+    if (pathJSON.waypoints[0].anchor.x < 8.25) {
+        Xstatus = "Left"
+    } else if (pathJSON.waypoints[0].anchor.x >= 8.25) {
+        Xstatus = "Right"
+    }
+    if (pathJSON.waypoints[0].anchor.y < 4 && ((pathJSON.waypoints[1].anchor.y + pathJSON.waypoints[0].anchor.y) / 2) < 4) {
+        Ystatus = "Bottom"
+    } else if (pathJSON.waypoints[0].anchor.y >= 4 && ((pathJSON.waypoints[1].anchor.y + pathJSON.waypoints[0].anchor.y) / 2) >= 4) {
+        Ystatus = "Top"
+    } else {
+        Ystatus = "bro what did you do for this to happen"
+    }
+
+    pathJSON.waypoints[0].linkedName = null
+    pathJSON.waypoints[1].linkedName = null
+    // document.getElementById("result").innerHTML = JSON.stringify(pathJSON)
+
+    let pathMirror = new File(["\ufeff" + JSON.stringify(pathJSON)], Ystatus + Xstatus + " " + importedPath.name);
+    document.getElementById("hiddenDownloader").href = window.URL.createObjectURL(pathMirror);
+    document.getElementById("hiddenDownloader").download = pathMirror.name
+    document.getElementById("hiddenDownloader").click()
+
+}
+
+function exportAllMirrors() {
+    document.getElementById("vertical").checked = true
+    document.getElementById("horizontal").checked = false
+    exportPath()
+    document.getElementById("vertical").checked = true
+    document.getElementById("horizontal").checked = true
+    exportPath()
+    document.getElementById("vertical").checked = false
+    document.getElementById("horizontal").checked = true
+    exportPath()
+    document.getElementById("vertical").checked = false
+    document.getElementById("horizontal").checked = false
+
+    alert(`Mirrored paths have been downloaded.\n \nMake sure to put these in your project's "pathplanner/paths" directory`)
+}
+
+function visualizeAuto() {
+    document.getElementById("exportAuto").style.visibility = "visible"
+    document.getElementById("exportAuto").style.opacity = 1
+
+    document.getElementById("autoList").querySelectorAll("pre")[0].innerHTML = ""
+    document.getElementById("autoList").querySelectorAll("pre")[1].innerHTML = ""
+
+    for (let i = 0; i < (JSON.parse(anotherReader.result).command.data.commands.length); i++) {
+        let checked
+        let textColor
+        console.log(i)
+
+        document.getElementById("autoList").querySelectorAll("pre")[0].innerHTML += `
+        `+ JSON.parse(anotherReader.result).command.data.commands[i].data.pathName + ``
+
+        if (document.getElementById("bottomR").checked) {
+            checked = "BottomRight"
+            textColor = "#eb3434a4"
+        } else if (document.getElementById("bottomL").checked) {
+            checked = "BottomLeft"
+            textColor = "#5234eba4"
+        } else if (document.getElementById("topR").checked) {
+            checked = "TopRight"
+            textColor = "#fb0505a4"
+        } else if (document.getElementById("topL").checked) {
+            checked = "TopLeft"
+            textColor = "#5234eba4"
+        }
+        document.getElementById("autoList").querySelectorAll("pre")[1].innerHTML += `<span style="color:` + textColor + `">
+        `+ checked + " " + JSON.parse(anotherReader.result).command.data.commands[i].data.pathName + `</span>`
+
+    }
+    if (autoVisualized == false) {
+        autoVisualized = true
+    }
+}
+
+function exportAuto() {
+    autoJSON = JSON.parse(anotherReader.result)
+    let checked
+
+    for (let i = 0; i < (autoJSON.command.data.commands.length); i++) {
+
+        if (document.getElementById("bottomR").checked) {
+            checked = "BottomRight"
+        } else if (document.getElementById("bottomL").checked) {
+            checked = "BottomLeft"
+        } else if (document.getElementById("topR").checked) {
+            checked = "TopRight"
+        } else if (document.getElementById("topL").checked) {
+            checked = "TopLeft"
+        }
+
+        autoJSON.command.data.commands[i].data.pathName = checked + " " + autoJSON.command.data.commands[i].data.pathName
+    }
+
+    let autoMirror = new File(["\ufeff" + JSON.stringify(autoJSON)], checked + " " + importedAuto.name);
+    document.getElementById("hiddenDownloader").href = window.URL.createObjectURL(autoMirror);
+    document.getElementById("hiddenDownloader").download = autoMirror.name
+    document.getElementById("hiddenDownloader").click()
+}
+
+let modeCooldown = false
+function switchModes() {
+    if (modeCooldown == false) {
+        pathMode = !pathMode
+
+        if (pathMode) {
+            document.getElementById("centerDiv2").style.opacity = 0
+            setTimeout(() => {
+                document.getElementById("centerDiv2").style.visibility = "hidden"
+                document.getElementById("centerDiv2").style.top = "1000%"
+            }, 200);
+            document.getElementById("centerDiv").style.visibility = "visible"
+            document.getElementById("centerDiv").style.opacity = 1
+        } else if (pathMode == false) {
+            document.getElementById("centerDiv").style.opacity = 0
+            setTimeout(() => {
+                document.getElementById("centerDiv").style.visibility = "hidden"
+            }, 200);
+            document.getElementById("centerDiv2").style.top = "50%"
+            document.getElementById("centerDiv2").style.visibility = "visible"
+            document.getElementById("centerDiv2").style.opacity = 1
+            if (firstTimeInAutos) {
+                alert('This is EXTREMELY experimental and will not work on most autos. If you are using it and think MAYBE it will work, make sure the paths you are using with it are in the same corner and have already been exported from the path mirrorer (this literally just renames the paths in the auto file for you.)') //basically its for lazy people
+                firstTimeInAutos = false
+            }
+        }
+        modeCooldown = true
+        setTimeout(() => {
+            modeCooldown = false
+        }, 1000);
+    }
+}
\ No newline at end of file