Finished ross content, added skill matrix, li, and ul, and improved many existing components, created and refactored to unified layouts and grid, visual improvements with proper column to row collapsing
Some checks failed
Build and Test - Staging / build_and_push (pull_request) Has been cancelled
Build and Test - Staging / deploy_staging (pull_request) Has been cancelled
Build and Test - Staging / test (pull_request) Has been cancelled

This commit is contained in:
2025-12-06 00:08:52 -08:00
parent 4b5f65bfdd
commit 87224a6dbb
29 changed files with 770 additions and 358 deletions

View File

@@ -1,6 +1,9 @@
ADCP ADCP
Altium
ASSEM ASSEM
astrojs astrojs
Atmel
barebones
Candian Candian
caperren caperren
CEOAS CEOAS
@@ -10,6 +13,7 @@ CONSERV
Corwin Corwin
dangerousthings dangerousthings
Dechorionator Dechorionator
ebox
fhhs fhhs
flowbite flowbite
HDFS HDFS
@@ -19,10 +23,13 @@ hwupload
iceops iceops
ITAR ITAR
Jetson Jetson
KFSK
leconte leconte
Loctite Loctite
luxon luxon
MGMT MGMT
Mokai
Multimeters
nixos nixos
offroad offroad
Onshape Onshape
@@ -30,6 +37,7 @@ OSSM
OSURC OSURC
Perren Perren
Perren's Perren's
Pixhawk
pubpath pubpath
RFID RFID
RSSI RSSI

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -2,4 +2,4 @@
--- ---
<h1 class="text-xl font-extrabold md:text-3xl"><slot /></h1> <h1 class="text-xl font-extrabold sm:text-2xl md:text-3xl"><slot /></h1>

View File

@@ -2,4 +2,4 @@
--- ---
<h2 class="my-4 font-bold md:text-2xl"><slot /></h2> <h2 class="text-lg font-bold sm:text-xl md:text-2xl"><slot /></h2>

View File

@@ -2,4 +2,4 @@
--- ---
<h3 class="mt-4 mb-2 font-bold md:text-lg"><slot /></h3> <h3 class="text-md font-semibold sm:text-lg md:text-xl"><slot /></h3>

9
src/components/Li.astro Normal file
View File

@@ -0,0 +1,9 @@
---
---
<>
<li>
<slot />
</li>
</>

View File

@@ -9,10 +9,12 @@ interface Props {
const { title, href, target = "_blank" } = Astro.props; const { title, href, target = "_blank" } = Astro.props;
--- ---
<a <div class="mx-auto">
<a
class="text-caperren-green border-caperren-green hover:border-caperren-green-light hover:text-caperren-green-light rounded-2xl border-2 bg-black p-2" class="text-caperren-green border-caperren-green hover:border-caperren-green-light hover:text-caperren-green-light rounded-2xl border-2 bg-black p-2"
href={href} href={href}
target={target} target={target}
> >
{title} {title}
</a> </a>
</div>

View File

@@ -39,7 +39,7 @@ import { Image } from "astro:assets";
</svg> </svg>
</button> </button>
<div <div
class="z-40 mt-1 hidden w-full lg:block lg:w-auto" class="z-40 mt-6 hidden w-full lg:mt-0 lg:block lg:w-auto"
id="navbar-multi-level" id="navbar-multi-level"
> >
<NestedNavbarEntry items={siteLayout} /> <NestedNavbarEntry items={siteLayout} />

View File

@@ -19,29 +19,34 @@ const { pathname } = Astro.url;
--- ---
<ul <ul
class={"flex flex-col p-4 bg-black border-caperren-green " + class:list={[
(depth ? "space-y-2" : "items-start lg:flex-row lg:space-x-8 lg:mt-0 ")} "border-caperren-green flex flex-col space-y-4 space-x-8 bg-black",
depth
? "space-y-4 py-4"
: "items-start lg:mt-0 lg:flex-row lg:space-y-0 lg:space-x-8",
]}
> >
{ {
items.map( items.map(
(entry) => (entry) =>
(entry.enabled ?? true) && ( (entry.enabled ?? true) && (
<li> <li class="">
{Array.isArray(entry.children) && entry.children.length ? ( {Array.isArray(entry.children) && entry.children.length ? (
<div <div>
class={
pathname.startsWith(getHrefPath(entry))
? "border-caperren-green border-b-2"
: ""
}
>
<button <button
id={"dropdownNavbarLink" + getNavLinkSuffix(entry)} id={"dropdownNavbarLink" + getNavLinkSuffix(entry)}
data-dropdown-toggle={ data-dropdown-toggle={
"dropdownNavbar" + getNavLinkSuffix(entry) "dropdownNavbar" + getNavLinkSuffix(entry)
} }
data-dropdown-placement="bottom" data-dropdown-placement="bottom-start"
class="hover:text-caperren-green-light lg:hover:text-caperren-green-light flex w-full items-center justify-between px-3 py-2 lg:p-0 lg:hover:bg-transparent" data-dropdown-offset-distance="5"
data-dropdown-offset-skidding="12"
class:list={[
"hover:text-caperren-green-light lg:hover:text-caperren-green-light flex w-full items-center justify-between lg:p-0 lg:hover:bg-transparent",
pathname.startsWith(getHrefPath(entry))
? "border-caperren-green border-b-2"
: false,
]}
> >
{entry.navText} {entry.navText}
<svg <svg
@@ -61,7 +66,7 @@ const { pathname } = Astro.url;
</button> </button>
<div <div
id={"dropdownNavbar" + getNavLinkSuffix(entry)} id={"dropdownNavbar" + getNavLinkSuffix(entry)}
class="border-caperren-green z-10 hidden w-screen border bg-black shadow-sm lg:w-max" class="border-caperren-green z-10 hidden w-max max-w-screen border bg-black px-6 shadow-sm"
> >
<Astro.self <Astro.self
items={entry.children} items={entry.children}
@@ -71,17 +76,16 @@ const { pathname } = Astro.url;
</div> </div>
</div> </div>
) : ( ) : (
<div <div>
class={
pathname === getHrefPath(entry)
? "border-caperren-green border-b-2"
: ""
}
>
<a <a
href={getHrefPath(entry)} href={getHrefPath(entry)}
target={getHrefPath(entry).startsWith("/") ? "" : "_blank"} target={getHrefPath(entry).startsWith("/") ? "" : "_blank"}
class="hover:text-caperren-green-light ring-caperren-green-dark block bg-transparent px-3 py-2 lg:p-0" class:list={[
"hover:text-caperren-green-light ring-caperren-green-dark block bg-transparent lg:p-0",
pathname === getHrefPath(entry)
? "border-caperren-green border-b-2"
: false,
]}
aria-current={ aria-current={
pathname === getHrefPath(entry) ? "page" : undefined pathname === getHrefPath(entry) ? "page" : undefined
} }

38
src/components/Ol.astro Normal file
View File

@@ -0,0 +1,38 @@
---
import Li from "@components/Li.astro";
import type { ComponentPropsBase } from "@interfaces/components.ts";
import type { lineItem } from "@interfaces/ul-li.ts";
interface Props extends ComponentPropsBase {
lineItems?: lineItem[];
depth?: number;
}
const { class: className, lineItems, depth = 0 } = Astro.props;
---
<ol
class:list={["list-inside list-disc", className, depth > 0 ? "ps-3" : false]}
>
{
lineItems ? (
lineItems.map((line) => (
<Li>
{line.item}
{line.subItems ? (
<Astro.self
class={className}
lineItems={line.subItems}
depth={depth + 1}
/>
) : undefined}
</Li>
))
) : (
<Li>
<slot />
</Li>
)
}
</ol>

View File

@@ -0,0 +1,21 @@
---
const hasHeader = Astro.slots.has("header");
const hasDefault = Astro.slots.has("default");
---
<div class="grid grid-cols-1 gap-3">
{
Astro.slots.has("header") && (
<div>
<slot name="header" />
</div>
)
}
{
Astro.slots.has("default") && (
<div class="grid grid-cols-1 gap-3">
<slot />
</div>
)
}
</div>

View File

@@ -1,7 +1,13 @@
--- ---
import type { ComponentPropsBase } from "@interfaces/components.ts";
interface Props extends ComponentPropsBase {
initialTab?: boolean;
}
const { class: className, initialTab = true } = Astro.props;
---
--- <div class:list={className}>
{initialTab && <>&ensp;</>}<slot />
<div class="">
<slot />
</div> </div>

View File

@@ -2,6 +2,6 @@
--- ---
<div class="space-y-2"> <div class="grid grid-cols-1 gap-2">
<slot /> <slot />
</div> </div>

View File

@@ -7,6 +7,10 @@ const keys: { [key: string]: string } = {
ADCP: "Acoustic doppler current profiler", ADCP: "Acoustic doppler current profiler",
COTS: "Consumer off-the-shelf", COTS: "Consumer off-the-shelf",
CTD: "Conductivity, temperature, and depth sensor", CTD: "Conductivity, temperature, and depth sensor",
GUI: "Graphical user interface",
NUC: "A small and low-power computer made by Intel",
PCBs: "Printed circuit boards",
UPS: "Uninterruptible power supply",
}; };
const key: string | undefined = Astro.props.key; const key: string | undefined = Astro.props.key;

View File

@@ -0,0 +1,30 @@
---
import H3 from "@components/H3.astro";
import PageGroup from "@components/PageGroup.astro";
import Ul from "@components/Ul.astro";
import type { categorySkills } from "@interfaces/skill-matrix.ts";
interface Props {
categorizedSkills: categorySkills[];
}
const { categorizedSkills } = Astro.props;
---
<PageGroup>
<Fragment slot="header"><H3>Relevant Skills</H3></Fragment>
<div
class="border-caperren-green grid grid-flow-row gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
{
categorizedSkills.map((categorySkills) => (
<div>
<div class="text-sm font-extrabold">{categorySkills.category}</div>
<hr class="text-caperren-green" />
<Ul class="text-sm" lineItems={categorySkills.skills} />
</div>
))
}
</div>
</PageGroup>

38
src/components/Ul.astro Normal file
View File

@@ -0,0 +1,38 @@
---
import Li from "@components/Li.astro";
import type { ComponentPropsBase } from "@interfaces/components.ts";
import type { lineItem } from "@interfaces/ul-li.ts";
interface Props extends ComponentPropsBase {
lineItems?: lineItem[];
depth?: number;
}
const { class: className, lineItems, depth = 0 } = Astro.props;
---
<ul
class:list={["list-inside list-disc", className, depth > 0 ? "ps-3" : false]}
>
{
lineItems ? (
lineItems.map((line) => (
<Li>
{line.item}
{line.subItems ? (
<Astro.self
class={className}
lineItems={line.subItems}
depth={depth + 1}
/>
) : undefined}
</Li>
))
) : (
<Li>
<slot />
</Li>
)
}
</ul>

View File

@@ -4,7 +4,7 @@ export const siteLayout: navLink[] = [
{ navText: "About", path: "" }, { navText: "About", path: "" },
{ navText: "Education", path: "education" }, { navText: "Education", path: "education" },
{ {
navText: "Experiences", navText: "Experience",
path: "experience", path: "experience",
children: [ children: [
{ {
@@ -29,7 +29,6 @@ export const siteLayout: navLink[] = [
path: "osu-ceoas-ocean-mixing-group", path: "osu-ceoas-ocean-mixing-group",
children: [ children: [
{ {
enabled: false,
navText: "Robotics Oceanographic Surface Sampler", navText: "Robotics Oceanographic Surface Sampler",
path: "robotic-oceanographic-surface-sampler", path: "robotic-oceanographic-surface-sampler",
}, },

View File

@@ -0,0 +1,6 @@
import type { lineItem } from "@interfaces/ul-li.ts";
export interface categorySkills {
category: string;
skills: lineItem[];
}

4
src/interfaces/ul-li.ts Normal file
View File

@@ -0,0 +1,4 @@
export interface lineItem {
item: string;
subItems?: lineItem[];
}

View File

@@ -4,6 +4,7 @@ import "@styles/global.css";
import Footer from "@components/Footer.astro"; import Footer from "@components/Footer.astro";
import H1 from "@components/H1.astro"; import H1 from "@components/H1.astro";
import Navbar from "@components/Navbar.astro"; import Navbar from "@components/Navbar.astro";
import PageGroup from "@components/PageGroup.astro";
import { pathToMetadata } from "@data/site-layout.ts"; import { pathToMetadata } from "@data/site-layout.ts";
@@ -39,28 +40,32 @@ const pageEnabled = pathToMetadata(Astro.url.pathname).enabled ?? true;
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{pageEnabled ? pageTitle : "Corwin Perren"}</title> <title>{pageEnabled ? pageTitle : "Corwin Perren"}</title>
</head> </head>
<body class="flex h-dvh w-full max-w-full flex-col bg-black text-white"> <body
class="grid h-dvh w-full max-w-full grid-cols-1 gap-0 bg-black text-white"
>
<div <div
id="content-body-scrolling" id="content-body-scrolling"
class="grow overflow-x-hidden overflow-y-scroll" class="grow overflow-x-hidden overflow-y-scroll"
> >
<Navbar /> <Navbar />
<main class="mx-6 my-6"> <main class="mx-6 my-2">
<div class="mb-2 md:mb-6">
{ {
title && showTitle && pageEnabled && ( showTitle && pageEnabled && (
<H1 bottomMargin={!subTitles}>{title}</H1> <PageGroup>
<Fragment slot="header">
<div class="leading-3">
<H1>{title}</H1>
{subTitles?.map((subTitle) => (
<p class="md:text-md text-sm font-bold italic">
{subTitle}
</p>
))}
</div>
</Fragment>
</PageGroup>
) )
} }
{ <div class="grid grid-cols-1 gap-4">
showTitle &&
pageEnabled &&
subTitles?.map((subTitle) => (
<p class="text-sm font-bold md:text-xl">{subTitle}</p>
))
}
</div>
<div>
{pageEnabled ? <slot /> : <H1>Under Construction</H1>} {pageEnabled ? <slot /> : <H1>Under Construction</H1>}
</div> </div>
</main> </main>

View File

@@ -1,10 +1,11 @@
--- ---
import PdfViewer from "@components/Media/PdfViewer.astro";
import BaseLayout from "@layouts/BaseLayout.astro"; import BaseLayout from "@layouts/BaseLayout.astro";
import PdfViewer from "@components/Media/PdfViewer.astro";
--- ---
<BaseLayout {...Astro.props}> <BaseLayout {...Astro.props}>
<div class="h-dvh"> <div class="mt-2 h-dvh">
<PdfViewer class="mx-auto" pdf={Astro.props.resume} /> <PdfViewer pdf={Astro.props.resume} />
</div> </div>
</BaseLayout> </BaseLayout>

View File

@@ -5,6 +5,7 @@ import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro"; import H3 from "@components/H3.astro";
import InlineLink from "@components/InlineLink.astro"; import InlineLink from "@components/InlineLink.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import PageGroup from "@components/PageGroup.astro";
import Table from "@components/Table.astro"; import Table from "@components/Table.astro";
import Timeline from "@components/Timeline/Timeline.astro"; import Timeline from "@components/Timeline/Timeline.astro";
@@ -108,16 +109,24 @@ const courseTable: tableData = {
<BaseLayout title="Education"> <BaseLayout title="Education">
<Carousel carouselGroup={diplomaCarouselGroup} /> <Carousel carouselGroup={diplomaCarouselGroup} />
<H2>Timeline</H2> <PageGroup>
<Fragment slot="header"><H2>Timeline</H2></Fragment>
<Timeline timeline={timeline} /> <Timeline timeline={timeline} />
<H2>Oregon State University</H2> </PageGroup>
<H3> <PageGroup>
<Fragment slot="header"><H2>Oregon State University</H2></Fragment>
<PageGroup>
<Fragment slot="header">
<InlineLink <InlineLink
class="font-bold md:text-lg" class="font-bold md:text-lg"
href="https://github.com/caperren/school_archives/tree/master/OSU%20Coursework" href="https://github.com/caperren/school_archives/tree/master/OSU%20Coursework"
>Coursework Archives</InlineLink ><H3>Coursework Archives</H3></InlineLink
> >
</H3> </Fragment>
<H3>Course Listing</H3> </PageGroup>
<PageGroup>
<Fragment slot="header"><H3>Course Listing</H3></Fragment>
<Table data={courseTable} /> <Table data={courseTable} />
</PageGroup>
</PageGroup>
</BaseLayout> </BaseLayout>

View File

@@ -3,8 +3,13 @@ import ExperienceLayout from "@layouts/ExperienceLayout.astro";
import H2 from "@components/H2.astro"; import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro"; import H3 from "@components/H3.astro";
import InlineLink from "@components/InlineLink.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import Video from "@components/Media/Video.astro";
import PageGroup from "@components/PageGroup.astro";
import Paragraph from "@components/Paragraph.astro"; import Paragraph from "@components/Paragraph.astro";
import Paragraphs from "@components/Paragraphs.astro";
import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
import Timeline from "@components/Timeline/Timeline.astro"; import Timeline from "@components/Timeline/Timeline.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts"; import type { carouselGroup } from "@interfaces/image-carousel.ts";
@@ -56,26 +61,29 @@ const headerCarouselGroup: carouselGroup = {
], ],
}; };
import InlineLink from "@components/InlineLink.astro";
import Video from "@components/Media/Video.astro";
import Paragraphs from "@components/Paragraphs.astro";
import PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
import { subTitles } from "./osu-ceoas-ocean-mixing-group.ts"; import { subTitles } from "./osu-ceoas-ocean-mixing-group.ts";
--- ---
<ExperienceLayout title="LeConte Glacier Deployments" subTitles={subTitles}> <ExperienceLayout title="LeConte Glacier Deployments" subTitles={subTitles}>
<Carousel carouselGroup={headerCarouselGroup} /> <Carousel carouselGroup={headerCarouselGroup} />
<H2>Summary</H2> <PageGroup>
<H3>Timeline</H3> <Fragment slot="header"><H2>Summary</H2></Fragment>
<PageGroup>
<Fragment slot="header"><H3>Timeline</H3></Fragment>
<Timeline timeline={deploymentTimeline} /> <Timeline timeline={deploymentTimeline} />
<H3>Location</H3> </PageGroup>
<PageGroup>
<Fragment slot="header"><H3>Location</H3></Fragment>
<iframe <iframe
class="w-full" class="w-full"
width="600" width="600"
height="450" height="450"
src="https://maps.google.com/maps?q=leconte%20glacier&t=k&z=11&ie=UTF8&iwloc=B&output=embed" src="https://maps.google.com/maps?q=leconte%20glacier&t=k&z=11&ie=UTF8&iwloc=B&output=embed"
></iframe> ></iframe>
<H2>Details</H2> </PageGroup>
</PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Details</H2></Fragment>
<Paragraphs> <Paragraphs>
<Paragraph> <Paragraph>
As part of my time working on the As part of my time working on the
@@ -85,23 +93,23 @@ import { subTitles } from "./osu-ceoas-ocean-mixing-group.ts";
Robotic Oceanographic Surface Sampler</InlineLink Robotic Oceanographic Surface Sampler</InlineLink
>, I had the fantastic opportunity to be deployed at the LeConte Glacier >, I had the fantastic opportunity to be deployed at the LeConte Glacier
in Alaska! This started in early 2017 with setup and ocean trials in in Alaska! This started in early 2017 with setup and ocean trials in
nearby Petersburg. The team had sent multiple shipping containers with our nearby Petersburg. The team had sent multiple shipping containers with
robotic platforms and most equipment to assemble, test, and debug them a our robotic platforms and most equipment to assemble, test, and debug
few months prior, allowing us to get to work the moment we arrived. We them a few months prior, allowing us to get to work the moment we
spent multiple weeks at the docks with our makeshift workstations built arrived. We spent multiple weeks at the docks with our makeshift
from plywood and pelican cases, validating the hardware we'd sent, and workstations built from plywood and pelican cases, validating the
making adjustments with improved hardware we'd hand-carried on our hardware we'd sent, and making adjustments with improved hardware we'd
flights. This also provided a great opportunity to work out any final hand-carried on our flights. This also provided a great opportunity to
firmware and/or software bugs while the vehicles were still relatively work out any final firmware and/or software bugs while the vehicles were
easy to retrieve. After a short trip back home to recover, and prep any still relatively easy to retrieve. After a short trip back home to
last minute items we'd forgotten, our research team flew back and headed recover, and prep any last minute items we'd forgotten, our research
for the glacier! team flew back and headed for the glacier!
</Paragraph> </Paragraph>
<Paragraph> <Paragraph>
The towering mountain of ice sits roughly 30 miles from Petersburg, so The towering mountain of ice sits roughly 30 miles from Petersburg, so
we'd commissioned an off-season fishing vessel, Steller, and it's crew, to we'd commissioned an off-season fishing vessel, Steller, and it's crew,
take us as close to it as was reasonably safe. The team worked 24 hours a to take us as close to it as was reasonably safe. The team worked 24
day, on two shifts, deploying and retrieving the ROSS platforms, hours a day, on two shifts, deploying and retrieving the ROSS platforms,
performing repairs (as needed), recovering/processing collected data, performing repairs (as needed), recovering/processing collected data,
manually deploying the ship's <PopoverWordDefinition key="CTD" />, and manually deploying the ship's <PopoverWordDefinition key="CTD" />, and
occasionally spending considerable time pushing icebergs the size of occasionally spending considerable time pushing icebergs the size of
@@ -111,18 +119,20 @@ import { subTitles } from "./osu-ceoas-ocean-mixing-group.ts";
the limitations of this isolated (and salty) environment. the limitations of this isolated (and salty) environment.
</Paragraph> </Paragraph>
<Paragraph> <Paragraph>
On top of being a unique engineering and team building experience, LeConte On top of being a unique engineering and team building experience,
lives among the most beautiful places I've yet to experience in this life. LeConte lives among the most beautiful places I've yet to experience in
There's something special about being somewhere so incredibly remote and this life. There's something special about being somewhere so incredibly
untouched by humans. The pristine evergreen forests, eerie blue-green hues remote and untouched by humans. The pristine evergreen forests, eerie
of the glacier and icebergs, ancient towering mountains, and genuinely blue-green hues of the glacier and icebergs, ancient towering mountains,
curious looks from local land and marine life unfamiliar with human and genuinely curious looks from local land and marine life unfamiliar
presence made it humbly clear that for once we as humans were the odd ones with human presence made it humbly clear that for once we as humans were
out. These trips were ones that I will treasure and think back on fondly the odd ones out. These trips were ones that I will treasure and think
on for the rest of my life. back on fondly on for the rest of my life.
</Paragraph> </Paragraph>
</Paragraphs> </Paragraphs>
<H2>Videos</H2> </PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Videos</H2></Fragment>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2"> <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
{ {
videos.map((video) => ( videos.map((video) => (
@@ -135,4 +145,5 @@ import { subTitles } from "./osu-ceoas-ocean-mixing-group.ts";
)) ))
} }
</div> </div>
</PageGroup>
</ExperienceLayout> </ExperienceLayout>

View File

@@ -26,4 +26,5 @@ export const deploymentTimeline: timelineEntry[] = [
export const subTitles = [ export const subTitles = [
"Oregon State University", "Oregon State University",
"College of Earth, Ocean, and Atmospheric Sciences", "College of Earth, Ocean, and Atmospheric Sciences",
"Ocean Mixing Group",
]; ];

View File

@@ -3,17 +3,26 @@ import ExperienceLayout from "@layouts/ExperienceLayout.astro";
import H2 from "@components/H2.astro"; import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro"; import H3 from "@components/H3.astro";
import InlineLink from "@components/InlineLink.astro";
import Li from "@components/Li.astro";
import LinkButton from "@components/LinkButton.astro"; import LinkButton from "@components/LinkButton.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import PdfViewer from "@components/Media/PdfViewer.astro"; import PdfViewer from "@components/Media/PdfViewer.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 PopoverWordDefinition from "@components/PopoverWordDefinition.astro";
import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro";
import Timeline from "@components/Timeline/Timeline.astro"; import Timeline from "@components/Timeline/Timeline.astro";
import Ul from "@components/Ul.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts"; import type { carouselGroup } from "@interfaces/image-carousel.ts";
import type { categorySkills } from "@interfaces/skill-matrix.ts";
import type { timelineEntry } from "@interfaces/timeline.ts"; import type { timelineEntry } from "@interfaces/timeline.ts";
import electronics_box from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/electronics-box.jpg"; import electronics_box from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/electronics-box.jpg";
import jet_drive from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/jet-drive.jpg"; import jet_drive from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/jet-drive.jpg";
import ross_ebox_4p0 from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-ebox-4p0.jpg";
import ross_on_vessel_at_night from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-on-vessel-at-night.jpg"; import ross_on_vessel_at_night from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-on-vessel-at-night.jpg";
import ross_on_vessel from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-on-vessel.jpg"; import ross_on_vessel from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-on-vessel.jpg";
import publication from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-publication.pdf"; import publication from "@assets/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler/ross-publication.pdf";
@@ -31,6 +40,7 @@ const headerCarouselGroup: carouselGroup = {
ross_team, ross_team,
ross_on_vessel, ross_on_vessel,
ross_on_vessel_at_night, ross_on_vessel_at_night,
ross_ebox_4p0,
electronics_box, electronics_box,
jet_drive, jet_drive,
ui, ui,
@@ -50,6 +60,72 @@ const timeline: timelineEntry[] = [
date: "May 2018", date: "May 2018",
}, },
]; ];
const categorizedSkills: categorySkills[] = [
{
category: "Electrical",
skills: [
{
item: "Schematic & PCB Design",
subItems: [{ item: "Altium Designer" }],
},
{
item: "PCB Assembly & Rework",
subItems: [
{ item: "Handheld Soldering" },
{ item: "Handheld Hot-Air Reflow" },
{ item: "Oven Reflow" },
],
},
{
item: "Electrical Diagnostics",
subItems: [
{ item: "Multimeters" },
{ item: "Oscilloscopes" },
{ item: "Logic Analyzers" },
],
},
{
item: "Harnessing Fabrication",
subItems: [
{ item: "DC Power & Signal" },
{ item: "Low Frequency RF (<1GHz)" },
{ item: "Waterproofing" },
],
},
{
item: "Simulation",
subItems: [{ item: "LTspice" }],
},
],
},
{
category: "Software & Environments",
skills: [
{ item: "Git" },
{
item: "Programming Languages",
subItems: [
{ item: "Python 2/3" },
{ item: "Bash Shell Scripting" },
{ item: "Low-Level Embedded C/C++ (Atmel Studio)" },
{ item: "High-Level Embedded C/C++ (Arduino/Teensy)" },
{ item: "Matlab" },
],
},
{
item: "Operating Systems",
subItems: [
{
item: "Linux",
subItems: [{ item: "Ubuntu" }, { item: "Raspbian" }],
},
{ item: "Microsoft Windows" },
],
},
],
},
];
--- ---
<ExperienceLayout <ExperienceLayout
@@ -57,56 +133,158 @@ const timeline: timelineEntry[] = [
subTitles={subTitles} subTitles={subTitles}
> >
<Carousel carouselGroup={headerCarouselGroup} /> <Carousel carouselGroup={headerCarouselGroup} />
<div class="mt-4 flex items-center justify-center"> <div class="grid grid-flow-row place-content-center gap-4 md:grid-flow-col">
<LinkButton <LinkButton
href="https://tos.org/oceanography/article/autonomous-ctd-profiling-from-the-robotic-oceanographic-surface-sampler" href="https://tos.org/oceanography/article/autonomous-ctd-profiling-from-the-robotic-oceanographic-surface-sampler"
title="Official Scientific Publication" title="Official Scientific Publication"
/> />
<LinkButton
href="https://www.kfsk.org/2017/04/19/remote-controlled-kayaks-ready-research-leconte-glacier/"
title="KFSK Petersburg Feature / Interview"
/>
</div> </div>
<H2>Summary</H2> <PageGroup>
<H3>Timeline</H3> <Fragment slot="header"><H2>Summary</H2></Fragment>
<PageGroup>
<Fragment slot="header"><H3>Timeline</H3></Fragment>
<Timeline timeline={timeline} /> <Timeline timeline={timeline} />
<H3>Key Takeaways</H3> </PageGroup>
<ul class="list-inside list-disc"> <PageGroup>
<li> <Fragment slot="header"><H3>Key Takeaways</H3></Fragment>
<div class="inline-block"> <Ul>
Assembled, fabricated, and debugged both custom and <Li
<PopoverWordDefinition key="COTS" /> >Hand assembled and validated dozens of custom <PopoverWordDefinition
hardware and electronics. key="PCBs"
</div> />, wiring harnesses, and electronics boxes</Li
</li>
<li>Two</li>
<li>Three</li>
</ul>
<h3 class="my-4 font-bold md:text-lg">Skills Used</h3>
<div
class="border-caperren-green relative grid grid-flow-row gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
> >
<div> <Li
<div class="text-sm font-extrabold">Software</div> >Wrote, debugged, and assisted with development of embedded firmware</Li
<hr class="text-caperren-green" /> >
<ul class="list-inside list-disc text-sm"> <Li
<li>One</li> >Accompanied the team on two deployments to the LeConte glacier in
<li>Two</li> Alaska to gather melt and mixing data</Li
</ul> >
</div> </Ul>
<div> </PageGroup>
<div class="text-sm font-extrabold">Electrical</div> <SkillMatrix categorizedSkills={categorizedSkills} />
<hr class="text-caperren-green" /> </PageGroup>
</div> <PageGroup>
<div> <Fragment slot="header"><H2>Details</H2></Fragment>
<div class="text-sm font-extrabold">Mechanical</div> <PageGroup>
<hr class="text-caperren-green" /> <Fragment slot="header"><H3>ROSS Overview</H3></Fragment>
</div> <Paragraphs>
<div> <Paragraph>
<div class="text-sm font-extrabold">Other</div> ROSS was a gasoline-powered water-sampling robotics platform built
<hr class="text-caperren-green" /> around a Mokai jet-drive kayak. It's purpose was to continuously, and
</div> often autonomously, gather water data over extremely long distances
</div> and/or in locations where human-safety concerns would make gathering
<H2>Details</H2> it manually too risky. There were a variety of sensors it could be
power and voltage logging outfitted with depending on the needs of the exact research project
<H2>Official Scientific Publication</H2> and destination, but some common ones were an <PopoverWordDefinition
key="ADCP"
/> for gathering 3D water current vector data, a <PopoverWordDefinition
key="CTD"
/> for measuring water conductivity/temperature/depth, and a high-precision
GPS for generating meaningful 3D plots of the sensor data. These kayaks
have been deployed to places like the Indian/Pacific Ocean mixing line,
and along the active LeConte glacier terminus in Alaska, gathering novel
data on how vastly different bodies of water act when mixing.
</Paragraph>
<Paragraph>
In its original configuration, the Mokai kayak's throttle and steering
were already drive-by-wire, which made it an excellent starting point
for automating. It was also designed for easy transport, breaking down
into three major compartments that could easily fit in the back of a
short-bed pickup. For our custom hulls, Mokai also thickened the
plastic significantly and provided a bare minimum of electronics. This
barebones platform was then modified by our team to include a
storm-surge-rated intake and exhaust for the engine, a keel to improve
rough sea stability, a large alternator, and a plethora of mount
points the electronics, batteries, fuel, sensors, and radios.
</Paragraph>
<Paragraph>
In terms of the electronics and software for this project, the kayak
itself was centered around a Pixhawk flight controller flashed with a
modified Rover variant (this was before a dedicated boat option
existed). One pelican-case electronics box housed this controller, a
small <PopoverWordDefinition key="NUC" /> with <PopoverWordDefinition
key="UPS"
/>, wifi router, radio control receiver, satellite modem, and quite a
few custom <PopoverWordDefinition key="PCBs" /> for interfacing with external
electronics and implementing glue logic/safety overrides. A second box housed
nothing but sealed lead-acid batteries, which were charged by the alternator
on later revisions of the platform. The PC ran a custom python script, which
interfaced with a Matlab GUI over a remote radio link. The kayak could also
be overridden with an FrSky RC controller, when at close range, and additionally
allowed for direct control without the PC needing to be in-the-loop. To
see some of the custom hardware inside of these boxes, check out Nick McComb's
design pages for them
<InlineLink
href="https://nickmccomb.net/college/printed-circuit-boards#omg"
>here</InlineLink
>! For even more context on ROSS, and history from before I joined the
project, check out his <InlineLink
href="https://nickmccomb.net/college/ross">summary page</InlineLink
>.
</Paragraph>
</Paragraphs>
</PageGroup>
<PageGroup>
<Fragment slot="header"><H3>My Experience</H3></Fragment>
<Paragraphs>
<Paragraph>
I first started on this project by doing what I thought was a one-off
help session for Nick, working on an issue he was having getting
ROSS's engine to start and shut down properly. I had more experience
with engines, and engine control, so I quickly realized that a beefier
and high-voltage-rated relay was needed to avoid arc-welding the
contacts closed during shutdown. He rolled out a <InlineLink
href="https://nickmccomb.net/college/printed-circuit-boards/ross-ebox-auxillary"
>new board revision</InlineLink
> with those changes and it was the final version used for the rest of ROSS's
lifetime. This little taste of the project, and some wishful prodding from
Nick, was enough for me to join the team part-time.
</Paragraph>
<Paragraph>
While the original plan for me was to re-write the <PopoverWordDefinition
key="GUI"
/> for ROSS in Python using Qt, it turns out they needed my help on the
electrical and firmware side more than anything, so most of my time at the
lab was focused on that. I hand-assembled so many of Nick's circuit boards
at this lab that I still can pick his out of a lot from design aesthetic
alone! I also helped with plenty of wiring harness builds, electrical box
fabrication, embedded firmware development, and of course, plenty of electrical
and software debugging. One thing that this project taught me very quickly
was how difficult it was to make reliable hardware in a high vibration,
electrically noisy, and salt-laden environments. The number of PCBs we went
through, alongside wiring harnesses, was pretty incredible considering the
lengths we went to in order to protect them.
</Paragraph>
<Paragraph>
A very unique aspect of this team/project, and a large part of why I
was drawn to it, was that it was about as hands-on as you could
possibly get. Doubly so for an undergraduate student! Not only did I
get to design and repair a real robot, but it was actually being used
for proper scientific research! We would regularly go to Newport, OR
for testing and have to make crazy additions and repairs on the fly.
This got even more extreme during my deployments to the <InlineLink
href="http://localhost:4321/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler"
>LeConte glacier</InlineLink
>, as you had to get creative and fix things with what you had on-hand
due to how remote we were. These are experiences that graduate
students rarely even get to have, so I'm extremely thankful and fond
of the time I spent here. Huge shout out to <InlineLink
href="https://nickmccomb.net">Nick</InlineLink
>, again, who made it possible in the first place! Also be sure to
check out the scientific paper on this project below!
</Paragraph>
</Paragraphs>
</PageGroup>
</PageGroup>
<PageGroup>
<Fragment slot="header"><H2>Official Scientific Publication</H2></Fragment>
<div class="h-334"> <div class="h-334">
<PdfViewer pdf={publication} /> <PdfViewer pdf={publication} />
</div> </div>
</PageGroup>
</ExperienceLayout> </ExperienceLayout>

View File

@@ -5,6 +5,7 @@ import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro"; import H3 from "@components/H3.astro";
import InlineLink from "@components/InlineLink.astro"; import InlineLink from "@components/InlineLink.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import PageGroup from "@components/PageGroup.astro";
import Paragraph from "@components/Paragraph.astro"; import Paragraph from "@components/Paragraph.astro";
import Paragraphs from "@components/Paragraphs.astro"; import Paragraphs from "@components/Paragraphs.astro";
@@ -27,42 +28,49 @@ const rfidImplantCarouselGroup: carouselGroup = {
--- ---
<HobbyLayout title="Body Mods"> <HobbyLayout title="Body Mods">
<H2>RFID Implant</H2> <PageGroup>
<Fragment slot="header"><H2>RFID Implant</H2></Fragment>
<Carousel carouselGroup={rfidImplantCarouselGroup} /> <Carousel carouselGroup={rfidImplantCarouselGroup} />
<H3>Details</H3> <PageGroup>
<Fragment slot="header"><H3>Details</H3></Fragment>
<Paragraphs> <Paragraphs>
<Paragraph> <Paragraph>
Back when I was in college, a few of my friends and I got this crazy idea Back when I was in college, a few of my friends and I got this crazy
to all get RFID implants together. They are essentially the same things idea to all get RFID implants together. They are essentially the same
you'd use to microchip a pet, but with a slightly different firmware things you'd use to microchip a pet, but with a slightly different
configuration, allowing scans with any 125KHz-compatible reader. The firmware configuration, allowing scans with any 125KHz-compatible
implants came from <InlineLink reader. The implants came from <InlineLink
href="https://dangerousthings.com/product/xem/" href="https://dangerousthings.com/product/xem/"
>dangerousthings.com</InlineLink >dangerousthings.com</InlineLink
>, and we were lucky enough to have a vet-med student as a friend who made >, and we were lucky enough to have a vet-med student as a friend who
the installation a quick and painless process! I'm glad that I'm not made the installation a quick and painless process! I'm glad that I'm
afraid of needles, as the 16 gauge injector the kit came with was nothing not afraid of needles, as the 16 gauge injector the kit came with was
to scoff at. Since healing, you would never know the implant was there, nothing to scoff at. Since healing, you would never know the implant
with the site leaving no scar or visible indication of its presence. was there, with the site leaving no scar or visible indication of its
presence.
</Paragraph> </Paragraph>
<Paragraph> <Paragraph>
With that out of the way, our group began work on hardware which would With that out of the way, our group began work on hardware which would
support the new implants. The goal was to have a generic usb-keyboard support the new implants. The goal was to have a generic usb-keyboard
emulator for typing passwords with a valid scan, a car off-acc-on ignition emulator for typing passwords with a valid scan, a car off-acc-on
replacement, and a fairly specialized modification to the OSU Robotics ignition replacement, and a fairly specialized modification to the OSU
Club's doorway scanning system so they would support these on top of the Robotics Club's doorway scanning system so they would support these on
official OSU ID cards. As tends to happen, life got busy, and only the top of the official OSU ID cards. As tends to happen, life got busy,
usb-keyboard emulator actually came to fruition. The electronics and and only the usb-keyboard emulator actually came to fruition. The
primary firmware were handled by <InlineLink href="https://nickmccomb.net" electronics and primary firmware were handled by <InlineLink
>Nick McComb</InlineLink href="https://nickmccomb.net">Nick McComb</InlineLink
>, enclosure by <InlineLink href="https://dylanthrush.com" >, enclosure by <InlineLink href="https://dylanthrush.com"
>Dylan Thrush</InlineLink >Dylan Thrush</InlineLink
>, and I supported some minor firmware development and debugging. If you >, and I supported some minor firmware development and debugging. If
want to see an example of the keyboard emulator unlocking a PC, check out you want to see an example of the keyboard emulator unlocking a PC,
the video on <InlineLink check out the video on <InlineLink
href="https://nickmccomb.net/college/printed-circuit-boards/computer-access-module" href="https://nickmccomb.net/college/printed-circuit-boards/computer-access-module"
>Nick's website</InlineLink >Nick's website</InlineLink
>! >!
</Paragraph> </Paragraph>
</Paragraphs> </Paragraphs>
</PageGroup>
</PageGroup>
</HobbyLayout> </HobbyLayout>

View File

@@ -1,7 +1,12 @@
--- ---
import HobbyLayout from "@layouts/HobbyLayout.astro";
import H2 from "@components/H2.astro";
import LinkButton from "@components/LinkButton.astro"; import LinkButton from "@components/LinkButton.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import HobbyLayout from "@layouts/HobbyLayout.astro"; import PageGroup from "@components/PageGroup.astro";
import Paragraph from "@components/Paragraph.astro";
import Paragraphs from "@components/Paragraphs.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts"; import type { carouselGroup } from "@interfaces/image-carousel.ts";
@@ -31,44 +36,53 @@ const headerCarouselGroup: carouselGroup = {
}; };
--- ---
<HobbyLayout title="Motorcycling - Chubby Buttons 2 Mount"> <HobbyLayout
title="Chubby Buttons 2 Mount"
subTitles={["Hobbies", "Motorcycling"]}
>
<Carousel carouselGroup={headerCarouselGroup} /> <Carousel carouselGroup={headerCarouselGroup} />
<div class="mt-4 flex items-center justify-center"> <div class="flex items-center justify-center">
<LinkButton <LinkButton
href="https://cad.onshape.com/documents/816b0b1bef7883d4dc25c66c/v/e11fe68753e080b72015cfb8/e/3802abbd9d7b7c4d2c7ebad3" href="https://cad.onshape.com/documents/816b0b1bef7883d4dc25c66c/v/e11fe68753e080b72015cfb8/e/3802abbd9d7b7c4d2c7ebad3"
title="Onshape CAD Design Files" title="Onshape CAD Design Files"
/> />
</div> </div>
<p class="mt-4"> <PageGroup>
<Fragment slot="header"><H2>Details</H2></Fragment>
<Paragraphs>
<Paragraph>
Having ridden motorcycles since I was sixteen, and being an avid music Having ridden motorcycles since I was sixteen, and being an avid music
enjoyer, I'd been looking for a way to improve my music listening experience enjoyer, I'd been looking for a way to improve my music listening
while on-the-go. One large pain-point I'd always had was with controlling experience while riding. One large pain-point I'd always had was
track selection and volume levels while my gloves were on, as smartphones controlling track selection and volume levels while my gloves were on,
don't respond very well to this, if at all. In 2023 I found out about chubby as smartphones don't respond very well to this, if at all. In 2023 I
buttons, a low-power and highly water-resistant media controller found out about chubby buttons, a low-power and highly water-resistant
specifically designed for use with gloves! The only problem was that it was media controller specifically designed for use with gloves! The only
designed to be worn on your arm using a strap, which isn't very practical on problem was that it was designed to be worn on your arm using a strap,
a motorcycle. which isn't very practical on a motorcycle.
</p> </Paragraph>
<p class="mt-4"> <Paragraph>
When starting this project, I'd recently gotten a 3D Printer, so having some When starting this project, I'd recently gotten a 3D printer, so having
baseline modelling skills I took some measurements, and began designing a some baseline modelling skills I took some measurements, and began
proper mount. I already owned and used many 1" RAM compatible mounts and designing a proper mount. I already owned and used many 1" RAM
gear on my bikes, so I decided to make this one natively support the ball compatible mounts and gear on my bikes, so I decided to make this one
size to use an existing clamp I had stored away. This design was the first natively support the ball size to use an existing clamp I had stored
where I decided to use heat-set inserts in the plastic, along with some away. This design was the first where I decided to use heat-set inserts
medium-strength Loctite on the fasteners, due to the high-vibration in the plastic, along with some medium-strength Loctite on the
environment the mount would see. The print was also done using a UV fasteners, due to the high-vibration environment the mount would see.
resistant, high-temp rated, and non-water-absorbing ASA filament, as the The print was also done using a UV resistant, high-temp rated, and
direct expose to the elements would not allow something like cheap PLA to non-water-absorbing ASA filament, as the direct exposure to the elements
last very long. would not allow something like cheap PLA to last very long.
</p> </Paragraph>
<p class="mt-4"> <Paragraph>
While my first iteration was sized appropriately and went together with no While my first iteration was sized appropriately and went together with
issues, the ball mount neck ended up snapping due to a low infill no issues, the ball mount neck ended up snapping due to a low infill
percentage. After changing that area to 100% infill, including a handful of percentage. After changing that area to 100% infill, including a handful
the rear mount layers that it attached to, a second iteration has worked of the layers at the rear mounting face where the neck attaches, a
perfectly for a few years now! If you're interested in printing this second iteration has worked perfectly for a few years now! If you're
yourself, feel free to download the model using the button under the photos! interested in printing this yourself, feel free to download the model
</p> using the button under the photos!
</Paragraph>
</Paragraphs>
</PageGroup>
</HobbyLayout> </HobbyLayout>

View File

@@ -4,6 +4,7 @@ import HobbyLayout from "@layouts/HobbyLayout.astro";
import H2 from "@components/H2.astro"; import H2 from "@components/H2.astro";
import H3 from "@components/H3.astro"; import H3 from "@components/H3.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import PageGroup from "@components/PageGroup.astro";
import type { carouselGroup } from "@interfaces/image-carousel.ts"; import type { carouselGroup } from "@interfaces/image-carousel.ts";
@@ -39,26 +40,35 @@ const kz750CarouselGroup: carouselGroup = {
}; };
--- ---
<HobbyLayout title="Motorcycling - Lineup"> <HobbyLayout title="Lineup" subTitles={["Hobbies", "Motorcycling"]}>
<H2>Current Lineup</H2> <PageGroup>
<H3>2015 Yamaha FJR 1300</H3> <Fragment slot="header"><H2>Current Lineup</H2></Fragment>
<PageGroup>
<Fragment slot="header"><H3>2015 Yamaha FJR 1300</H3></Fragment>
<Carousel carouselGroup={fjrCarouselGroup} /> <Carousel carouselGroup={fjrCarouselGroup} />
</PageGroup>
<H3>2021 CSC SG400</H3> <PageGroup>
<Fragment slot="header"><H3>2021 CSC SG400</H3></Fragment>
<Carousel carouselGroup={cscCarouselGroup} /> <Carousel carouselGroup={cscCarouselGroup} />
</PageGroup>
<H2>Prior Lineup</H2> </PageGroup>
<H3>2005 Suzuki DRZ 400</H3> <PageGroup>
<Fragment slot="header"><H2>Prior Lineup</H2></Fragment>
<PageGroup>
<Fragment slot="header"><H3>2005 Suzuki DRZ 400</H3></Fragment>
<Carousel carouselGroup={drzCarouselGroup} /> <Carousel carouselGroup={drzCarouselGroup} />
</PageGroup>
<h3 class="my-4 font-bold underline md:text-lg"> <PageGroup>
1991 Kawasaki Concours ZG1000 <Fragment slot="header"><H3>1991 Kawasaki Concours ZG1000</H3></Fragment>
</h3>
<Carousel carouselGroup={concoursCarouselGroup} /> <Carousel carouselGroup={concoursCarouselGroup} />
</PageGroup>
<H3>1979 Kawasaki KZ750</H3> <PageGroup>
<Fragment slot="header"><H3>1979 Kawasaki KZ750</H3></Fragment>
<Carousel carouselGroup={kz750CarouselGroup} /> <Carousel carouselGroup={kz750CarouselGroup} />
</PageGroup>
<H3>1991 Kawasaki Ninja 600R</H3> <PageGroup>
<Fragment slot="header"><H3>1991 Kawasaki Ninja 600R</H3></Fragment>
<Carousel carouselGroup={ninjaCarouselGroup} /> <Carousel carouselGroup={ninjaCarouselGroup} />
</PageGroup>
</PageGroup>
</HobbyLayout> </HobbyLayout>

View File

@@ -4,6 +4,7 @@ import BaseLayout from "@layouts/BaseLayout.astro";
import H2 from "@components/H2.astro"; import H2 from "@components/H2.astro";
import InlineLink from "@components/InlineLink.astro"; import InlineLink from "@components/InlineLink.astro";
import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro"; import Carousel from "@components/Media/CustomCarousel/CustomCarousel.astro";
import PageGroup from "@components/PageGroup.astro";
import Paragraph from "@components/Paragraph.astro"; import Paragraph from "@components/Paragraph.astro";
import Paragraphs from "@components/Paragraphs.astro"; import Paragraphs from "@components/Paragraphs.astro";
@@ -21,7 +22,8 @@ const headerCarouselGroup: carouselGroup = {
<BaseLayout title="About" showTitle={false}> <BaseLayout title="About" showTitle={false}>
<Carousel carouselGroup={headerCarouselGroup} /> <Carousel carouselGroup={headerCarouselGroup} />
<H2>Who Am I</H2> <PageGroup>
<Fragment slot="header"><H2>Who Am I</H2></Fragment>
<Paragraphs> <Paragraphs>
<Paragraph> <Paragraph>
My name is Corwin Perren, and I'm a multi-disciplinary engineer with a <InlineLink My name is Corwin Perren, and I'm a multi-disciplinary engineer with a <InlineLink
@@ -29,23 +31,24 @@ const headerCarouselGroup: carouselGroup = {
> from Oregon State University. For as long as I can remember, I've been fascinated > from Oregon State University. For as long as I can remember, I've been fascinated
by how things work, never being shy about taking them apart to learn the gritty by how things work, never being shy about taking them apart to learn the gritty
details. At a young age, I began tinkering, adding lights and fans and doorbells details. At a young age, I began tinkering, adding lights and fans and doorbells
to the pretend cardboard box houses my brother and I would play in. Later, I to the pretend cardboard box houses my brother and I would play in. Later,
learned to solder, work on vehicles and engines, install and run Linux, manage I learned to solder, work on vehicles and engines, install and run Linux,
enterprise computing infrastructure, build and repair computers, write scripts, manage enterprise computing infrastructure, build and repair computers, write
and by the end of high school set out with a clear goal for my college years. scripts, and by the end of high school set out with a clear goal for my college
I wanted to learn and teach myself enough to be able to think up almost any years. I wanted to learn and teach myself enough to be able to think up almost
project, encompassing all facets of engineering, and be capable of driving it any project, encompassing all facets of engineering, and be capable of driving
to completion with my own skill set. it to completion with my own skill set.
</Paragraph> </Paragraph>
<Paragraph> <Paragraph>
I think young me would be very pleased by how well I managed to achieve I think young me would be very pleased by how well I managed to achieve
that goal! Through college, I learned electronics and PCB design, embedded that goal! Through college, I learned electronics and PCB design,
and pc programming, basic mechanical design and fabrication, on top of embedded and pc programming, basic mechanical design and fabrication, on
learning how to work well with others in a team. I quickly realized that top of learning how to work well with others in a team. I quickly
robotics was an ideal focus due to its inherent multi-disciplinary nature, realized that robotics was an ideal focus due to its inherent
and joined the OSU Robotics Club, which introduced me to people who are multi-disciplinary nature, and joined the OSU Robotics Club, which
still my best friends today. Through student engineering jobs, I had the introduced me to people who are still my best friends today. Through
unique opportunity to work on some incredible projects such as the student engineering jobs, I had the unique opportunity to work on some
incredible projects such as the
<InlineLink <InlineLink
href="/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler" href="/experience/osu-ceoas-ocean-mixing-group/robotic-oceanographic-surface-sampler"
>robotic oceanographic surface sampler</InlineLink >robotic oceanographic surface sampler</InlineLink
@@ -67,13 +70,13 @@ const headerCarouselGroup: carouselGroup = {
> at SpaceX in Hawthorne at the end of college, I applied for a <InlineLink > at SpaceX in Hawthorne at the end of college, I applied for a <InlineLink
href="/experience/spacex/hardware-test-engineer-i-ii" href="/experience/spacex/hardware-test-engineer-i-ii"
>test engineering</InlineLink >test engineering</InlineLink
> position with the company's Starlink team and was hired in mid-2019. For six > position with the company's Starlink team and was hired in mid-2019. For
years, I developed test system hardware, software, harnesses, mechanical fixtures, six years, I developed test system hardware, software, harnesses, mechanical
devops infrastructure, websites, and tooling to ensure that Starlink, Falcon, fixtures, devops infrastructure, websites, and tooling to ensure that Starlink,
Dragon, and Starship component tests were producing well-validated and reliable Falcon, Dragon, and Starship component tests were producing well-validated
hardware. Through it all, I got to apply and hone every skill I had developed, and reliable hardware. Through it all, I got to apply and hone every skill
while learning countless more. Now though, it's on to the next adventure, whatever I had developed, while learning countless more. Now though, it's on to the
that may be! next adventure, whatever that may be!
</Paragraph> </Paragraph>
<Paragraph> <Paragraph>
To learn more about my experiences, hobbies, interests, and skills, feel To learn more about my experiences, hobbies, interests, and skills, feel
@@ -85,12 +88,15 @@ const headerCarouselGroup: carouselGroup = {
>rfid implant</InlineLink >rfid implant</InlineLink
> in my hand! > in my hand!
</Paragraph> </Paragraph>
<Paragraph> <Paragraph class="mt-8 flex flex-col items-center" initialTab={false}>
<div>
If you're interested in contacting me, feel free to message on <InlineLink If you're interested in contacting me, feel free to message on <InlineLink
href="https://github.com/caperren">LinkedIn</InlineLink href="https://github.com/caperren">LinkedIn</InlineLink
>, or via the primary contact methods on my <InlineLink >, or via the primary contact methods on my <InlineLink
href="/resume/2025-11-10-infrastructure-engineer">resume</InlineLink href="/resume/2025-11-10-infrastructure-engineer">resume</InlineLink
>. >.
</div>
</Paragraph> </Paragraph>
</Paragraphs> </Paragraphs>
</PageGroup>
</BaseLayout> </BaseLayout>