Navbar

For my main navbar I decided to use a fixed position so that the options are always available to the user.

On the left I have added colour scheme choice buttons, these work by adding a class of light or dark to the html element, each class contains the css variables to effect the theme change. I have utilised local storage to save the prefered theme between site visits, also on the first visit the theme is selected based on the users prefered theme settings, defaulting to dark if they have no preference.

The scroll behavior of the Projects and Contact links is dependant on the users <Prefers Reduced Motion> flag, I have tried to respect the reduced motion flag with every animation, please let me know if you think I missed anything.

Hi! My name is Harry Legg

I am a Full Stack and Unity developer.

I want to provide value to your business, learning more each day so I can provide even more value tomorrow.

Hero Text

I created my Hero text using a caligraphy font which I vectorised and adapted to my liking. I made each letter its own path and setup an animation to rotate the hue, I started the animation staggered using a negative delay, each letter is 1.5s behind the preceeding one. By setting it to 15s for a complete cycle I think the effect is subtle enough not to warrant a <prefers reduced motion> opt out, but encourage you to contact me if you disagree.

Skills

  • HTML5
  • CSS3
  • Javascript
  • PHP
  • C#
  • C++
  • MySQL
  • JQuery
  • Unity
  • Image Editing
  • Blender
  • Laragon
  • Inkscape
  • React
  • Typescript
  • Vite
Two sheets of A4 on a wooden table, titled HARRY LEGG

Projects Section

I have used a grid to display my skills, I have used a grid-template-columns repeat(auto-fit,minmax(80px, 1fr)) to ensure this displays responsively. In fact I have not used an media queries to achieve the responsiveness of my website.

I decided to include React and Typescript but clarify that I am still in the process of learning them. I apply a blur filter to the img child of the comingsoon class, and use a pseudo after element to add the coming soon text which has a text-shadow to increase its legibility. I have also used a greyscale filter to dull down the comingsoon logos.

For my Resumé page I decided to recreate my resumé in html and make it look as though it is on two sheets of paper on a wooden desk. The animation I added was one of the most straight forward aspects of the entire site proportionally to its impact. I decided to add the phone, coffee stain and polaroids to enhance the 'desk' effect, notice that the time on the phone is correct (±1min) and if you move it around the wifi and mobile signal change. If you are viewing my resumé on a phone it will take up the entire screen width but you may catch a glimpse of a polaroid between the pages, hopefully encouraging you to view it as it was designed to be seen, on a desktop.

I wanted to implement a page transition when navigating to my resumé page, I have used SWUP to achieve this. Implementing SWUP lead me to refactor several aspects and was more effort than I feel it was worth but something I am glad to have done as I learned a lot in the process. It also lead me to preload the background (another AI generated seamless texture) to improve the user experience.

Projects

Personal Website

Image of this website

My tech stack for this site was Vanilla Javascript, CSS, and HTML, I used PHP for the backend.

I have not used any templates, I have tried to demonstrate an understanding of a range of techniques and effects. I recently added SWUP to my tech stack to include transitions between pages, I hope to build on these in the future.

Radical Book Review

Image of a New York Times Best Seller List App

This was an app I made for a job interview at Radical. The challenge was to create CRUD API which provided access to the New York Times Best Sellers lists and allowed the user to give the books ratings (or not) and enter them into a database stored locally.

As an optional extra I chose to create a front end to demonstrate the API as well but it was also possible to just run the API and test it with Swagger.

I used EntityFrameworkCore for the database interface and ASP.NET MVC framework for the frontend. Interactive elements were handled using jquery and styling was done with Bootstrap.

Airbnb Clone React App

Clone of airbnb experiences called watercnc

I am in the process of learning React, I am following the Scrimba 12hr React Course. Where as the course uses interactive screen casts I am following it on youtube and completing the course in typescript. I am using Vite build tools and NPM.

This app loads random images from picsum so will appear different each time you load the page. This is different from the course version of the project because their hero image was a single static image where as I have used CSS to recreate the original design. The data for the cards is stored in an array to mimic data coming from an api.

See it 'live'!

Unity Top-Down Scroller

Still from top down unity game

I haven't yet finished this game to a point I am satisfied to release it to the world.

It is a recreation of a DOS game from 1993 that I got on a cover disk all of those moons ago. The original game was create by Patrick Piche and I have tried to recreate the atmosphere of the original using a modern game engine. It was after I started the project that I happened to discover that Patrick Piche now works for Unity.

I have also created an animal grazing simulation which used a neural network for the animals to find food and avoid the edge of the map, this was trained using a genetic algorithm adjusting the weights randomly each generation. I found neural networks to be surprisingly straight forward but I am not interested in persuing AI per se.

Projects Section

The background for this section was created using a Stable Diffusion Plugin in Blender, this AI image generator can produce borderless textures which can be used for tiled backgrounds. I have then added a Linear gradient on top of the image so it is not so bright in dark mode and not so busy in light mode.

The top and bottom of this section are wavy, I achieved this by creating a wave profile SVG which I used to mask the background in a before and after pseudo element of the section element. I sized them so that there are 5 waves across the windows width.

For the cards I have made them clickable so that they transition to absolute positioned elements which migrate to the top of the current scroll location and the width increases to the smaller of the dynamic screen width or a given width. I actually clone the element and hide the original to avoid affecting the layout of the other elements. I wanted to demonstrate an understanding of how to achieve this but if I was doing this again I would utilise an existing library (such as animate.js) for animating elements.

Client Feedback

01720 423364 harry.legg86@googlemail.com
Contact Me


Contact section

I used the semantic address element for marking up my contact details, my phone number is a tel link and email address is a mailto link. Personally I prefer not to use mailto links so I also added a button to copy the email address to clipboard using the JS clipboard API, for feedback I toggle the visibility of the tick path on the clipboard icon svg.

The contact form sends its contents to a PHP script that uses the PHPMailer library to send the email. I added some CSS transitions to the labels which are positioned absolutely so they appear inside the input fields.

This section has a slanted background, I created this effect by adding an absolutely positioned after pseudo element to the section element, I gave it an inset of 0 so that it is the same size and position but then used a skewY transform to get the slanted effect.

Your Achievements

During your visit to my website you have earned these achievements.

Achievements Section

I created these trophies using DALL·E 2 for the original designs (except the mystery trophy which is 100% my own work), which I then vectorised using Inkscape and animated by adding relevant CSS directly to the code. The animation only plays if the user does not have the <prefers reduced motion> flag set. The Programmer trophy was the most complicated due to all of the keys, I was also unable to use a mesh gradient as these aren't yet supported by browsers so I came up with a work around of using 4 linear gradients.

Original trophy designs created using DALL·E 2

I setup various event listeners to monitor for the relevant event, scrolling was straight forward, Programmer and Networker both look for pointerDown on the respective links, it would be a breach of privacy to confirm that the user has visited the link. I specifically made it so that even right clicking is considered acceptable to gain the achievement (incase someone right clicks and selects open in new tab/window). The Recruiter achievement requires two actions: visiting my Resumé page and some sort of email interaction (using the copy email address button is enough). The Collector achievement is awarded for collecting the 5 preceeding achievements. Which includes the Gamer achievement which currently cannot be achieved as I haven't created a games page yet (check back soon for this). The Inspector achievement is awarded when the browsers inspection window is opened (for at least 2 seconds), I implemented this using Sindre Sorhus' code from GitHub. The final achievement remains a mystery, although anyone who inspects the code can easily achieve this if they work out how.

If you hover over each trophy the title text will tell you how many people have achieved this. I wrote a PHP script to store the count for each achievement in a file on the server, this is updated using AJAX when someone achieves a new trophy. I could have used a database but felt that would have been overkill.

I added a notification and feedback events when each achievement is awarded, I use fireworks.js and party.js, and randomly choose one of 3 effects for each achievement. Each time an achievement is awarded I reset the timer and update the notification to include the awards that are currently being celebrated, ensuring the last comma is replaced with an '&'. How many can you get at once?

View Achievements