Rhys · developer portfolio
Java backend engineer
in the making.
Web developer already.
Java for depth. The web for clients. Enterprise automation for a living. Everything here is real work with the decisions left in - including the ones I would make differently now.
Three ways in. Pick whichever matches why you came.
- Days
- RPA developer, Traverse Automation
- Nights
- BSc Computing & IT, Open University
- Between
- Freelance web development at byjoio
Eight places, joined where the work is actually joined. Hover a point to light its routes; arrow keys walk them once focused. Anywhere you have been stays lit.
Project · Java
Mexveng
A 2D medieval RPG in Java and LibGDX. It exists because tutorials end before the hard parts begin - I wanted a codebase big enough that architecture decisions have consequences.
Top-down world, tile maps, entities, combat, dialogue. Solo project, long-running, and deliberately unglamorous under the hood: plain Java, explicit state, no magic. When something breaks at 11pm I want to read the code and know why.
Decision: why Java and LibGDX, not a full engine
I'm moving into Java backend work, so every hour in Mexveng is an hour in the language I'm betting my career on. LibGDX gives me a game loop and rendering, then stays out of the way - the architecture is mine to get right or wrong, which is exactly the practice I'm here for. Unity would have shipped a game faster and taught me less.
Decision: explicit over clever
Mexveng has a house rule: if a line needs a comment to explain what it does, rewrite the line. Cleverness is a cost you pay every time you read the file. The walkthrough below is real style, not cleaned up for visitors - four corner checks written out by hand instead of a loop, because four named checks read faster than one abstract one.
Feel the movement
This is not Mexveng running in your browser. It is Mexveng's movement and collision model, ported to about ninety lines of JavaScript so you can feel a design decision instead of reading about it. Notice how you slide along walls when moving diagonally into them - that behaviour falls out of the code below, not out of extra code.
Click or tab to the canvas, then WASD or arrow keys. Touch: use the pad.
The real thing, in Java
The class the demo above reimplements. Step through the decisions - each one exists because a bug taught me it should.
public final class Movement {
private static final float MAX_STEP = 1f / 30f;
private final TileMap map;
private final Body body;
public Movement(TileMap map, Body body) {
this.map = map;
this.body = body;
}
public void update(float rawDelta, Vector2 input) {
float delta = Math.min(rawDelta, MAX_STEP);
if (input.len2() > 1f) {
input.nor();
}
float nextX = body.x + input.x * body.speed * delta;
if (!collides(nextX, body.y)) {
body.x = nextX;
}
float nextY = body.y + input.y * body.speed * delta;
if (!collides(body.x, nextY)) {
body.y = nextY;
}
}
private boolean collides(float x, float y) {
return map.isSolidAt(x, y)
|| map.isSolidAt(x + body.width, y)
|| map.isSolidAt(x, y + body.height)
|| map.isSolidAt(x + body.width, y + body.height);
}
}
-
Clamp the frame time
Tab away from the game and come back: the next frame reports a huge delta, and an unclamped body teleports through walls. Clamping to a thirtieth of a second means the worst case is the game slowing down, never breaking. One line, one whole class of bugs gone.
-
Normalise diagonal input
Holding up and right gives an input vector of length 1.41 - free 41% speed boost for diagonal walkers. Normalising only when the length exceeds 1 keeps analogue sticks working: a half-tilted stick should still mean half speed.
-
Move one axis at a time
The decision the demo lets you feel. Try X and Y together and a diagonal walk into a wall just stops dead. Resolve X first, then Y, and sliding along walls falls out for free - no special case, no extra code. The best feature is the one the structure gives you.
-
Four corners, written out
This could be a loop over corner offsets. It is four explicit checks instead, because when collision misbehaves I want to see exactly which corner and why, in the file, at a glance. Explicit over clever - the house rule, applied.
Client work · byjoio
Static first
byjoio is my freelance practice. Small businesses come to me with slow, template-built sites. They leave with hand-built static ones - same content, a fraction of the weight, nothing to maintain.
The pattern is the same every time: semantic HTML, mobile-first CSS on custom properties, vanilla JavaScript only where the page earns it. GitHub Pages for hosting, Formspree for forms, analytics in the client's own account. At handover the client owns every piece - if I disappear tomorrow, their site doesn't.
Drag the handle
A composite of real rebuilds - client details removed, the shape kept. Left is what arrives; right is what leaves.
The template build
The byjoio rebuild
and where they do it.
- Typical template build
- 2-4 MB · 40+ requests · builder runtime, jQuery, three tracking scripts
- Typical byjoio rebuild
- Under 100 KB · under 10 requests · zero frameworks, zero build step
Decision: why static, when everyone sells a CMS
Most small-business sites are brochures, and brochures don't need servers. Static means nothing to patch, nothing to breach, hosting that costs nothing, and pages fast by construction rather than by optimisation. When a client genuinely needs to edit content weekly, that changes the answer - the point is to ask, not to assume.
Client names and links live with the clients, not on my portfolio. Ask me and I'll walk you through specific builds.
Client work · pattern
Forms without a backend
Every byjoio site needs a contact form. None of them need a server. This is the pattern that ships on all of them: native validation first, a honeypot for spam, Formspree for delivery, and a fallback that still works when JavaScript doesn't.
Try it
Live demo - nothing is sent anywhere.
Sent. Or it would be - this is the demo. On a real byjoio site this message replaces the form and the enquiry lands in the client's inbox via their own Formspree account.
There is a fourth field on this form that you cannot see. Spam bots fill it in; humans never do. That is the whole spam filter.
The code that ships
The actual submission handler from the byjoio pattern, step by step.
const form = document.querySelector('.contact-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();
if (form.website.value !== '') {
return;
}
if (!form.reportValidity()) {
return;
}
const button = form.querySelector('[type=submit]');
button.disabled = true;
try {
const response = await fetch(form.action, {
method: 'POST',
body: new FormData(form),
headers: { Accept: 'application/json' },
});
if (!response.ok) {
throw new Error(String(response.status));
}
form.hidden = true;
document.querySelector('.form-sent').hidden = false;
} catch {
form.submit();
}
});
-
The honeypot
The hidden "website" field. Bots auto-fill every input; humans can't see this one. If it has a value, drop the submission silently - no captcha, no friction for real visitors, and in practice it stops nearly all form spam on small sites.
-
Let the browser validate
requiredandtype="email"in the markup already know the rules.reportValidity()shows the browser's own messages, in the visitor's own language, with correct focus handling. Reimplementing that in JavaScript is work I'd have to test and maintain for a worse result. -
Disable before sending
A slow connection plus an impatient thumb means double submissions - and a client asking why enquiries arrive twice. Disabling the button before the request closes the gap.
-
Fetch, with a real fallback
Success swaps the form for a confirmation without leaving the page. But the catch block is the important line: if fetch fails for any reason,
form.submit()falls back to a plain HTML post to Formspree's hosted page. The form works with JavaScript broken, blocked, or absent - the enhancement is optional, the function isn't.
Decision: why not just build a backend? I'm a backend developer.
Because the boring solution wins. A mail server I run is a mail server the client depends on me for, forever. Formspree in the client's own account costs them nothing at their volume, survives me, and turns a server-shaped problem into a paragraph of JavaScript. Knowing how to build it is exactly what lets me decide not to.
Deep dive · automation
The same process, twice
By day I automate business processes in Blue Prism at Traverse Automation. I'm moving toward building services in Java. The clearest way I can show you the difference is to solve one problem both ways.
The problem: 200 supplier invoices arrive by email every day. Each needs validating, coding, and entering into a finance system. Some days it's 12. Some days it's 900.
-
1 · The interface
Blue Prism
The bot drives the finance system's own screens - the same buttons and fields a human uses. No API required, and that is RPA's superpower: it automates systems nobody can change. Most enterprise software is exactly that.
Java service
The service needs a real seam: an API, a database, a file drop. If the finance system offers none, Java cannot start - which is why this problem landed on my desk as an RPA developer in the first place.
-
2 · Where the logic lives
Blue Prism
Process diagrams and object actions inside a proprietary tool. Readable to trained eyes, but diffing two versions of a process means eyeballing flowcharts. Review culture has to fight the tooling.
Java service
Plain text. Diffable, reviewable line by line, testable in isolation, refactorable with confidence. The entire ecosystem of software quality practice - version control, code review, CI - applies with no translation.
-
3 · When it breaks
Blue Prism
The vendor redesigns one screen and selectors break at 3am. You find out from the morning queue report. The mitigations are real engineering: work queues, retries, exception screenshots, alerting - built so failure is contained, not prevented.
Java service
Failures are exceptions you designed for, at boundaries you chose. The compiler removes a whole class of them before deploy; tests remove another. What remains fails loudly, in logs you structured, at the moment it happens.
-
4 · Change over time
Blue Prism
Fast to build - weeks, not quarters - and the business feels that speed. The cost moves to maintenance: every upstream UI change is your emergency. The bot is coupled to the one thing you don't control.
Java service
Slower to first value, because the cost is front-loaded into design. But coupling is to contracts, not screens. When the vendor redesigns their UI, nothing happens. The service ages like infrastructure, not like a workaround.
-
5 · The honest answer
Blue Prism wins when
The interface is human-only, the timeline is weeks, and the process might not exist in two years. That describes a huge amount of real business - RPA is the right call far more often than backend developers like to admit.
Java wins when
You own the systems, the volume matters, and the process must survive years of change. I want to spend my career on this kind of problem. The first kind is paying for the degree.
What the day job actually taught me
Production RPA is distributed-systems practice wearing a business-process costume. Idempotent steps, because bots get restarted mid-run. Work queues with retry limits and poison-item handling. Audit trails, because finance asks. Defensive waits at every boundary you don't control. None of that knowledge is Blue Prism knowledge - it moves with me to Java intact.
Skills
Tools
The levels are honest. Daily means I work with it every working day. Working means I ship with it. Building means I'm deliberately investing. Open a tool to see where it's used on this map.
-
Enterprise RPA at Traverse Automation: process design, object layer, work queues, exception handling, production support.
-
The direction of travel. Mexveng is the practice ground; the Open University degree is the theory under it; nearly a decade of on-and-off use since Minecraft modding is the foundation.
-
Semantic markup, mobile-first layouts on custom properties, BEM-ish naming. Every byjoio build - and this site.
-
Vanilla by default - every interactive element on this site is hand-built, no framework, no build step. View source; that's the point.
-
Rendering, input and the game loop for Mexveng. Chosen precisely because it does little enough that the architecture stays mine.
-
Functional components, TypeScript where the project already uses it. Reached for when a byjoio project genuinely needs it - which is rarer than the industry suggests.
-
Version control for everything, GitHub Pages for client hosting, Actions where a build step earns its place.
-
The no-backend toolkit for client sites - always set up in the client's own accounts, so handover is real.
Not listed: things I've only read about. If it's here, I've built with it.
Background
The long way to Java
Careers read cleaner backwards. This page starts at now and runs downhill into the past - scroll down to go back in time.
-
Now
Direction: Java backend engineering
Not a whim - a convergence. The day job taught me how business systems fail. The degree is putting theory under the practice. Mexveng is where the language gets exercised until it's second nature. The rest of this site is the evidence.
-
Ongoing
BSc Computing & IT, Open University
Part-time, alongside full-time work. Slower than the standard route and better for it: everything lands on problems I've already met in production, so the theory sticks.
-
Ongoing
byjoio - freelance web development
Real clients, real deadlines, real handovers. Freelancing is where I learned that shipping is a skill separate from building - scoping honestly, saying no to features, leaving a client independent rather than dependent.
-
Day job
Traverse Automation - RPA developer
Blue Prism in production: work queues, retries, audit trails, incidents at inconvenient hours. The job that taught me how businesses actually run - and exactly where the limits of automating-from-the-outside sit.
-
2016-2017
Minecraft modding - first Java
I wanted the game to do something it didn't, and the only path was code. First classes, first NullPointerException, first time changing a system from the inside. A decade later the tools are better and the reason hasn't changed.
That's the bottom. The only way from here is forward - back to now.
Current
Now
Three tracks, running at once, on purpose.
- Days
- RPA developer at Traverse Automation - Blue Prism automation in production, from design through support.
- Nights
- BSc Computing & IT at the Open University, part-time. Currently the long, worthwhile way to do a degree.
- Between
- byjoio client builds, and Mexveng - the Java RPG that keeps the language sharp while the career catches up to it.
Where this goes
A Java backend role, with people who review code properly. I bring production automation experience, freelance delivery discipline, and a codebase that proves I can sustain a system over time - not just start one.
Contact
No form, no funnel.
Email me and you get me.
- Hiring for Java - start at the thinking.
- Need a site built - start at static first.
Code lives at github.com/byjoio-dev, including this site.