diff --git a/project-words.txt b/project-words.txt
index 141346e..0893b85 100644
--- a/project-words.txt
+++ b/project-words.txt
@@ -16,6 +16,7 @@ Dechorionator
ebox
fhhs
flowbite
+Gitea
HDFS
headshot
Homelab
diff --git a/src/assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif
new file mode 100644
index 0000000..379fc55
Binary files /dev/null and b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif differ
diff --git a/src/assets/experience/spacex/avionics-test-engineering-internship/swag.jpg b/src/assets/experience/spacex/avionics-test-engineering-internship/swag.jpg
new file mode 100644
index 0000000..813bdf3
Binary files /dev/null and b/src/assets/experience/spacex/avionics-test-engineering-internship/swag.jpg differ
diff --git a/src/assets/resume/corwin_perren_2025-10-27-infrastructure_engineer.pdf b/src/assets/resume/corwin_perren_2025-10-27_infrastructure_engineer.pdf
similarity index 88%
rename from src/assets/resume/corwin_perren_2025-10-27-infrastructure_engineer.pdf
rename to src/assets/resume/corwin_perren_2025-10-27_infrastructure_engineer.pdf
index e88030b..aedf620 100644
Binary files a/src/assets/resume/corwin_perren_2025-10-27-infrastructure_engineer.pdf and b/src/assets/resume/corwin_perren_2025-10-27_infrastructure_engineer.pdf differ
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
index b9d1939..af98c0e 100644
--- a/src/components/Footer.astro
+++ b/src/components/Footer.astro
@@ -1,10 +1,23 @@
---
+import InlineLink from "@components/InlineLink.astro";
+const { pathname } = Astro.url;
---
diff --git a/src/components/InlineLink.astro b/src/components/InlineLink.astro
index a302e00..93f5428 100644
--- a/src/components/InlineLink.astro
+++ b/src/components/InlineLink.astro
@@ -7,16 +7,10 @@ interface Props extends ComponentPropsBase {
}
const { class: className, href, target } = Astro.props;
+const { pathname } = Astro.url;
-let finalTarget: string | undefined = target;
-
-if (target === undefined) {
- if (href.startsWith("/")) {
- finalTarget = "";
- } else {
- finalTarget = "_blank";
- }
-}
+const finalTarget =
+ target === undefined ? (href.startsWith("/") ? undefined : "_blank") : target;
---
<>
@@ -24,6 +18,7 @@ if (target === undefined) {
class:list={["text-blue-500", "hover:text-blue-300", className]}
href={href}
target={finalTarget}
+ aria-current={pathname === href ? "page" : undefined}
>
diff --git a/src/components/NestedNavbarEntries.astro b/src/components/NestedNavbarEntries.astro
index b965f3e..30b94e5 100644
--- a/src/components/NestedNavbarEntries.astro
+++ b/src/components/NestedNavbarEntries.astro
@@ -1,26 +1,18 @@
---
import type { navLink } from "@interfaces/site-layout.ts";
+import { getHrefPath, getNavLinkSuffix } from "@data/site-layout.ts";
+
const items: navLink[] = Astro.props.items;
const depth: number = Astro.props.depth ?? 0;
const paths: string[] = Astro.props.paths ?? [];
-const getNavLinkSuffix = (entry: navLink): string => {
- return "-" + [...paths, entry.path].join("-");
-};
-const getHrefPath = (entry: navLink): string => {
- return entry.pubpath
- ? entry.pubpath
- : "/" +
- (paths && paths.length ? [...paths, entry.path].join("/") : entry.path);
-};
-
const { pathname } = Astro.url;
---
- (entry.enabled ?? true) && (
+ (entry.enabled ?? true) &&
+ !(entry.hidden ?? false) && (
-
{Array.isArray(entry.children) && entry.children.length ? (
{entry.navText}
diff --git a/src/components/PopoverWordDefinition.astro b/src/components/PopoverWordDefinition.astro
index e35e7cf..271fa90 100644
--- a/src/components/PopoverWordDefinition.astro
+++ b/src/components/PopoverWordDefinition.astro
@@ -7,10 +7,14 @@ const keys: { [key: string]: string } = {
ADCP: "Acoustic doppler current profiler",
COTS: "Consumer off-the-shelf",
CTD: "Conductivity, temperature, and depth sensor",
+ DUTs: "Devices under test",
GUI: "Graphical user interface",
NUC: "A small and low-power computer made by Intel",
PCBs: "Printed circuit boards",
+ TDD: "Test driven development",
UPS: "Uninterruptible power supply",
+ VISA: "Virtual instrument software architecture",
+ VPS: "Virtual private server",
};
const key: string | undefined = Astro.props.key;
@@ -21,6 +25,12 @@ if (key && keys.hasOwnProperty(key)) {
word = key;
definition = keys[key];
}
+
+if (!word || !definition) {
+ throw new Error(
+ `Popover definition is missing! Inputs were\nkey: ${key}\nword: ${word}\ndefinition: ${definition}`,
+ );
+}
---
<>
diff --git a/src/components/Ul.astro b/src/components/Ul.astro
index a6a749b..6825377 100644
--- a/src/components/Ul.astro
+++ b/src/components/Ul.astro
@@ -13,7 +13,11 @@ const { class: className, lineItems, depth = 0 } = Astro.props;
---
0 ? "ps-3" : false]}
+ class:list={[
+ "list-outside list-disc",
+ className,
+ depth > 0 ? "ps-3" : "ms-3",
+ ]}
>
{
lineItems ? (
diff --git a/src/data/site-layout.ts b/src/data/site-layout.ts
index 540e71a..d0dd984 100644
--- a/src/data/site-layout.ts
+++ b/src/data/site-layout.ts
@@ -1,6 +1,7 @@
import type { navLink } from "@interfaces/site-layout.ts";
export const siteLayout: navLink[] = [
+ // Standard navbar entries
{ navText: "About", path: "" },
{ navText: "Education", path: "education" },
{
@@ -8,7 +9,6 @@ export const siteLayout: navLink[] = [
path: "experience",
children: [
{
- enabled: false,
navText: "SpaceX",
path: "spacex",
children: [
@@ -18,7 +18,6 @@ export const siteLayout: navLink[] = [
path: "hardware-test-engineer-i-ii",
},
{
- enabled: false,
navText: "Avionics Test Engineering Internship",
path: "avionics-test-engineering-internship",
},
@@ -189,6 +188,7 @@ export const siteLayout: navLink[] = [
},
{ enabled: false, navText: "NixOS", path: "nixos" },
{ navText: "Body Mods", path: "body-mods" },
+ { navText: "This Website", path: "this-website" },
],
},
{
@@ -270,3 +270,13 @@ export const getPaths = (
}
return [...new Set(foundPaths)];
};
+
+export const getNavLinkSuffix = (paths: string[], entry: navLink): string => {
+ return "-" + [...paths, entry.path].join("-");
+};
+export const getHrefPath = (paths: string[], entry: navLink): string => {
+ return entry.pubpath
+ ? entry.pubpath
+ : "/" +
+ (paths && paths.length ? [...paths, entry.path].join("/") : entry.path);
+};
diff --git a/src/interfaces/site-layout.ts b/src/interfaces/site-layout.ts
index 48facb1..19bb829 100644
--- a/src/interfaces/site-layout.ts
+++ b/src/interfaces/site-layout.ts
@@ -1,5 +1,6 @@
export interface navLink {
enabled?: boolean;
+ hidden?: boolean;
navText: string;
path?: string;
pubpath?: string;
diff --git a/src/pages/experience/spacex/avionics-test-engineering-internship.astro b/src/pages/experience/spacex/avionics-test-engineering-internship.astro
index 70d7caf..03f3f0f 100644
--- a/src/pages/experience/spacex/avionics-test-engineering-internship.astro
+++ b/src/pages/experience/spacex/avionics-test-engineering-internship.astro
@@ -1,16 +1,28 @@
---
+import H2 from "@components/H2.astro";
+import H3 from "@components/H3.astro";
+import Li from "@components/Li.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
+import PageGroup from "@components/PageGroup.astro";
+import Paragraph from "@components/Paragraph.astro";
+import Paragraphs from "@components/Paragraphs.astro";
+import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
+import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
import Timeline from "@components/Timeline/Timeline.astro";
+import Ul from "@components/Ul.astro";
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
import spring_2019_interns from "@assets/experience/spacex/avionics-test-engineering-internship/spring-2019-interns.jpg";
+import swag from "@assets/experience/spacex/avionics-test-engineering-internship/swag.jpg";
+import InlineLink from "@components/InlineLink.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts";
+import type { categorySkills } from "@interfaces/skill-matrix.ts";
import type { timelineEntry } from "@interfaces/timeline.ts";
const headerCarouselGroup: carouselGroup = {
animation: "slide",
- images: [spring_2019_interns],
+ images: [spring_2019_interns, swag],
};
const timeline: timelineEntry[] = [
@@ -23,58 +35,157 @@ const timeline: timelineEntry[] = [
date: "March 2019",
},
];
+
+const categorizedSkills: categorySkills[] = [
+ {
+ category: "Software & Environments",
+ skills: [
+ { item: "Git" },
+ {
+ item: "Programming Languages",
+ subItems: [
+ { item: "Python 2/3" },
+ { item: "Bash Shell Scripting" },
+ { item: "Microsoft SQL" },
+ ],
+ },
+ {
+ item: "Atlassian Suite",
+ subItems: [
+ { item: "Jira" },
+ { item: "Bitbucket" },
+ { item: "Confluence" },
+ ],
+ },
+ {
+ item: "Automation Interfaces",
+ subItems: [{ item: "NI MAX/VISA" }, { item: "Jira RESTful APIs" }],
+ },
+ {
+ item: "Operating Systems",
+ subItems: [
+ {
+ item: "Linux",
+ subItems: [{ item: "Ubuntu" }, { item: "WSL" }],
+ },
+ { item: "Microsoft Windows" },
+ ],
+ },
+ ],
+ },
+ {
+ category: "Electrical",
+ skills: [
+ {
+ item: "Schematic & PCB Design",
+ subItems: [{ item: "Altium Designer" }],
+ },
+ {
+ item: "Electrical Diagnostics",
+ subItems: [{ item: "Multimeters" }],
+ },
+ ],
+ },
+];
---
-
+
-
- Summary
- Timeline
-
- Key Takeaways
-
- Skills Used
-
-
-
-
-
- - Python
- - Test Driven Development
-
-
-
-
-
-
-
-
-
-
-
- Details
-
- Though I did get to work on some really fun projects during my internship at
- SpaceX, I unfortunately can’t go into much detail due to NDA’s and ITAR
- restrictions. What I can say is that I mainly wrote Python for a new avionics
- hardware test system. My experience with writing Python in the numerous other
- projects I’ve done really helped me out here, as the framework SpaceX has
- created was quite complex and would otherwise have been fairly difficult to
- write code for. I also wrote a simple tool for automating the creation of Jira
- work tickets so that the two teams that ended up using it wouldn’t have to
- have their members manually creating dozens of them as work and issues came in
- through a separate system. I was also quite happy in that I got to perform
- some circuit debugging on avionics test system hardware, both for my project
- and for a separate test system. A final experience I had here was getting to
- work directly with the head engineer from a company that supplied a piece of
- test hardware I was interfacing with. It was quite incredible to see just how
- much weight a SpaceX email address had when trying to solve problems I had
- found with the hardware. Not only were they responsive, but in fact were
- willing to fast-track firmware updates for us to get things working. Coming
- from clubs and small labs where a support email might not even get a response
- for months, it was quite a refreshing experience.
+
+ Summary
+
+ Timeline
+
+
+
+ Key Takeaways
+
+ - Wrote re-usable, unit-tested, and safety-focused test software
+ components in Python for validating high-pressure transducers
+ - Assisted in the running of qualification tests against flight
+ networking hardware
+ - Wrote software in Python to automate work-ticket generation in Jira
+ - Successfully debugged electrical faults in used in Avionics test systems
+ - Directly interfaced with the engineering team for test equipment, driving firmware fixes and providing beta test feedback
+
+
+
+
+
+ Details
+
+
+ Working at SpaceX was a dream come true, even when it was only for a
+ three month internship. I've always loved space, including the
+ technology related to it, as I know many others also do. I grew as a
+ Trekkie, watching endless hours of rubbermaid tubs filled with VHS
+ recordings of the original series, The Next Generation, and Voyager. As
+ someone with a multi-disciplinary background, and with a special focus
+ on robotics and automation, test engineering was a very good fit!
+
+
+ During this internship, my primary goal was to create re-usable
+ components for high pressure test systems. This involved interfacing
+ with test rack equipment which could apply pressure to , and would then validate their response and performance to this
+ stimulus. While I'd written quite a bit of Python prior to this, the
+ standards for these components were (understandably!) much higher than
+ I'd encountered previously. This effectively meant that the internship
+ was a bit of a crash course in , as
+ being able to verify that the tests would apply the correct stimulus,
+ and in the correct way, helped reduce the chances of damaging , or supporting test equipment. As part of this effort, I also made
+ significant improvements to the driver for the piece of test equipment
+ which controlled how pressure was applied. While doing so, I encountered
+ a fair number of discrepancies in the documentation and
+ commands for this device. I ended up contacting the company and was put in
+ contact with their engineering department, where I then drove fixes to their
+ firmware and documentation, ultimately resulting in a fully functional test
+ setup. Since I ended up working for the company long-term, I know that these components were used, and likely still are, for
+ many pressure-related validation tests at the company and worked well!
+
+
+ There were also a couple of side projects I worked on while here. The
+ first was small Python app which automated the creation of Jira work
+ tickets for the Lifecycle Engineering Team. Previously, a member of that
+ team on a rotating schedule would manually create counterpart Jira
+ tickets associated to a proprietary tracking system created in-house. By
+ manually querying the SQL database for this proprietary app, and making
+ it run on a schedule, tickets were made and assigned to the appropriate
+ teams automatically, improving the response time to these tickets, and
+ removing the potential for errors during the previously manual
+ copy/pasting efforts. In my first week, I also debugged a custom circuit
+ board for a motor controller test system, finding the location of a dead
+ short, directing a tech to repair the failure, and then verified that
+ the board functioned correctly afterwards. The final small project I
+ worked on was manually running the shock tests in the qualification
+ efforts for a piece of spaceflight networking gear while its owner, a
+ friend, could not be present.
+
+
+
diff --git a/src/pages/hobby/this-website.astro b/src/pages/hobby/this-website.astro
new file mode 100644
index 0000000..4a37d61
--- /dev/null
+++ b/src/pages/hobby/this-website.astro
@@ -0,0 +1,120 @@
+---
+import ExperienceLayout from "@layouts/ExperienceLayout.astro";
+
+import H3 from "@components/H3.astro";
+import InlineLink from "@components/InlineLink.astro";
+import PageGroup from "@components/PageGroup.astro";
+import Paragraph from "@components/Paragraph.astro";
+import Paragraphs from "@components/Paragraphs.astro";
+import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
+import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
+
+import type { categorySkills } from "@interfaces/skill-matrix.ts";
+
+const categorizedSkills: categorySkills[] = [
+ {
+ category: "Software & Environments",
+ skills: [
+ {
+ item: "DevOps",
+ subItems: [
+ { item: "Github Actions" },
+ { item: "dev/staging/production environments" },
+ { item: "automatic build/test/deploy" },
+ ],
+ },
+ { item: "Git" },
+ {
+ item: "Docker",
+ subItems: [
+ { item: "Custom Builds" },
+ { item: "Registry & Asset Management" },
+ ],
+ },
+ {
+ item: "Programming Languages",
+ subItems: [
+ { item: "HTML" },
+ { item: "CSS" },
+ { item: "Typescript" },
+ { item: "Bash" },
+ { item: "Makefile" },
+ ],
+ },
+ {
+ item: "Web Frameworks",
+ subItems: [
+ { item: "Astro" },
+ { item: "tailwindcss" },
+ { item: "flowbite" },
+ ],
+ },
+ {
+ item: "Operating Systems",
+ subItems: [
+ {
+ item: "Linux",
+ subItems: [{ item: "NixOS" }, { item: "Alpine Linux" }],
+ },
+ ],
+ },
+ ],
+ },
+];
+---
+
+
+
+ Summary
+
+
+
+ While I've traditionally used Wordpress to build my websites in the
+ past, I finally decided to make a custom one after developing the skills
+ to do so at SpaceX. I still wouldn't call myself a web developer by trade, but I take
+ great pride in being able to create things on my own, and have also felt
+ that Wordpress was overkill for a simple portfolio website. It also gave
+ me a chance to put my DevOps skills to use at home, which I've been
+ wanting to do for a while.
+
+
+ The core framework of my website is Astro, chosen for its focus on static site generation and de-duplication of
+ code via re-usable components. This seemed like the perfect middle-ground of providing enough
+ structure and quality-of-life features to reduce the overall effort of
+ building the site, without being overly bloated or opinionated. So far
+ I've been incredibly happy with this decision, and would recommend it to
+ others looking to build static websites. To add some helpful styling
+ utilities, and basic web components, tailwindcss and flowbite were also
+ added. Like my decision to use Astro, these both provided good starting points
+ for creating a website that felt like my own, without struggling for too long
+ at the start.
+
+
+ From the DevOps perspective, I created a Makefile within the repo for
+ local development targets to build, run, and test both in a pure
+ context, and within a Docker container. After pushing updates on a
+ branch to my local Gitea instance, and opening a pull request, the
+ website performs spelling checks, runs unit tests, and integration
+ tests. Once these pass, the website is built into a Docker container and
+ uploaded to the registry in my Gitea instance. The image is then
+ deployed to staging on my , allowing
+ for manual validation of the changes. In order to merge, the build,
+ test, and deploy actions must pass, and ideally I should be empirically
+ validating the staging deployment. After merging and closing the pull
+ request, another action builds, tests, and deploys the main branch in
+ the same way as before, but to production, and is what you see here!
+
+
+
+
+
diff --git a/src/pages/resume/2025-11-10-infrastructure-engineer.astro b/src/pages/resume/2025-11-10-infrastructure-engineer.astro
index a171ad4..2f97304 100644
--- a/src/pages/resume/2025-11-10-infrastructure-engineer.astro
+++ b/src/pages/resume/2025-11-10-infrastructure-engineer.astro
@@ -1,7 +1,7 @@
---
import ResumeLayout from "@layouts/ResumeLayout.astro";
-import resume from "@assets/resume/corwin_perren_2025-10-27-infrastructure_engineer.pdf";
+import resume from "@assets/resume/corwin_perren_2025-10-27_infrastructure_engineer.pdf";
---