Added rss for blog.

This commit is contained in:
Warwick 2024-05-10 16:16:14 +01:00
commit 27400f5b36
56 changed files with 971 additions and 0 deletions

8
.babelrc Executable file
View file

@ -0,0 +1,8 @@
{
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "h",
"pragmaFrag": "Fragment",
}]
]
}

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.hugo_build.lock
/public/
/resources/

8
archetypes/default.md Normal file
View file

@ -0,0 +1,8 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
thumbnail: /img/fof.png
draft: true
tags: ["draft"]
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/thumbnails/ga.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

BIN
assets/thumbnails/monq.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

16
config.toml Normal file
View file

@ -0,0 +1,16 @@
baseURL = "https://warwicknew.co.uk"
languageCode = "en-us"
title = "Warwick New"
theme = "warwick_portfolio"
pluralizeListTitles = false
[Author]
name = "Warwick New"
email = "wytau@sdf.org"
[outputs]
home = ['html']
section = ['html', 'rss']
taxonomy = ['html']
term = ['html']

View file

@ -0,0 +1,65 @@
---
title: "Graphics: Nothing to PBR"
date: 2023-11-07T15:17:49Z
thumbnail: /thumbnails/graphics.png
tags: ["c/c++", "opengl", "glsl","cmake", "3d maths","games"]
---
I am someone who is fascinated by graphics programming, the creation of game engines and all things low-level. Here I've taken the time to create a proper graphics pipeline in order to create a PBR rendering system. I'll likely reuse the shaders and model loading classes in future projects but for my next personal graphics project I'm tempted to pick up some Vulkan and make greater use of namespaces and more modern general C++ programming paradigms to make something more robust to build on top of.
{{< video "/projects/videos/pbr-norm.mp4" >}}
## What steps did I take.
I'm writing what I did up a little while after the fact, but he major steps I took were:
- Setting up CMake/SDL/Opengl Boilerplate.
- Implementing Camera Movement
- Loading in models and textures
- Implementing PBR (Physically Based Rendering)
- Implementing Normal Maps.
Much of what I implemented here was made possible by [LearnOpenGL.com](https://learnopengl.com/) and [3Blue1Brown's series on Linear Algebra](https://www.3blue1brown.com/topics/linear-algebra), as well as my time as an undergrad at falmouth.
### Setting up SDL/Opengl Boilerplate.
So back in the second year of my undergrad in computing for games I had worked with SDL and OpenGL to render some terrain in C++. The only problem being is that in my time since then I've come to hate my reliance on Visual Studio and undergrad levels of programming style at the time.
This pushed me to finally get some C++ build system knowledge and go through the initial stages of [LearnOpenGL](https://learnopengl.com/)'s tutorial using the libraries I preferred. At the time I wanted to keep to one library ecosystem and using SDL-image with SDL made more sense than using a separate header library stb_image with glfw3. Before long I had a simple textured square.
![Textured square](/posts/graphics-nothing-to-pbr/gl-boilerplate.png)
## Implementing Camera Movement
Following on from rendering a textured square I implemented an MVP stack. While I was at it I created objects to contain data to be rendered that also stored transforms. In this project practically all object transformations are stored as Matrices. I understand that in the long term this isn't ideal but it's good enough for a simple renderer.
{{< video "/posts/graphics-nothing-to-pbr/camera-movement.webm" >}}
## Loading in models and textures
With the ability to look around objects I moved on to using [Assimp](https://www.assimp.org/) to load in models using [LearnOpenGL](https://learnopengl.com/)'s tutorial. Loading in Textures with the [SDL2-image](https://www.libsdl.org/projects/old/SDL_image/) library.
I ran into some weird issues along the way when it came to getting the image textures to work correctly, but I figured it out. I believe the textures initially weren't loaded into memory, then it was being loaded in upside down, before like Goldilocks, I got it just right.
![Broken texture loading](/posts/graphics-nothing-to-pbr/loading-models.png)
I did go as far as implementing some simple diffuse lighting before deciding to just flat out and jump to PBR. And that gave some pretty good results. In hind sight I should have switch to working on other aspects of the project like giving it some a purpose other than rendering models. As this may have helped it keep my interest in the longer term.
![Diffuse Lighting of model](/posts/graphics-nothing-to-pbr/diffuse-lighting.png)
## Implementing PBR (Physically Based Rendering)
I then went through the steps to implement PBR from [LearnOpenGL](https://learnopengl.com/)'s articles. I didn't get at far as using textures for IBL or diffuse irradience, really I just wanted to focus on getting the lighting in. And I did it by implementing metalness, roughness, and AO in order. Other combinations of PBR layers exist but this was the one I chose.
![Stages of PBR implementation](/posts/graphics-nothing-to-pbr/pbr.jpg)
I was also interested in texture packing so although it wasn't strictly necessary I got it rendering after packing each layer into the RGB values of a single texture (RMA aka. Roughness, Metallness, AO). This combined with some blender fu, allowed me to load in a single texture instead of three for PBR:
![PBR texture packed into RMA](/posts/graphics-nothing-to-pbr/rma.jpg)
This gave me this result:
{{< video "/posts/graphics-nothing-to-pbr/pbr.mp4" >}}
## Implementing Normal Maps.
The last step I took was to add normal maps as I felt that PBR alone was pretty flat. But I felt that so far I was following [LearnOpenGL](https://learnopengl.com/)'s articles too closely and not necessarily gaining a strong enough understanding of what was going on in the technique.
To counter this, I decided to calculate the tangent space of the normals at run time inside the GPU using the Geometry shader step, rather than caching tangents in another buffer like in [LearnOpenGL](https://learnopengl.com/)'s implementation. Doing while and referring to resources like [3Blue1Brown's series on Linear Algebra](https://www.3blue1brown.com/topics/linear-algebra), Gave me a much needed deeper under standing of linear algebra and how transforms actually work.
This gave me the last update of this project:
{{< video "/projects/videos/pbr-norm.mp4" >}}

View file

@ -0,0 +1,8 @@
---
title: "Playing With C and Sockets"
date: 2023-11-07T15:19:57Z
thumbnail: /thumbnails/c-socks.png
draft: true
tags: ["c/c++", "web-development", "Sockets"]
---

6
content/greeter.md Normal file
View file

@ -0,0 +1,6 @@
---
title: "Greeter"
date: 2023-10-15T21:48:35+01:00
---
# Warwick
Graphics, Games, Web, Education

45
content/projects/monq.md Normal file
View file

@ -0,0 +1,45 @@
---
title: "Monq"
date: 2023-10-25T14:44:18+01:00
thumbnail: /thumbnails/monq.jpg
tags: ["unreal","c/c++","games"]
---
Monq is my most complete game project. I made it in my second year of
university with some friends, and we were going to use it to form a successful
startup. I learned a lot about how a multidisciplinary team works and tinkered
with creating frameworks in C++ with inheritance both to blueprints and further
C++ sub-classes, covering concepts such as all the AI using unreal's tools,
puzzle implementation, shader implementation using noise and more. Most of the
mechanics for which I was responsible, used a variety of vector and positional
mathematics to implement.
## Trailer
{{< youtube fRSD64D0LUw >}}
## Team
**Programming:** Warwick New, James Hellman
**Designers:** James Hellman, Nicholas Stankowski
**Art:** Harri Slee, Robert Adolfson
**Music:** Jason Read
**Writing:** Michael Wheatley
**Animation:** George Evans, Ross Everson
## Main Contributions
### Tiger AI
Here I created an AI that guards an arena. The puzzle part of this boss was based on trying to get the ai to get a chain stuck on pillars left around the arena reducing the range it could navigate. I did this by calculating the distance between the previous attachment point and the next and reducing the available navigatable circumference of the tiger appropriately. Since this was my first more complicated AI, I now know that It would have been far easier to restrict the AI's movement through the use of a more complex steering system rather than calculating where the actor should target moving towards.
![Tiger AI](/projects/monq/TigerAI.png)
![Tiger Diagram](/projects/monq/TigerDiagram.png)
### Mirror Reflections
Here is an example of me simulating reflections in monq to create a light bounce puzzle. Each mirror triggers the next to recursively make light reflection beams. Here I had to work out angles of reflection before creating a new cast to attach a beam particle.
I also worked on the sand texture in this image mixing various forms of noise to create the ripples based on changes in topography.
![Mirror Reflections](/projects/monq/MirrorReflection.png)

View file

@ -0,0 +1,16 @@
---
title: "Ramble"
date: 2023-11-07T14:46:17Z
thumbnail: /thumbnails/ramble.png
tags: ["javascript","react","nodejs","docker","dynamodb","janus","web-development"]
---
Ramble was a web project I created during my master's degree to create a startup. In this project, I was the CTO and built a website that allowed users to stream their podcasts live and accept call-ins in a similar vein to talk shows! I learnt the entire JavaScript web development stack from React to audio streaming to DevOps in order to make it a reality.
It also had chatroom functionality with the ability to re-stream to audiences much like other apps that came out in the time since, such as Clubhouse.
During the project's lifespan of just under two years, I mostly worked on creating the streaming functionality of the project and managing how the project was designed to function behind the hood when it was deployed. I learned a ton about how web deployment works during this time allowing me to work on web development modules in the Games Academy at Falmouth University today.
Here's a demo of the project I took before we moved on.
{{< video "/projects/ramble/ramble.mp4" >}}

View file

@ -0,0 +1,18 @@
---
title: "University Graphics Project"
date: 2023-10-25T11:56:20+01:00
thumbnail: /thumbnails/uni-graphics.png
tags: ["c/c++", "opengl", "glsl","cmake", "3d maths","games"]
---
{{< video "/projects/videos/uni-graphics.mp4" >}}
I made this project for a module at uni. It's a terrain map based on perlin
noise with flat face lighting, It was the first project where I picked up a lot
of the 3D maths used in games and learned about simulation. It was my first
project using GLSL with C++ and also the project I optimised for an
optimisation module in my final year. Getting deep into learning more about
memory management and Object-Oriented design.
#### Build
- [Win64 Build](/builds/UniGraphics-Win64.zip)

View file

@ -0,0 +1,15 @@
---
title: "An Exploratory Analysis of Student Experiences With Peer Evaluation in Group Game Development Projects"
date: 2023-11-07T15:23:05Z
thumbnail: /thumbnails/ga.jpg
tags: ["academia", "teaching", "student experience"]
---
Collaborative projects are commonplace in computing education. They typically enable students to gain experience building software in teams, equipping them with the teamwork skills they need to be competitive in the labour market. However, students often need encouragement to reflect upon and synthesise their experience to attain the most learning. Peer evaluation offers one such approach, but the conditions which facilitate effective peer evaluation have not yet been established. This paper seeks to provide insight into student experiences with peer evaluation. It builds upon prior qualitative work, analysing quantitative data collected through a questionnaire taken by undergraduate students on a collaborate digital game development module. An exploratory factor analysis identifies seven dimensions of variance in the student experience: perceived impact; arbitrary influence; inconsistency; team cohesiveness; assessment pressure; ease and professionalism. Correlation analysis suggests some factors such as arbitrary influence, team cohesion, assessment pressure, and professionalism are associated with attained learning, whilst factors such as inconsistency and onerousness are not. This informs the development of a conceptual framework, suggesting focuses which facilitate effective peer evaluation. Expanding this conceptual framework and validating it across different demographics, contexts, and project types are suggested as avenues for further investigation.
## Authors
- [Alexander Mitchell](https://dl.acm.org/profile/99659739515)
- [Michael Scott](https://dl.acm.org/profile/81555254356)
- [Joseph Walton-Rivers](https://dl.acm.org/profile/99659883826)
- [Matt Watkins](https://dl.acm.org/profile/81544299456)
- [Warwick New](https://dl.acm.org/profile/99659883587)
- [Douglas Brown](https://dl.acm.org/profile/99659333535)

View file

@ -0,0 +1,16 @@
---
title: "Student Perspectives on the Purpose of Peer Evaluation During Group Game Development Projects"
date: 2023-11-07T15:24:03Z
thumbnail: /thumbnails/ga.jpg
tags: ["academia", "teaching", "student experience"]
---
Being able to work well in a team is valued in industry and beyond. As such, many university educators strive to help their students to collaborate effectively. However, it is typically the case that more than ad-hoc experience is needed to master teamwork. Often, students need to become reflective practitioners who learn from their experiences and enact change. Self and peer evaluation can help evoke such reflection. However, the facilitating conditions for effective learning from peer evaluation during group projects in computing are not yet well-defined. This research is an initial step in identifying these conditions. In this study, students engaged in a long-term multidisciplinary software engineering project in which they produced a digital game. They completed regular exercises in which they reflected upon and wrote about their contributions to the project as well as those of their peers. Thematic analysis of 200 responses to an open-ended question about the purpose of these exercises illustrated student perspectives: giving and receiving feedback; prompting personal reflection and improvement; supporting supervision; aiding marking; informing project planning and management; exploring and reshaping group dynamics; improving project outputs; providing a system to hold group members accountable; and giving a sense of safety to raise issues without repercussion. Giving consideration to these differing perceptions will help educators to address student concerns about group projects, notably standardisation, workload efficiency, and fairness, and will lay the foundations for a model of peer evaluation which improves teamwork.
## Authors
- [Alexander Mitchell](https://dl.acm.org/profile/99659739515)
- [Terry Greer](https://dl.acm.org/profile/99659884092)
- [Warwick New](https://dl.acm.org/profile/99659883587)
- [Joseph Walton-Rivers](https://dl.acm.org/profile/99659883826)
- [Matt Watkins](https://dl.acm.org/profile/81544299456)
- [Douglas Brown](https://dl.acm.org/profile/99659333535)
- [Michael Scott](https://dl.acm.org/profile/81555254356)

Binary file not shown.

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2023 Warwick New
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,2 @@
+++
+++

View file

@ -0,0 +1,116 @@
@keyframes slideInLeft {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
#greeter {
display: flex;
justify-content: space-around;
align-content: space-around;
flex-wrap: wrap;
align-items: stretch;
height: 100vh;
width: 100%;
position: relative;
animation: 1s ease-out 0s 1 slideInLeft;
}
#greeter-sim {
flex-grow: 2;
}
#greeter-sim * {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
#greeter-content {
padding: 2%;
margin: 0;
flex-grow: 2;
}
@media (max-width: 950px){
#greeter-content {
margin: 5% 5% 5% 5%;
}
}
#greeter-content li {
font-size: 133%;
}
/* CSS scroll button */
.scroll-down-dude {margin: 12px 0px 0px 24px;}
.scroll-down-dude:before,
.scroll-down-dude:after {
content: "";
display: block;
width: 12px;
height: 12px;
transform: rotate(45deg);
border-bottom: 4px solid white;
border-right: 4px solid white;
}
.scroll-down-dude:before {
-webkit-animation: down-arrow-before 2.6s cubic-bezier(0.77, 0, 0.175, 1) infinite;
animation: down-arrow-before 2.6s cubic-bezier(0.77, 0, 0.175, 1) infinite;
}
.scroll-down-dude:after {
-webkit-animation: down-arrow-after 2.6s cubic-bezier(0.77, 0, 0.175, 1) infinite;
animation: down-arrow-after 2.6s cubic-bezier(0.77, 0, 0.175, 1) infinite;
}
@-webkit-keyframes down-arrow-before {
50% {
transform: rotate(45deg) translate(70%, 70%);
}
100% {
transform: rotate(45deg) translate(70%, 70%);
}
}
@keyframes down-arrow-before {
50% {
transform: rotate(45deg) translate(70%, 70%);
}
100% {
transform: rotate(45deg) translate(70%, 70%);
}
}
@-webkit-keyframes down-arrow-after {
50% {
transform: rotate(45deg) translate(110%, 110%);
opacity: 0;
}
51% {
transform: rotate(45deg) translate(-130%, -130%);
}
100% {
transform: rotate(45deg) translate(-70%, -70%);
opacity: 1;
}
}
@keyframes down-arrow-after {
50% {
transform: rotate(45deg) translate(110%, 110%);
opacity: 0;
}
51% {
transform: rotate(45deg) translate(-130%, -130%);
}
100% {
transform: rotate(45deg) translate(-70%, -70%);
opacity: 1;
}
}

View file

@ -0,0 +1,116 @@
/* Font stuff */
@import url('https://fonts.googleapis.com/css?family=Abel:700|Abel:400');
body {
font-family: 'Abel';
font-weight: 400;
}
h1, h2, h3, h4, h5 {
font-family: 'Abel';
font-weight: 700;
}
html {font-size: 100%;} /* 16px */
h1 {font-size: 4.210rem; /* 67.36px */}
h2 {font-size: 3.158rem; /* 50.56px */}
h3 {font-size: 2.369rem; /* 37.92px */}
h4 {font-size: 1.777rem; /* 28.48px */}
h5 {font-size: 1.333rem; /* 21.28px */}
small {font-size: 0.750rem; /* 12px */}
:root {
--text: #b4bfc0;
--background: #010202;
--primary: #e3eff2;
--secondary: #00bcd1;
--accent: #8c240d;
--paper: #050606;
}
/* Custom CSS */
body {
color-scheme: dark;
background-color: var(--background);
accent-color: var(--accent);
caret-color: var(--text);
color: var(--text);
padding: 0;
margin: 0;
}
a:link, a:active{
color: var(--primary);
}
a:visited {
color: var(--accent);
}
a:hover {
color: var(--secondary);
}
.header {
background-color: var(--paper);
padding: 1rem;
}
.homepage-header {
background-color: var(--paper);
padding: 2rem;
}
footer {
bottom: 0;
left: 0;
right: 0;
padding: .5rem;
background: var(--paper);
color: var(--text);
font-weight: var(--text);
display: flex;
justify-content: center;
align-items: center;
gap: 0.2rem;
}
.flex-wrap-container {
display: flex;
align-items: flex-start;
flex-direction: row;
flex-wrap: wrap;
}
.container {
max-width: 1000px;
min-width: 800px;
padding: 10px;
background-color: var(--paper);
margin: 10px auto;
}
.flex-wrap-container .container {
max-width: 800px;
}
.summary {
z-index: 1;
max-width: 500px;
}
#article-content img {
max-width: 100%;
max-height: 50vh;
height: auto;
display: block;
margin-left: auto;
margin-right: auto;
}
div.summary__img_container {
position:relative; top:0; left:0; width:600px; height:250px;
z-index: 0;
}
img.summary__img {
position:absolute; top:0; right:0; width:600px; height:100%;
-webkit-mask-image:-webkit-gradient(linear, right top, left top, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
mask-image: linear-gradient(to left, rgba(0,0,0,1), rgba(0,0,0,0));
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,100 @@
// create background element
let canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.style.cssText = `
background: #00000000;
position:fixed;
left:0;
top:0;
z-index:-99999;
`
// set it's size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let context = canvas.getContext('2d');
// this will be populated and used later
drawableObjectList = [];
class Splash {
constructor(distance, x, y) {
this.distance = distance;
this.x = x;
this.y = y;
this.time = 0;
}
draw() {
context.fillStyle = "#00000000";
context.strokeStyle = `rgba(140, 36, 13, ${this.distance + 0.1})`;
let splashSize = this.distance * (this.time/100);
context.beginPath();
context.ellipse(this.x, this.y, 100 * splashSize , 50 * splashSize, 0, 0, Math.PI * 2);
context.fill();
context.stroke();
if (this.time > 100) {
drawableObjectList = drawableObjectList.filter((item) => {return item !== this});
}
this.time += 1;
}
}
// this is the object that'll look cool
class Drop {
constructor() {
this.x = Math.random() * window.innerWidth;
this.y = Math.random() * window.innerHeight;
this.distance = Math.random();
}
draw() {
context.fillStyle = `rgba(140, 36, 13, ${this.distance + 0.1})`;
context.strokeStyle = `rgba(140, 36, 13, ${this.distance + 0.1})`;
// draw point
context.beginPath();
context.moveTo(this.x,this.y);
context.lineTo(this.x,this.y-this.distance*100);
context.stroke();
// move point
this.y += (this.distance + 0.3) * 4;
// keep point in bounds
if (this.y > window.innerHeight - (1 - this.distance) * 300) {
// Add splash
drawableObjectList.push(new Splash(this.distance, this.x, this.y))
this.y = 0
this.x = Math.random() * window.innerWidth;
this.distance = Math.random();
}
}
}
// populate element array
for (let i = 0; i < 50; i++) {
drawableObjectList.push(new Drop());
}
function loop() {
// Loop and clear frame
requestAnimationFrame(loop);
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
// Draw objects.
drawableObjectList.forEach((point) => {
point.draw();
});
// Handle page size change
if (canvas.width != window.innerWidth) {
canvas.width = window.innerWidth;
}
if (canvas.height != window.innerHeight) {
canvas.height = window.innerHeight;
}
}
loop();

View file

@ -0,0 +1,117 @@
// thanks to https://stackoverflow.com/a/74129799
const { cos, sin, sqrt, acos, atan, atan2, abs, PI } = Math
const clamp = (a, b, x) => x < a ? a : x > b ? b : x
const cvs = document.createElement('canvas')
cvs.style.cssText = ` background: #00000000; `
const primaryCol = getComputedStyle(document.body).getPropertyValue('--secondary');
const secondCol = getComputedStyle(document.body).getPropertyValue('--accent');
const ctx = cvs.getContext('2d')
const RADIUS = 150
const NB_SECTIONS = 6
const LINE_WIDTH = 3
const SCALE = devicePixelRatio
const width = RADIUS * 2 + 20
const height = RADIUS * 2 + 20
cvs.width = width * SCALE
cvs.height = height * SCALE
cvs.style.width = `${width}px`
cvs.style.height = `${height}px`
document.getElementById("greeter-sim").appendChild(cvs)
const vec = (x = 0, y = 0, z = 0) => ({ x, y, z })
vec.set = (o, x = 0, y = 0, z = 0) => {
o.x = x
o.y = y
o.z = z
return o
}
const X = vec(1, 0, 0)
const Y = vec(0, 1, 0)
const Z = vec(0, 0, 1)
// orientation of camera
let theta, phi
// project v to the camera, output to o
function project(o, { x, y, z }) {
let ct = cos(theta), st = sin(theta)
let cp = cos(phi), sp = sin(phi)
let a = x * ct + y * st
return vec.set(o, y * ct - x * st, cp * z - sp * a, cp * a + sp * z)
}
// draw camera-facing section of sphere with normal v and offset o (-1 < o < 1)
const _p = vec()
function draw_section(n, o = 0) {
let { x, y, z } = project(_p, n) // project normal on camera
let a = atan2(y, x) // angle of projected normal -> angle of ellipse
let ry = sqrt(1 - o * o) // radius of section -> y-radius of ellipse
let rx = ry * abs(z) // x-radius of ellipse
let W = sqrt(x * x + y * y)
let sa = acos(clamp(-1, 1, o * (1 / W - W) / rx)) // ellipse start angle
let sb = z > 0 ? 2 * PI - sa : - sa // ellipse end angle
ctx.beginPath()
ctx.ellipse(x * o * RADIUS, y * o * RADIUS, rx * RADIUS, ry * RADIUS, a, sa, sb, z <= 0)
ctx.stroke()
}
const _n = vec()
function draw_arcs() {
for (let i = NB_SECTIONS; i--;) {
let a = i / NB_SECTIONS * Math.PI
draw_section(vec.set(_n, cos(a), sin(a)))
}
for (let i = NB_SECTIONS - 1; i--;) {
let a = (i + 1) / NB_SECTIONS * Math.PI
draw_section(Z, cos(a))
//draw_section(X, cos(a))
//draw_section(Y, cos(a))
}
}
ctx.lineCap = 'round'
ctx.scale(SCALE, SCALE)
function render() {
requestAnimationFrame(render)
theta = performance.now() / 24000 * PI
phi = cos(performance.now() / 12000 * PI)
// 1. change the basis of the canvas
ctx.save()
ctx.clearRect(0, 0, width, height)
ctx.translate(width >> 1, height >> 1)
ctx.scale(1, -1)
// 2. draw back arcs
ctx.lineWidth = LINE_WIDTH / 2
ctx.strokeStyle = secondCol
ctx.scale(-1, -1) // the trick is to flip the canvas
draw_arcs()
ctx.scale(-1, -1)
// 3. draw sphere border
ctx.strokeStyle = primaryCol
ctx.lineWidth = LINE_WIDTH + 2
ctx.beginPath()
ctx.arc(0, 0, RADIUS, 0, 2 * Math.PI)
ctx.stroke()
// 4. draw front arcs
ctx.lineWidth = LINE_WIDTH
ctx.strokeStyle = primaryCol
draw_arcs()
ctx.restore()
}
requestAnimationFrame(render)

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{ if ne .IsHome true }}
{{- partial "header.html" . -}}
{{ end }}
<div id="content">
{{- block "main" . }}{{- end }}
</div>
{{- partial "footer.html" . -}}
</body>
</html>

View file

@ -0,0 +1,11 @@
{{ define "main" -}}
<div class="container">
<h1> {{ .Title | title }} </h1>
{{ .Content }}
</div>
{{range .Pages }}
<div class="container">
{{ .Render "summary" }}
</div>
{{- end }}
{{- end }}

View file

@ -0,0 +1,39 @@
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if ne .Title .Site.Title }}{{ .Site.Title }}&apos;s {{.Title}}{{ else }}{{ .Site.Title }}{{ end }}</title>
<link>{{ .Permalink }}</link>
<description>{{ if ne .Title .Site.Title }}{{ .Site.Title }}&apos;s {{.Title}}{{ else }}{{ .Site.Title }}{{ end }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{ end }}
{{ range $pages }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>{{ .Content | html }}</description>
</item>
{{ end }}
</channel>
</rss>

View file

@ -0,0 +1,15 @@
{{define "main"}}
<div class="container">
<section id="single-article">
<article id="article-content">
<h1 style="margin-bottom: 1px"> {{.Title}} </h1>
{{- partial "taglist.html" . -}}
<time datetime="{{.Params.date.Format "2006-01-02T15:04:05"}}" class="index-article__date">
{{.Params.date.Format "2 January 2006"}}
</time>
<hr>
{{ .Content }}
</article>
</section>
</div>
{{end}}

View file

@ -0,0 +1,36 @@
<div class="item">
<div style="justify-content: space-between; flex-wrap:nowrap" class="flex-wrap-container">
<div class="summary">
<a class="summary__link" href="{{ .Permalink }}">
{{ if gt (len .Title) 40}}
<h4 style="margin: 0">{{slicestr .Title 0 40}}...</h4>
{{ else }}
<h4 style="margin: 0">{{ .Title }}</h4>
{{ end }}
{{- partial "taglist.html" . -}}
</a>
{{ if gt (len .Summary) 500 }}
<p>{{slicestr .Summary 0 500}}...</p>
{{ else }}
<p>{{.Summary}}</p>
{{ end }}
<span class="summary__date">
{{.Params.date.Format "2 January 2006"}}
</span>
</div>
{{ if .Params.thumbnail }}
{{- $image := resources.Get .Params.thumbnail -}}
{{ if $image }}
<div class="summary__img_container" style="align-self: center">
<a style="display: block" href="{{ .Permalink }}">
<img
class="summary__img"
src="{{ ($image.Fill "600x200 q100 Center").RelPermalink }}"
>
</a>
</div>
{{ end }}
{{ end }}
</div>
</div>

View file

@ -0,0 +1,59 @@
{{ define "main" }}
{{ partial "greeter.html" .}}
<header id="homepage-header" class="homepage-header">
<div class="flex-wrap-container" style="align-items:center">
{{ $logo := (resources.Get "/img/logo.png").Resize "100x100" }}
<a href="/">
<img style="padding-right: 1%" src="{{ $logo.RelPermalink }}" alt="logo">
</a>
<a style="text-decoration: none" href="/">
<h1 style="display:inline; color:var(--primary)">{{.Title}}</h1>
</a>
<span style="margin-left: auto;">
{{ range .Site.Sections.Reverse }}
<a href="{{ .Permalink }}"><h4 style="display: inline-block; padding-left:.375em;padding-right:.375em;">{{ .Title }}</h4></a>
{{ end }}
</span>
{{ $rss := (resources.Get "/img/rss.png").Resize "30x30" }}
<a type="application/rss+xml" href="/blog/index.xml" target="_blank">
<img style="padding-right: 1em" src="{{ $rss.RelPermalink }}" alt="rss icon">
</a>
</div>
</header>
<main>
<div class="flex-wrap-container">
<div class="container">
<h2>Projects</h2>
<hr>
{{- $pageLen := len (where .Site.RegularPages "Type" "projects") -}}
{{- range $i, $element := (where .Site.RegularPages "Type" "projects") }}
{{ .Render "summary" }}
{{- if lt $i (sub $pageLen 1) }} <hr> {{ end -}}
{{- end }}
</div>
<div class="container">
<h2>Blog</h2>
<hr>
{{- $pageLen := len (where .Site.RegularPages "Type" "blog") -}}
{{- range $i, $element := (where .Site.RegularPages "Type" "blog") }}
{{ .Render "summary" }}
{{- if lt $i (sub $pageLen 1) }} <hr> {{ end -}}
{{- end }}
</div>
<div class="container">
<h2>Research Papers</h2>
<hr>
{{- $pageLen := len (where .Site.RegularPages "Type" "research papers") -}}
{{- range $i, $element := (where .Site.RegularPages "Type" "research papers") }}
{{ .Render "summary" }}
{{- if lt $i (sub $pageLen 1) }} <hr> {{ end -}}
{{- end }}
</div>
</div>
</main>
{{ end }}

View file

@ -0,0 +1,3 @@
<footer>
&#169; Warwick New. All rights reserved. 2020 - {{now.Year}}
</footer>

View file

@ -0,0 +1,20 @@
{{ with .Site.GetPage "/greeter" }}
{{$greeter_style := resources.Get "css/greeter.css"}}
{{$greeter_sim := resources.Get "js/greeter.js"}}
<link rel="stylesheet" type="" href="{{$greeter_style.RelPermalink}}">
<div id="greeter">
<div id="greeter-sim"></div>
<div id="greeter-content">
{{ .Content }}
</div>
<div style="text-align:center; width:100%">
</div>
<div>
<a style="text-align:center" onClick="document.getElementById('homepage-header').scrollIntoView({block: 'start', behavior: 'smooth'});" >
Scroll Down
</a>
<div class="scroll-down-dude" onClick="document.getElementById('homepage-header').scrollIntoView({block: 'start', behavior: 'smooth'});"></div>
</div>
</div>
<script src="{{$greeter_sim.RelPermalink}}"></script>
{{ end }}

View file

@ -0,0 +1,6 @@
<head>
{{$styles := resources.Get "css/main.css"}}
<link rel="stylesheet" type="" href="{{$styles.RelPermalink}}">
{{$background := resources.Get "js/background.js"}}
<script type="text/javascript" src="{{$background.RelPermalink}}" defer></script>
</head>

View file

@ -0,0 +1,37 @@
{{ $logo := (resources.Get "/img/logo.png").Resize "100x100" }}
{{ $rss := (resources.Get "/img/rss.png").Resize "30x30" }}
<header id="header" class="header">
<div class="flex-wrap-container" style="align-items:center">
<a href="/">
<img style="padding-right: 1em" src="{{ $logo.RelPermalink }}" alt="logo">
</a>
<div>
<a style="text-decoration: none" href="/">
<h1 style="display:inline; color:var(--primary)">{{.Site.Title}}</h1>
<nav aria-label="breadcrumb" >
{{ range $index, $value := .Ancestors.Reverse }}
{{ if (ne $index 0) }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
&#8594;
{{ end }}
{{ end }}
<a aria-current="page" href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
</nav>
</a>
</div>
<span style="margin-left: auto;">
{{ range .Site.Sections.Reverse }}
<a href="{{ .Permalink }}"><h4 style="display: inline-block; padding-left:.75em;padding-right:.75em;">{{ .Title }}</h4></a>
{{ end }}
</span>
{{ with .OutputFormats.Get "rss" -}}
{{ printf `<link rel=%q type=%q href=%q title=%q>` .Rel .MediaType.Type .Permalink site.Title | safeHTML }}
{{ end }}
<a type="application/rss+xml" href="/blog/index.xml" target="_blank">
<img style="padding-right: 1em" src="{{ $rss.RelPermalink }}" alt="rss icon">
</a>
</div>
</header>

View file

@ -0,0 +1,14 @@
{{- if isset .Page.Params "tags" -}}
{{- $tagsLen := len .Params.tags -}}
{{- if gt $tagsLen 0 -}}
<!-- Taglist shamelessly stolen from here: https://github.com/LukeSmithxyz/lugo/blob/master/layouts/partials/taglist.html -->
<div style="clear:both" class=taglist>
{{- with .Site.Params.relatedtext }}{{ . }}<br>{{ end -}}
{{- range $k, $v := .Params.tags -}}
{{- $url := printf "tags/%s" (. | urlize | lower) -}}
<a id="tag_{{ . | lower }}" href="{{ $url | absURL }}">{{ . | title }}</a>
{{- if lt $k (sub $tagsLen 1) }} &middot; {{ end -}}
{{- end -}}
</div>
{{- end -}}
{{- end }}

View file

@ -0,0 +1,4 @@
{{ $link := .Get 0 }}
<video width="100%" style="max-height:50vh" controls autoplay muted loop>
<source src="{{$link}}">
</video>

View file

@ -0,0 +1,19 @@
# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "Warwick_portfolio"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
description = "A them I've created to display content in my portfolio."
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.41.0"
[author]
name = "Warwick New"
homepage = "https://warwicknew.co.uk"
[taxonomies]
tag = "tags"
category = "categories"