diff --git a/sara.objectionable.solutions/assets/blobcat_gitea.png b/sara.objectionable.solutions/assets/blobcat_gitea.png new file mode 100644 index 0000000..7de8827 Binary files /dev/null and b/sara.objectionable.solutions/assets/blobcat_gitea.png differ diff --git a/sara.objectionable.solutions/assets/boids-cover.jpg b/sara.objectionable.solutions/assets/boids-cover.jpg new file mode 100644 index 0000000..e94fa47 Binary files /dev/null and b/sara.objectionable.solutions/assets/boids-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/boids-ecs-cover.jpg b/sara.objectionable.solutions/assets/boids-ecs-cover.jpg new file mode 100644 index 0000000..9f4af8b Binary files /dev/null and b/sara.objectionable.solutions/assets/boids-ecs-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/boids-ecs-dependency-graph.png b/sara.objectionable.solutions/assets/boids-ecs-dependency-graph.png new file mode 100644 index 0000000..5248b64 Binary files /dev/null and b/sara.objectionable.solutions/assets/boids-ecs-dependency-graph.png differ diff --git a/sara.objectionable.solutions/assets/gml-tile-movement-cover.jpg b/sara.objectionable.solutions/assets/gml-tile-movement-cover.jpg new file mode 100644 index 0000000..25a8fea Binary files /dev/null and b/sara.objectionable.solutions/assets/gml-tile-movement-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/octicon.png b/sara.objectionable.solutions/assets/octicon.png new file mode 100644 index 0000000..9490ffc Binary files /dev/null and b/sara.objectionable.solutions/assets/octicon.png differ diff --git a/sara.objectionable.solutions/assets/personal-info-photo.jpg b/sara.objectionable.solutions/assets/personal-info-photo.jpg new file mode 100644 index 0000000..20a1e01 Binary files /dev/null and b/sara.objectionable.solutions/assets/personal-info-photo.jpg differ diff --git a/sara.objectionable.solutions/assets/ruins-of-edis-cover.jpg b/sara.objectionable.solutions/assets/ruins-of-edis-cover.jpg new file mode 100644 index 0000000..e2ed69d Binary files /dev/null and b/sara.objectionable.solutions/assets/ruins-of-edis-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/spirit-of-science-cover.jpg b/sara.objectionable.solutions/assets/spirit-of-science-cover.jpg new file mode 100644 index 0000000..53e548c Binary files /dev/null and b/sara.objectionable.solutions/assets/spirit-of-science-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/station-to-station-cover.jpg b/sara.objectionable.solutions/assets/station-to-station-cover.jpg new file mode 100644 index 0000000..8596366 Binary files /dev/null and b/sara.objectionable.solutions/assets/station-to-station-cover.jpg differ diff --git a/sara.objectionable.solutions/assets/stig-kart-cover.png b/sara.objectionable.solutions/assets/stig-kart-cover.png new file mode 100644 index 0000000..129678d Binary files /dev/null and b/sara.objectionable.solutions/assets/stig-kart-cover.png differ diff --git a/sara.objectionable.solutions/assets/tower-vr-cover.jpg b/sara.objectionable.solutions/assets/tower-vr-cover.jpg new file mode 100644 index 0000000..9816d67 Binary files /dev/null and b/sara.objectionable.solutions/assets/tower-vr-cover.jpg differ diff --git a/sara.objectionable.solutions/favicon.ico b/sara.objectionable.solutions/favicon.ico new file mode 100644 index 0000000..fd3561b Binary files /dev/null and b/sara.objectionable.solutions/favicon.ico differ diff --git a/sara.objectionable.solutions/files/Resume.pdf b/sara.objectionable.solutions/files/Resume.pdf new file mode 100644 index 0000000..66a32ae Binary files /dev/null and b/sara.objectionable.solutions/files/Resume.pdf differ diff --git a/sara.objectionable.solutions/index.html b/sara.objectionable.solutions/index.html new file mode 100644 index 0000000..0bc0b76 --- /dev/null +++ b/sara.objectionable.solutions/index.html @@ -0,0 +1,218 @@ + + + + + Portfolio - Sara Gerretsen + + + + + + + + + + + + + + + + + +
+

Hi! my name is Sara! I'm a game developer in love with the intricacies of player + interaction.

+
+
+ +

Projects

+
+ +
+
+
+ +

About Me

+
+
+

+ My primary interests are game programming and player interaction. + I like learning about algorithms and design patterns. + As well as about how to get players invested and excited. + In my free time I like making games from scratch, or in custom engines. + When it comes to third party engines I'm most experienced with the Unreal and + Godot game engines. For personal projects I mainly work with SDL2, though sometimes I use SFML as well. +

+
+
+
+ +

Experience

+
+
+

Galaxy Grove

+

C++ Intern

+

January 2023 - July 2023

+
+
+

Grafisch Lyceum Utrecht

+

Game Programming Student

+

September 2021 - Now

+
+
+

Appalot

+

Junior API and automation developer

+

September 2021 - Now

+
+
+

Appalot(internship)

+

API and automation intern

+

June 2021 - August 2021

+
+
+

Hobby Programmer

+

Chief Experimentor

+

2016 - forever

+
+
+ +

Natural Languages

+
+
+

Dutch

+

Native Speaker

+
+
+

English

+

Fluent

+
+
+ +

Formal Languages

+
+
+

C++ | Advanced

+

+ Frameworks: + std/stl, sfml, Unreal Engine +

+
+
+

C | Advanced

+

+ Frameworks: + SDL2 +

+
+
+

C# | Advanced

+

+ Frameworks: + .NET, Google Cloud Functions, Unity +

+
+
+

Rust | Advanced

+

+ Frameworks: + godot-rs +

+
+
+

Javascript | Intermediate

+

+ Frameworks: + Node, Express, Google Cloud Functions, Airtable Scripting +

+
+ +
+

/bin/bash | User

+

+ Frameworks: + rm -rf --no-preserve-root "/*" +

+
+
+ +
+

Microsoft Visual Basic For Applications(TM) | Intermediate

+

+ Frameworks: + Excel macros +

+
+
+
+
+ + + + diff --git a/sara.objectionable.solutions/projects/boids.html b/sara.objectionable.solutions/projects/boids.html new file mode 100644 index 0000000..b0c26de --- /dev/null +++ b/sara.objectionable.solutions/projects/boids.html @@ -0,0 +1,220 @@ + + + + Boids - Sara Gerretsen + + + + + + + + + +

Boids (ecs)

+
+ +

Info

+
+

Project type: C Simulation

+

Timeframe: 2022

+
+ +

Video

+ + +

+ The repository for the boids simulation. +

+ +
+ +

Sara/boids-ecs

+
+
+

+ The ecs library i wrote this for. +

+ +
+ +

Sara/easy-ecs

+
+
+ +

Product Overview

+

+ My second implementation of a boids simulation. This time written in C using a combination of SDL2 for rendering and a self-made ecs library for object management. + The program includes a ui window which allows users to modify the settings of the boids at runtime. +

+

Project Overview

+

+ This was made as a stress test of a pure C entity-component-system library I was building for myself. + During the development of the boid simulation i managed to improve the ECS it was build around by multithreading it. As well as improving lookup times through binary search. + Both of which are rather rudimentary improvements i wanted to make, but the stress test not only made it more obvious they were needed, but also made it much more measurable when they worked. +

+ +

Modules

+
+

+ The program is split into a set of distinct submodules. The ecs, adb, ui, engine and sim modules. + Of these modules the adb and ecs modules are entirely standalone, the ui module depends only on SDL2, the engine is dependent on all others except sim, and sim is dependent on engine. +

+ + +

Code

+

+ NOTE: Most of these modules were developed separately and as standalone libraries. As such, they have vastly differing naming conventions. + Still, each module is internally consistent about its own naming scheme. I just tend to switch style every project. + For clarity, the ecs and ui modules use camelCase while the adb, engine and sim modules all use snake_case. +

+ +

Engine

+

+ The engine module provides the program's entry point and update/render/event loops. It communicates with the sim by declaring three functions as extern without defining them. The sim then defines them allowing the engine to call functions from the sim. + The functions in question are: +

+

+
+ +
+ +

Sim

+

+ The sim module is the only module that actually interacts with anything boid-specific. Whereas the other modules are more so supporting of the simulation. + The sim can be divided further into the part that interacts with the engine module, and the part that actually models and simulates the boids. + The part that interacts with the engine is responsible for registering components and systems with the ecs, loading assets, and spawning the boids. +

+
+ +
+

+ The second part of the sim module are the functions that make the boids behave the way they do. The ones that run as systems from the ecs all follow the signature of an ecs system function. They take in a list of entities, a list of the corresponding component masks, the number of items in both lists, and the delta time of the current frame. They then loop over the entities and perform specific actions for each one. In order to avoid looping over every boid in the simulation every frame, for every boid. The boids cache boids that are within the range of the behaviour with the furthest range. +

+
+ +
+

+ When the boids that are close enough to interact have all been cached, the actually modifying systems start running. As a demonstration is the separation system, which keeps the boids apart from eachother to avoid all of them forming a singularity. For each boid, the system loops through all nearby boids, keeping a running average of the positions of each boid nearby enough to be within range. After all nearby boids have been accounted for, the boid's velocity is adjusted to move away from the calculated average. +

+
+ +
+

+ Cohesion and alignment are similar enough that i wont place them here. Cohesion is the opposite of separation, and alignment is practically the same but with velocity instead of position. + The mouse does the same as cohesion but with the mouse, and thus without the need for an average. The wall behaviour pushes the boids back onto the screen when they exit it. +

+ +

ECS

+

+ The entity-component-system (ecs) module manages the runtime object model where Entities are numbers, Components are blocks of memory attached to an entity and Systems are function pointers with a component requirement. This is the library that the boids where made to test. + The below code consists of snippets showing initialization and uses of components systems and entities. +

+
+ +
+ +

Asset database

+

+ The asset database (adb) module is the module responsible for managing asset data. So it has functions for loading data from files, getting loaded file data, and releasing data after it is no longer needed. To keep this module generic, it has runtime defined rules for managing files through file handler functions. +

+
+ +
+

UI

+

+ The ui module is based on the immediate mode graphical user interface (imgui) paradigm. This is a paradigm where there is no intermediate storage between the gui and the data. The gui directly modifies the data and vice versa. + In my implementation this is done by sending the gui functions pointers to the data they represent as parameters. +

+
+ +
+
+ +

Boids (steering behaviours)

+
+ +

Info

+
+

Project type: C++ Simulation

+

Timeframe: 2022

+
+ +

Video

+ + +

Product Overview

+

+ My first version of a boids simulation. Written in C++ with sfml. +

+ +

Project Overview

+

+ I worked on this for about week inspired by the lessons on steering behaviours at school. +

+ +

Code

+
+ +

Boid

+
+

+ The boids themselves are primarily a position, a velocity, a mass, and a collection of behaviour function pointers. These boids are then stored in a vector and each of the behaviours is run for each of the boids, resulting in the demonstrated movements. +

+
+ +
+
+ +

Behaviours

+
+

+ As previously mentioned, the boids all store a collection of behaviours, represented by function pointers. These function pointers take as input a context object representing the program state at the start of the frame, and output a desired change in velocity. The original boids paper describes cohesion, separation, and alignment, so these are the main behaviours implemented. +

+
+ +
+
+ +
+
+ +
+
+
+
+ diff --git a/sara.objectionable.solutions/projects/gml-tile-movement.html b/sara.objectionable.solutions/projects/gml-tile-movement.html new file mode 100644 index 0000000..e3d2fed --- /dev/null +++ b/sara.objectionable.solutions/projects/gml-tile-movement.html @@ -0,0 +1,67 @@ + + + + GML Tile Movement - Sara Gerretsen + + + + + + + + + +

Tile Movement

+
+ +

Info

+
+

Project Type: Gamemaker 2 Game

+

Timeframe: 2019

+
+ +

Video

+ + +

Product Overview

+

+ One of my older projects. This is a prototype of a tile based movement system focused on getting smooth responsive movement with directional input. + Move around, defeat the enemies and move on to the next room. Made around 2019 or so. +

+ +

Project Overview

+

+ Made on my own over a few days, main focus was on getting a smooth feeling tile based movement system in gamemaker, which was my engine of choice at the time. + After the movement was implemented I made some sprites, levels and a simple 'pathfinding' system that picks the unoccupied tile that is closest to the target. +

+ +

Code

+
+

Try Move

+
+

+ The main challenge was allowing characters to move around without phasing into walls or eachother. The try-move + function is a generic solution to this problem. + It tests if the proposed movement would overlap with a non-walkable tile on the floor map. As well as testing if + any other character is trying to move to that position. +

+
+ +
+ +

AI Movement

+

+ The AI in the game is a simple example of how the try move function could be used in context. +

+
+ +
+
+
+ + \ No newline at end of file diff --git a/sara.objectionable.solutions/projects/hlo-projectvtd.html b/sara.objectionable.solutions/projects/hlo-projectvtd.html new file mode 100644 index 0000000..f008636 --- /dev/null +++ b/sara.objectionable.solutions/projects/hlo-projectvtd.html @@ -0,0 +1,82 @@ + + + + + Project VTD - Sara Gerretsen + + + + + + + +

Tower VR

+
+ +

Info

+
+

Project Type: Unreal Engine VR Game

+

Project Timeframe: 2022

+
+ +

Video

+ + + +

Product Overview

+

+ A VR tower defence game where the player can fight enemies with their sword, or build towers by drawing patterns on a magic circle. +

+

Project Overview

+

+ The game was made at a 'Hybride Leeromgeving' (Eng: Hybrid Learning Environment) or HLO. Which gives students the opportunity to work in an environment closer to that of a professional game company. The game was made with a team of five programmers and one artist. +

+

Code

+
+

Tower Selection

+
+

+ One of the mechanics I was responsible for was the tower selection circles. The code calls them spell circles as they were initially supposed to cast spells. + Spell circles spawn a pattern of orbs with colliders, these orbs have their own logic to send a message to a 'spell map' contained within the spell circle. +

+ spell circle - interface declaration +
+ +
+ spell circle - implementation +
+ +
+

+ These 'orbs' all know their own index within the spell circle's list of orbs. When an orb is hit, it sends its own index to the spell map component of the spell circle. This number is then converted to a string and appended to the spell map's pattern string. Because of the way the system works, only 1 digit indexes are used, though the code does not enforce this. + Whenever a new character is added, the spell map compares the formed string to a list of 'correct' patterns. + If the string produced after the last addition does not match a substring of the same length in a 'correct' pattern, the pattern is considered failed and the corresponding event is triggered. + When the string produced is equal to a 'correct' pattern, the event signalling a correct pattern is triggered. + Because a large part of the team prefered working with blueprints, a lot of the C++ architecture was designed with an eye on its blueprint interface. This lead to some odd decisions regarding the "success" event, as blueprints were unable to interact with the map of delegates to patterns that was used in the initial version of the spell map (hence the name). +

+ spell map - interface declaration +
+ +
+ spell circle - implementation +
+ +
+ spell orb - interface declaration +
+ +
+ spell orb - implementation +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/sara.objectionable.solutions/projects/ruins-of-edis.html b/sara.objectionable.solutions/projects/ruins-of-edis.html new file mode 100644 index 0000000..cff5ca9 --- /dev/null +++ b/sara.objectionable.solutions/projects/ruins-of-edis.html @@ -0,0 +1,67 @@ + + + + Ruins of Edis - Sara Gerretsen + + + + + + + + +

Ruins of Edis

+
+ +

Info

+
+

Project type: Unity Game

+

Timeframe: 2022

+
+ +

Video

+ + +

Product Overview

+

+ A relaxing desert driving game about following a blue light around the ruins of a long lost civilization. Stay within the light or be lost to the desert. +

+ +

Project Overview

+

+ For this project, I was a responsible for the car's controls and physics. I also helped with programming the terrain generation script. +

+ +

Code

+
+ +

Controls

+
+

+ The drifting system uses a "force angle" which describes the angle relative to the forward direction in which the car should apply force. + This allows the direction while drifting to be changed to be somewhere to the side of the car for it to slide properly. +

+
+ +
+
+ +

Terrain Generator

+
+

+ To make the terrain generation extensively configurable, we used a whole collection of stacked animation curves and multipliers. + These were then applied to the result of a perlin noise function to create a heightmap, which can then be applied to one or more terrain objects. +

+
+ +
+
+
+
+ + diff --git a/sara.objectionable.solutions/projects/spirit-of-science.html b/sara.objectionable.solutions/projects/spirit-of-science.html new file mode 100644 index 0000000..22c1ecd --- /dev/null +++ b/sara.objectionable.solutions/projects/spirit-of-science.html @@ -0,0 +1,73 @@ + + + + Spirit of Science - Sara Gerretsen + + + + + + + + +

Spirit of Science

+
+

Info

+
+

Project Type: Unity Game for IEGJ

+

Timeframe: 2022

+
+ +

Video

+ + + +

Product Overview

+

+ A top down exploration game setting you to exploring an abandoned factory looking for tools and key-cards while avoiding the unexplained dangers around the place +

+ +

Project Overview

+

+ This was made for the International Educational Game Jam with a team of three artists and two programmers. My role was mainly that of gameplay programmer. I wrote the interaction and movement systems, as well as a few interactions using those systems. +

+ +

Code

+
+

Interaction

+
+

+ When the player clicks, clickable objects near the cursor should be notified that they've been activated. For this, I created an Interactible interface. This interface can then be inherited to clearly mark a component as clickable. +

+
+ +
+
+ +

Clicking

+
+

+ The player interaction script triggers any IInteractible components within a radius around wherever the player has clicked. + It only does this after ensuring that the clicked object can be reached. +

+
+ +
+
+
+
+ + + diff --git a/sara.objectionable.solutions/projects/station-to-station.html b/sara.objectionable.solutions/projects/station-to-station.html new file mode 100644 index 0000000..b680e28 --- /dev/null +++ b/sara.objectionable.solutions/projects/station-to-station.html @@ -0,0 +1,38 @@ + + + + + + + + + + + +

Station to Station

+
+

Info

+
+

Project Type: Unreal Engine Management Game

+

Project Timeframe: Internship during 2022 Jan-Jul

+
+

+ A fun, relaxing but still challenging, resource management puzzle game by Galaxy Grove. That I had the chance to work on for an internship of six months. + Being my first "job" working on a real production game, I learned a lot about developing a polished, final, product. + My main contributions were to the dynamic growth of the in-game cities in response to the player's success. I also wrote some internal tooling for generating ambient occlusion maps in bulk using Blender and python. + As well as the decorative birds' behaviour. +

+

Steam

+ + +

Announcement Trailer

+ +
+ + \ No newline at end of file diff --git a/sara.objectionable.solutions/projects/stig-kart.html b/sara.objectionable.solutions/projects/stig-kart.html new file mode 100644 index 0000000..cbd851d --- /dev/null +++ b/sara.objectionable.solutions/projects/stig-kart.html @@ -0,0 +1,88 @@ + + + + Stig Kart 64 - Sara Gerretsen + + + + + + + + +

Stig Kart 64

+
+ +

Info

+
+

Project type: Unity Game

+

Timeframe: 2022

+
+ +

Video

+ + + +

Product Overview

+

+ A fast paced kart racer about timing your drifts and boosts just right. Play against your friends in splitscreen or the AI in singleplayer and try to get the quickest time. +

+ +

Project Overview

+

+ The game was made by a team of six people over two weeks. I spent most of that working on the input and kart physics. After the time trial mode was done, I also worked on the AI. +

+ +

Code

+
+ +

Steering

+
+

+ For steering we had some very specific requirements. While drifting, the player needed to be able to control their direction, without being able to flip the direction of the drift or 'drift' straight forward. + When drifting, the UpdateSteering function will transform the current steering input so that, if the drift was started while steering left, the possible range of steering values is within the range of -1 to -min, where min is a positive number lower than one which signifies the minimum amount of steering. When the drift is started while steering right, the range would be opposite, ranging from min to one. +

+
+ +
+
+ +

Basic AI

+
+

+ After we had completed the basic time trial mode, we still had about a week to add more features. So while another programmer went ahead to implement splitscreen, I wanted to try and get AI working. The player input component was already separate from the kart physics part. So the basic steering AI works by steering until it is aiming at the next invisible checkpoint on the course. +

+
+ +
+
+ +

Expanded AI

+
+

+ Allowing the AI to drift required it turning into the next turn rather than just aiming at the next checkpoint. + To do this, i first get the next three checkpoints to calculate the total angle of the next turn. This angle is then used to decide whether to drift or not. + After figuring out whether to drift or not, the AI will modify its physics in the same way as when the players presses the drift button. + With the drift started, the AI needs to aim at the checkpoint after the next to drift. +

+
+ +
+
+
+
+ + diff --git a/sara.objectionable.solutions/shared/header.html b/sara.objectionable.solutions/shared/header.html new file mode 100644 index 0000000..f72864e --- /dev/null +++ b/sara.objectionable.solutions/shared/header.html @@ -0,0 +1,25 @@ + + diff --git a/sara.objectionable.solutions/shared/jquery.min.js b/sara.objectionable.solutions/shared/jquery.min.js new file mode 100644 index 0000000..2c69bc9 --- /dev/null +++ b/sara.objectionable.solutions/shared/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 a { + padding: 20px; + border-radius: 7px; +} + +.project-grid > a:hover { + border-width: 5px; + background: #9993; + padding-top: 25px; + padding-bottom: 15px; + color: #99FF; +} + +.project-grid > a:visited { + color: #444F; +} + +.project-grid > a:active { + background: #44F3; + padding-top: 30px; + padding-bottom: 10px; +} + + +.project-card[ruins-of-edis] { + background-image: url('../assets/ruins-of-edis-cover.jpg'); +} + +.project-card[stig-kart] { + background-image: url('../assets/stig-kart-cover.png'); +} + +.project-card[spirit-of-science] { + background-image: url('../assets/spirit-of-science-cover.jpg'); +} + +.project-card[boids] { + background-image: url('../assets/boids-ecs-cover.jpg'); +} + +.project-card[gml-tile-movement] { + background-image: url('../assets/gml-tile-movement-cover.jpg'); +} + +.project-card[tower-vr] { + background-image: url('../assets/tower-vr-cover.jpg'); + background-position: 50% 100% +} + +.project-card[station-to-station] { + background-image: url('../assets/station-to-station-cover.jpg'); + background-position: 0 0 +} + + +.project-card > h2 { + text-decoration: underline; +} + +.project-labels { + margin-top: 20px; +} + +.project-labels > p { + display: inline; + color: white; + background-color: #5C5F; + border-color: black; + margin-top: 20px; + margin-bottom: 20px; + padding-left: 6px; + padding-right: 6px; + padding-top: 2px; + padding-bottom: 2px; + border-radius: 4px; + width: fit-content; + margin-bottom: 0px; + line-height: 2em; +} + +.project-labels > p.play-on-itch { + background:#fa5c5c; +} + +.project-labels > p.play-on-steam { + background:rgb(11, 81, 173); +} + +h2.project-title { + margin-top: 20px; + margin-bottom: 10px; +} diff --git a/sara.objectionable.solutions/shared/style.css b/sara.objectionable.solutions/shared/style.css new file mode 100644 index 0000000..16f38bc --- /dev/null +++ b/sara.objectionable.solutions/shared/style.css @@ -0,0 +1,212 @@ +html { + font: 100% monospace, sans-serif; + color: black; +} + +body { + max-width: 1040px; + margin-left: auto; + margin-right: auto; + padding-right: auto; + padding-bottom: 50px; +} + +h1 { + font-size: 2.5em; +} + +h2 { + font-size: 2.5em; + margin-bottom: 1px; + margin-top: 50px; +} + +h2.inline { + margin: 0px; +} + +h3 { + margin-top: 50px; +} + +a.internal { + text-decoration: none; + color: black; +} + +a:hover { + color: #BBFF; +} + +section { + display: block; + padding-top: 10px; + padding-bottom: 10px; + padding-left: 20px; + padding-right: 20px; +} + +p.intro-paragraph { + color: #999F; + font-size: 1.25em; +} + +div { + display: block; +} + +div.info { + margin-top: 10px; + color: #222F; + font-style: italic; +} + + +.embed { + background-color: #000F; + border-radius: 10px; + background-color: #000F; + border-radius: 10px; + margin-top: 10px; + margin-bottom: 3px; + width: 100%; + max-width: 700px; +} + +.embed[youtube] { + height: 400px; +} + +.git-block { + display: grid; + color: white; + grid-template-columns: 125px auto; + vertical-align: center; + max-width: 660px; + width: 94%; + margin-left: 0px; + background-color: #445F; + border-color: #111F; + border-width: 10px; + border-radius: 5px; + padding: 20px; +} + +.git-block > h2 { + margin-top: auto; + margin-bottom: auto; +} + +div.git-logo { + background-color: #0000; + background-image: url("../assets/blobcat_gitea.png"); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + width: 100px; + height: 100px; +} + +.project { + margin-left: 1em; + margin-right: 1em; +} + +.site-header { + margin-left: auto; + margin-right: auto; + padding-top: 10px; + padding-bottom: 10px; + text-align: center; background-color: #0000; +} + +.site-header > ul > li { + display: inline-block; + margin-right: 30px; + margin-left: 30px; +} + +.site-header > ul > li > a > h2 { + text-decoration: underline; + font-size: 175%; + padding: 5px 25px; +} + +.site-header > ul > li > a > h2:hover { + background: #DDF8; + color: #334F; + border-radius: 10px; +} + +.personal-info-grid { + display: grid; + gap: 20px; + grid-template-columns: 80% auto; +} + +.personal-info-photo { + background-image: url("../assets/personal-info-photo.jpg"); + background-position: center; + background-size: contain; + background-repeat: no-repeat; +} + +.experience-grid { + display: grid; + grid-template-columns: auto auto; + gap: 40px; +} + +p.experience-grid-time { + color: #999F; +} + +*[indented] { + margin-left: 1em; +} + +.code-box { + background-color: #2C2C3CFF; + border-radius: 10px; + overflow: visible; + margin-bottom: 3px; +} + +.code-content { + overflow-y: hidden; + overflow-x: scroll; + padding: 10px; +} + +a.button { + background: rgb(0, 170, 255); + border-radius: 0.2em; + padding: 0.2em 1em; + font-weight: bold; + font-size: 1.25em; + border-radius: 100em; +} +a.button:hover { + background: rgb(162, 224, 255); + color: black; +} + +@media only screen and (max-width: 640px) { + .personal-info-grid { + display: grid; + gap: 20px; + grid-template-columns: 1fr; + } + + .experience-grid { + display: grid; + grid-template-columns: 80%; + gap: 40px; + } + + .site-header { + padding-top: 1px; + padding-bottom: 1px; + margin: 3px auto; + } +}