294 lines
12 KiB
TypeScript
294 lines
12 KiB
TypeScript
|
|
export type MoreSection = {
|
|
title?: string;
|
|
text: string;
|
|
}
|
|
|
|
export type SocialLink = {
|
|
label: string;
|
|
url: string;
|
|
icon: "gh" | "li" | "x" | "dev";
|
|
};
|
|
|
|
export type ContactMethod = {
|
|
masked: boolean;
|
|
label: string;
|
|
icon: string;
|
|
}
|
|
|
|
export type Project = {
|
|
id: number;
|
|
slug: string;
|
|
title: string;
|
|
description: string;
|
|
details?: string;
|
|
tags: string[];
|
|
images?: string[];
|
|
videos?: string[];
|
|
link: string;
|
|
year: string;
|
|
};
|
|
|
|
|
|
export const PROFILE = {
|
|
name: "Hunter W",
|
|
title: "Software Engineer",
|
|
email: "contact@hwilliams.dev",
|
|
bio: `I build user experiences before I write code.
|
|
Experience with full-stack development across a variety of frameworks and languages including Vue,
|
|
React, Next.JS, Nuxt, Node.JS, Express, Flask, FastAPI, Gunicorn, and more.`,
|
|
moreSections: [
|
|
{
|
|
title:"A little more about me",
|
|
text: `I graduated with a B.S. in Computer Science from Georgia Southern University in May 2025.
|
|
I have been working with AWS building analytics and monitoring dashboards with a sprinkle of prompt
|
|
engineering on major production projects.`
|
|
},
|
|
{
|
|
text: "I make mods for video games such as Space Engineers and Rimworld in my free time."
|
|
},
|
|
{
|
|
title:"My goals",
|
|
text: `User experience. \n \n Nothing makes me happier than seeing someone excited to use the software I make, and the way that happens is by practicing
|
|
development techniques that make a good user experience. I especially enjoy peeling back the layers of old systems to explore how an existing
|
|
user experience can be improved. I love the words 'Wow, it used to be difficult to do this!'.
|
|
`
|
|
},
|
|
{
|
|
title:"My dreams",
|
|
text: `Stop me if you've heard this one before: I left college with a burning passion for machine learning and artificial intelligence. It's still there, and despite
|
|
the trouble going on in the world right now I see a bright future for how these incredibly advanced statistical models can still be applied in new ways.
|
|
\n
|
|
`
|
|
},
|
|
{
|
|
title:"Wow, you're still here?",
|
|
text: `I appreciate you, but I am totally out of things to talk about.`
|
|
}
|
|
] satisfies MoreSection[],
|
|
moreSectionsStart: 1,
|
|
links: [
|
|
{ label: "GitHub", url: "https://github.com/FerrenF", icon: "gh" },
|
|
{ label: "LinkedIn", url: "https://www.linkedin.com/in/hwilliamsf/", icon: "li" }
|
|
] satisfies SocialLink[],
|
|
contactMethods: [{
|
|
masked: true,
|
|
label: "contact@hwilliams.dev",
|
|
icon: "email"
|
|
}
|
|
] satisfies ContactMethod[]
|
|
};
|
|
|
|
export const SITE = {
|
|
title: "Hunter W. - Software Engineer",
|
|
description: "SWE Looking for work",
|
|
source: {
|
|
label: "Git",
|
|
link: "https://git.hwilliams.dev/hwilliams/hwilliams-dev"
|
|
}
|
|
};
|
|
|
|
export const PROJECTS: Project[] = [{
|
|
id: 1,
|
|
slug: "flowbased-agent-management",
|
|
title: "Flow-Based Agent Management platform",
|
|
description: "This Flow-based Agent Managemment (FAM) platform is a real-world example of an Agent support tool designed to streamline in-person interactions.",
|
|
details: `# Flow-based Agent Management platform (FAM)
|
|
|
|
This Flow-based Agent Managemment (FAM) platform is designed to optimize and streamline in-person digitally assisted transactions/communication between a guest and an agent.
|
|
To do this, FAM seeks to create 'workflows' from sub-processes identified during normal business operation. Big impacts are achieved just by shaving seconds off of the effort and time required to fulfill a customer's needs at the counter and building
|
|
workflows that guide an agent through them rather than rely on experience.
|
|
|
|
<blockquote>A welcome screen using the default theme.
|
|
<a target="_blank" href="/img/projects/fam/example-welcome.png">
|
|
<img src="/img/projects/fam/example-welcome.png" alt="Alt text" width="600"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
## Private Repository
|
|
The complete implementation of this project was tailored to the needs of a large organization. As such, the source for this project is private.
|
|
|
|
<blockquote>A short video of the platform's operation.
|
|
<video width="640" height="360" controls>
|
|
<source src="/img/projects/fam/runthrough.mp4" type="video/mp4">
|
|
Your browser does not support the video tag.
|
|
</video>
|
|
</blockquote>
|
|
|
|
## Summary
|
|
|
|
In the context of <b>FAM</b>, an \`interaction\` is the behavior that occurs between a guest and an agent.
|
|
An \`agent\` is a real-person (and most often a representative of some business) whom is interacting with a \`guest\` in order to exchange information or complete some task.
|
|
|
|
A front-desk employee at a hotel checking in a guest is an easy to reach example. The ticketing/admission agents at an event might be another.
|
|
These agent to guest interactions are what drive an organization on the ground.
|
|
|
|
|
|
<blockquote>A standard conversation flow
|
|
<a target="_blank" href="/img/projects/fam/standard-conversation-flow.png">
|
|
<img src="/img/projects/fam/standard-conversation-flow.png" alt="Alt text" />
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
These interactions might repeat throughout normal business operation, and more than one may happen at once. Agents can
|
|
(in general) only handle one interaction at a time.
|
|
|
|
|
|
<blockquote>A line of workflows waiting to happen
|
|
<a target="_blank" href="/img/projects/fam/flow-lineup.png">
|
|
<img src="/img/projects/fam/flow-lineup.png" alt="Alt text" />
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
Scale this up. Hundreds of guests, or thousands of guests arriving at a high rate. A once a year event is happening or somesuch.
|
|
Most organizations at such scale aren't going to have a single agent handling any task that might be a bottleneck to normal operation.
|
|
|
|
|
|
<blockquote>An surge of workflows happening all at once
|
|
<a target="_blank" href="/img/projects/fam/flow-lineup-at-scale.png">
|
|
<img src="/img/projects/fam/flow-lineup-at-scale.png" alt="Alt text" />
|
|
</a>
|
|
</blockquote>
|
|
|
|
With or without the additional help — at scale — little variances in the amount of time spent in every component of an interaction while
|
|
completing tasks and exchanging information might have a very high cumulative impact on a business' ability to scale operation to bursts in demand.
|
|
|
|
FAM supports breaking these interactions down into streamlined, consistent, efficient, repeatable, and flexible
|
|
workflows.
|
|
|
|
|
|
<blockquote>
|
|
<a target="_blank" href="/img/projects/fam/workflow-steps.png">
|
|
<img src="/img/projects/fam/workflow-steps.png" alt="A workflow divides some business process into a sequence of steps." width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
<blockquote>
|
|
<a target="_blank" href="/img/projects/fam/workflow-abandon.png">
|
|
<img src="/img/projects/fam/workflow-abandon.png" alt="A workflow is easy to repeat or abandon." width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
<blockquote>
|
|
<a target="_blank" href="/img/projects/fam/workflow-sequence-trav.png">
|
|
<img src="/img/projects/fam/workflow-sequence-trav.png" alt="A workflow may allow traversal between steps." width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
There is a minimum amount of time that it takes an agent to complete a task in a UI, on average, and a reasonable maximum amount of time that might
|
|
be spent on the same task in the same UI, on average.
|
|
|
|
|
|
<blockquote>
|
|
<a target="_blank" href="/img/projects/fam/variables.png">
|
|
<img src="/img/projects/fam/variables.png" alt="A workflow may allow traversal between steps." width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
FAM targets these little variances. By doing this, FAM reduces the amount of time lost to mistakes and the overall interaction duration without reducing the quality of the interaction
|
|
through purpose-built UX-first guided workflows.
|
|
|
|
Task identification from business analysis are made into functional workflows that support reducing the time taken to complete tasks while also addressing the variability in
|
|
how much time that it takes to complete these tasks.
|
|
|
|
|
|
<blockquote>The FAM platform runs on a vue/nuxt stack. Here's a part of the app structure in a diagram, without exposing too much.
|
|
<a target="_blank" href="/img/projects/fam/reference-1.png">
|
|
<img src="/img/projects/fam/workflow.png" alt="Workflow architecture" width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
A step can contain any type of work, and can be used in multiple workflows.
|
|
|
|
|
|
An identification step for a check-in process using the default template might look like such:
|
|
|
|
<blockquote>The general feel of a workflow step.
|
|
<a target="_blank" href="/img/projects/fam/flow-look-1.png">
|
|
<img src="/img/projects/fam/flow-look-1.png" alt="Example Step" width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
In this picture, a guest has had their member ID scanned on the first and their profile information is displayed. The first step is now locked and the agent must reset to go back.
|
|
|
|
The area with a marching border on the right side integrates an external barcode scanner in order to
|
|
read information on the back of US driver's license.
|
|
|
|
This information is compared with the displayed profile on the left, and discrepencies are highlighted in yellow.
|
|
|
|
Checking the acknowledgement box at the bottom moves the workflow into the next step by fulfulling the step advancement conditions.
|
|
|
|
<blockquote>The major components of this UI.
|
|
<a target="_blank" href="/img/projects/fam/flow-look-2.png">
|
|
<img src="/img/projects/fam/flow-look-2.png" alt="Example Step" width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
## Implementation
|
|
|
|
This platform was implemented as a solution for in-person registration, VIP registration, pre-event mailouts, and entitlements fulfillment for an Atlanta-based organization's yearly convention for May 2026, where it achieved significant success:
|
|
The setup consists of a Vue 3 frontend and a configurable backend interface. This particular implementation utilized a Perl catalyst backend. Standard 2D barcode scanning devices and RFID tag readers were used
|
|
in the guest identification system and have out-of-the box modular support in flows created on the platform.
|
|
|
|
<pre>Some Stats:</pre>
|
|
|
|
- Single day registration of over 10,000 guests with an average processing time of about 45 seconds.
|
|
- Previous year: ~2 minutes.
|
|
- No single guest wait time greater than 10 minutes.
|
|
- Previous year had lines that wrapped around the entire building and there were stories of four hour waits.
|
|
|
|
<blockquote>A testament
|
|
<a target="_blank" href="/img/projects/fam/stats-2026-1.png">
|
|
<img src="/img/projects/fam/stats-2026-1.png" alt="Example Step" width="800"/>
|
|
</a>
|
|
</blockquote>
|
|
|
|
|
|
A real-world solution for event staff and volunteer management.
|
|
`,
|
|
tags: ["Vue", "Node.JS", "Event-Management", "Real-Time", "Full-Stack"],
|
|
link: "private",
|
|
year: "2026",
|
|
images: [ "img/projects/fam/example-welcome.png", "img/projects/fam/example-step-in-flow.png"],
|
|
videos: [ "img/projects/fam/runthrough.mp4" ]
|
|
},{
|
|
id: 2,
|
|
slug: "clean-space",
|
|
title: "Clean Space",
|
|
description: "Clean Space is an architecture, proof of concept, and an in-development tool for Space Engineers and Space Engineers 2 server owners featuring client and server side .",
|
|
tags: ["C#", ".NET", "WPF", "Netcode", "Security"],
|
|
link: "https://github.com/FerrenF/CleanSpace",
|
|
year: "2025",
|
|
}, {
|
|
id: 3,
|
|
slug: "personal-portfolio",
|
|
title: "Personal Portfolio Website",
|
|
description: "This very website! Built with Next.JS, React, and TypeScript. Featuring a custom CMS and a lot of custom-built components and hooks.",
|
|
tags: ["Next.JS", "React", "TypeScript", "Vercel"],
|
|
link: "https://git.hwilliams.dev/hwilliams/hwilliams-dev",
|
|
year: "2026",
|
|
}];
|
|
|
|
|
|
import { remark } from "remark";
|
|
import remarkParse from "remark-parse";
|
|
import rehypeRaw from "rehype-raw";
|
|
import rehypeStringify from "rehype-stringify";
|
|
import remarkRehype from "remark-rehype";
|
|
|
|
|
|
export async function getProjectDetails(slug: string) {
|
|
const p = PROJECTS.find((v)=>v.slug == slug);
|
|
if (!p || !p.details) return null;
|
|
const re = await remark()
|
|
.use(remarkParse)
|
|
.use(remarkRehype, { allowDangerousHtml: true })
|
|
.use(rehypeRaw)
|
|
.use(rehypeStringify).process(p.details);
|
|
return re?.toString();
|
|
} |