feat: add resume.pdf button
All checks were successful
Deploy to SFTP Server / build (push) Successful in 41m27s
All checks were successful
Deploy to SFTP Server / build (push) Successful in 41m27s
This commit is contained in:
parent
e41ef2fceb
commit
d1d6867130
BIN
public/max-richter-resume.pdf
Normal file
BIN
public/max-richter-resume.pdf
Normal file
Binary file not shown.
@ -10,14 +10,15 @@ const t = useTranslations(Astro.url);
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Card
|
<Card
|
||||||
classes="googley-eye-target relative rounded-diag-md border border-neutral bg-dark grid xs:grid-cols-[250px_1fr] min-h-[180px] sm:h-[180px] mt-8">
|
classes="googley-eye-target relative rounded-diag-md border border-neutral bg-dark grid xs:grid-cols-[200px_1fr] sm:grid-cols-[300px_1fr] mt-8">
|
||||||
<div
|
<div
|
||||||
class="image relative h-[130%] self-end items-end flex overflow-hidden order-last xs:order-first">
|
class="relative xs:h-full self-end items-end flex order-last xs:order-first">
|
||||||
<div class="relative inline w-1/2 xs:w-full">
|
<div
|
||||||
|
class="image xs:absolute inline w-1/2 xs:w-full xs:h-[110%] overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={MaxImg}
|
src={MaxImg}
|
||||||
alt="its mee"
|
alt="its mee"
|
||||||
class="object-bottom h-full object-cover"
|
class="object-bottom h-full object-contain"
|
||||||
hash={false}
|
hash={false}
|
||||||
maxWidth={700}
|
maxWidth={700}
|
||||||
loader={false}
|
loader={false}
|
||||||
@ -31,9 +32,15 @@ const t = useTranslations(Astro.url);
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content flex flex-col p-8 pl-4 gap-2 justify-center">
|
<div class="content flex flex-col p-8 pl-4 gap-3 justify-center">
|
||||||
<h1 class="text-2xl">{t("home.title")}</h1>
|
<h1 class="text-2xl">{t("home.title")}</h1>
|
||||||
<p>{t("home.subtitle")}</p>
|
<p>{t("home.subtitle")}</p>
|
||||||
|
<a
|
||||||
|
class="bg gradient flex items-center border border-neutral gap-2 w-fit p-2 px-4 rounded-2xl"
|
||||||
|
href="/max-richter-resume.pdf">
|
||||||
|
{t("resume").toLowerCase()}.pdf
|
||||||
|
<span class="i-tabler-download w-4 h-4 dark:opacity-50"></span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import IconSun from "~icons/tabler/Sun";
|
import IconSun from "~icons/tabler/Sun";
|
||||||
import IconMoon from "~icons/tabler/Moon";
|
import IconMoon from "~icons/tabler/Moon";
|
||||||
|
import { colors } from "@helpers/colors";
|
||||||
|
|
||||||
let theme = writable("");
|
let theme = writable("");
|
||||||
|
|
||||||
@ -10,8 +11,12 @@
|
|||||||
document.documentElement.classList.remove("light", "dark");
|
document.documentElement.classList.remove("light", "dark");
|
||||||
document.documentElement.classList.add($theme);
|
document.documentElement.classList.add($theme);
|
||||||
localStorage.setItem("theme", $theme);
|
localStorage.setItem("theme", $theme);
|
||||||
// @ts-ignore
|
|
||||||
window["updateBackgroundColor"]?.();
|
const background = window.getComputedStyle(document.body);
|
||||||
|
|
||||||
|
$colors = {
|
||||||
|
background: background.backgroundColor,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleTheme() {
|
function toggleTheme() {
|
||||||
|
@ -2,38 +2,36 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import createFishes from "./fishes/webgl-fishes";
|
import createFishes from "./fishes/webgl-fishes";
|
||||||
import { Color } from "ogl";
|
import { Color } from "ogl";
|
||||||
import { rgbToHex } from "@helpers/colors";
|
import { colors, rgbToHex } from "@helpers/colors";
|
||||||
|
|
||||||
let canvasBottom: HTMLCanvasElement;
|
let canvasBottom: HTMLCanvasElement;
|
||||||
|
|
||||||
let speed = 0;
|
let speed = 0;
|
||||||
let timeOffset = Math.random() * 100000;
|
let timeOffset = Math.random() * 100000;
|
||||||
|
|
||||||
let fishCanvasBack: { resize: any; update: any };
|
let fishCanvasBack: ReturnType<typeof createFishes>;
|
||||||
let render = true;
|
let render = true;
|
||||||
|
|
||||||
const color = new Color("#ffffff");
|
const color = new Color("#ffffff");
|
||||||
|
|
||||||
|
function updateColor(c: string) {
|
||||||
|
const d = new Color(rgbToHex(c));
|
||||||
|
color.set(d.r, d.g, d.b);
|
||||||
|
fishCanvasBack?.resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if ($colors.background) {
|
||||||
|
updateColor($colors.background);
|
||||||
|
}
|
||||||
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
fishCanvasBack.resize();
|
fishCanvasBack.resize();
|
||||||
|
|
||||||
render = window.innerWidth > 500;
|
render = window.innerWidth > 500;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateBackgroundColor = () => {
|
|
||||||
const background = window.getComputedStyle(document.body);
|
|
||||||
const d = new Color(rgbToHex(background.backgroundColor));
|
|
||||||
color.set(d.r, d.g, d.b);
|
|
||||||
fishCanvasBack.resize();
|
|
||||||
};
|
|
||||||
|
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const background = window.getComputedStyle(document.body);
|
|
||||||
const d = new Color(rgbToHex(background.backgroundColor));
|
|
||||||
color.set(d.r, d.g, d.b);
|
|
||||||
|
|
||||||
fishCanvasBack = createFishes(canvasBottom, { amount: 100, color });
|
fishCanvasBack = createFishes(canvasBottom, { amount: 100, color });
|
||||||
|
|
||||||
fishCanvasBack.resize();
|
fishCanvasBack.resize();
|
||||||
@ -45,8 +43,6 @@
|
|||||||
render && fishCanvasBack.update(t, timeOffset);
|
render && fishCanvasBack.update(t, timeOffset);
|
||||||
}
|
}
|
||||||
loaded = true;
|
loaded = true;
|
||||||
// @ts-ignore
|
|
||||||
window["updateBackgroundColor"] = updateBackgroundColor;
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -69,10 +65,10 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.5s;
|
transition: opacity 4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.loaded {
|
canvas.loaded {
|
||||||
opacity: 0.2;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import { createLeaves, setRotation } from "./leaves";
|
import { createLeaves, setRotation } from "./leaves";
|
||||||
import { Color } from "ogl";
|
import { Color } from "ogl";
|
||||||
import { rgbToHex } from "@helpers/colors";
|
import { rgbToHex } from "@helpers/colors";
|
||||||
|
import { colors } from "@helpers/colors";
|
||||||
|
|
||||||
let canvas: HTMLCanvasElement;
|
let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
@ -14,17 +15,17 @@
|
|||||||
|
|
||||||
const color = new Color("#000000");
|
const color = new Color("#000000");
|
||||||
|
|
||||||
const updateBackgroundColor = () => {
|
function updateColor(c: string) {
|
||||||
const background = window.getComputedStyle(document.body);
|
const d = new Color(rgbToHex(c));
|
||||||
const d = new Color(rgbToHex(background.backgroundColor));
|
|
||||||
color.set(d.r, d.g, d.b);
|
color.set(d.r, d.g, d.b);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
$: if ($colors.background) {
|
||||||
|
updateColor($colors.background);
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
updateBackgroundColor();
|
createLeaves({ canvas, num: 40, minZ: 0, maxZ: 1, color });
|
||||||
createLeaves({ canvas, num: 20, minZ: 0, maxZ: 1, color });
|
|
||||||
// @ts-ignore
|
|
||||||
window["updateBackgroundColor"] = updateBackgroundColor;
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}, 100);
|
}, 100);
|
||||||
@ -48,10 +49,10 @@
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 2s;
|
transition: opacity 4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loaded {
|
.loaded {
|
||||||
opacity: 0.2;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
BIN
src/content/projects/plantarium/images/plantarium-screenshot.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/plantarium-screenshot.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,3 @@
|
|||||||
|
[ZoneTransfer]
|
||||||
|
ZoneId=3
|
||||||
|
HostUrl=about:internet
|
@ -16,6 +16,8 @@ Plantarium ist die Schnittmenge zwischen zwei Dingen die ich sehr faszinierend f
|
|||||||
Es ist eine WebApp die es Nutzern ermöglicht Pflanzen zu erstellen und zu exportieren.
|
Es ist eine WebApp die es Nutzern ermöglicht Pflanzen zu erstellen und zu exportieren.
|
||||||
Die User legen dabei über ein Node-System fest wie die Pflanze aussieht und Plantarium generiert daraus ein 3D Modell.
|
Die User legen dabei über ein Node-System fest wie die Pflanze aussieht und Plantarium generiert daraus ein 3D Modell.
|
||||||
|
|
||||||
|
<Image src={plantarium_screenshot} alt="Plantarium Screenshot"/>
|
||||||
|
|
||||||
# Die Anfänge und Herausforderungen
|
# Die Anfänge und Herausforderungen
|
||||||
|
|
||||||
Der erste Prototyp war innerhalb von zwei Wochen intensiver Arbeit fertig und sah ungefähr so aus:
|
Der erste Prototyp war innerhalb von zwei Wochen intensiver Arbeit fertig und sah ungefähr so aus:
|
||||||
@ -33,6 +35,7 @@ import screenshot_geometry_nodes from "./images/screenshot-geometry-nodes.jpg"
|
|||||||
import screenshot_houdini from "./images/screenshot-houdini.jpg"
|
import screenshot_houdini from "./images/screenshot-houdini.jpg"
|
||||||
import screenshot_unreal from "./images/screenshot-unreal.jpg"
|
import screenshot_unreal from "./images/screenshot-unreal.jpg"
|
||||||
import screenshot_davinci from "./images/screenshot-davinci.jpg"
|
import screenshot_davinci from "./images/screenshot-davinci.jpg"
|
||||||
|
import plantarium_screenshot from "./images/plantarium-screenshot.png"
|
||||||
import Plantarium from "./images/plantarium.png"
|
import Plantarium from "./images/plantarium.png"
|
||||||
import ImageGallery from "@components/ImageGallery.svelte"
|
import ImageGallery from "@components/ImageGallery.svelte"
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ import ImageGallery from "@components/ImageGallery.svelte"
|
|||||||
|
|
||||||
<Leaves client:load/>
|
<Leaves client:load/>
|
||||||
|
|
||||||
|
|
||||||
<ImageSlider title="Erster Prototyp" client:load>
|
<ImageSlider title="Erster Prototyp" client:load>
|
||||||
<Image src={page01_0} alt="Stem Page"/>
|
<Image src={page01_0} alt="Stem Page"/>
|
||||||
<Image src={page01_1} alt="Branches page"/>
|
<Image src={page01_1} alt="Branches page"/>
|
||||||
@ -83,8 +87,6 @@ In der Beispielgrafik haben wir zwei `input-color` nodes die jeweils eine Farbe
|
|||||||
|
|
||||||
Das coole ist das man dieses System sehr generisch gestalten kann und zum beispiel eine `generate-stem`, `generate-branches` oder eine `add-leaves` node programmieren kann. Aufgrund der
|
Das coole ist das man dieses System sehr generisch gestalten kann und zum beispiel eine `generate-stem`, `generate-branches` oder eine `add-leaves` node programmieren kann. Aufgrund der
|
||||||
|
|
||||||
<Image src={Plantarium} alt="Plantariums uses nodes to create plants"/>
|
|
||||||
|
|
||||||
<ImageSlider title="Beispiele von Node Systemen" client:load>
|
<ImageSlider title="Beispiele von Node Systemen" client:load>
|
||||||
<Image src={screenshot_geometry_nodes} alt="Blenders uses nodes to create geometry"/>
|
<Image src={screenshot_geometry_nodes} alt="Blenders uses nodes to create geometry"/>
|
||||||
<Image src={screenshot_houdini} alt="Houdini uses nodes for vfx/simulations"/>
|
<Image src={screenshot_houdini} alt="Houdini uses nodes for vfx/simulations"/>
|
||||||
|
9
src/env.d.ts
vendored
9
src/env.d.ts
vendored
@ -1,3 +1,12 @@
|
|||||||
/// <reference path="../.astro/types.d.ts" />
|
/// <reference path="../.astro/types.d.ts" />
|
||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client" />
|
||||||
/// <reference types="unplugin-icons/types" />
|
/// <reference types="unplugin-icons/types" />
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
colors: import("svelte/store").Writable<{
|
||||||
|
background: string;
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
// function to turn css rgb() strings to hex
|
// function to turn css rgb() strings to hex
|
||||||
export function rgbToHex(rgb: string) {
|
export function rgbToHex(rgb: string) {
|
||||||
let hex = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
let hex = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||||
@ -12,3 +14,7 @@ export function rgbToHex(rgb: string) {
|
|||||||
.join("")
|
.join("")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const colors = writable({
|
||||||
|
background: "#f0f0f0",
|
||||||
|
});
|
||||||
|
@ -23,6 +23,7 @@ export const ui = {
|
|||||||
'nav.videos': 'Videos',
|
'nav.videos': 'Videos',
|
||||||
'nav.photos': 'Photos',
|
'nav.photos': 'Photos',
|
||||||
'toc.title': 'Table of Contents',
|
'toc.title': 'Table of Contents',
|
||||||
|
"resume": "Resume",
|
||||||
},
|
},
|
||||||
de: {
|
de: {
|
||||||
"en": "English",
|
"en": "English",
|
||||||
@ -39,6 +40,7 @@ export const ui = {
|
|||||||
'nav.projects': 'Projekte',
|
'nav.projects': 'Projekte',
|
||||||
'nav.videos': 'Videos',
|
'nav.videos': 'Videos',
|
||||||
'nav.photos': 'Fotos',
|
'nav.photos': 'Fotos',
|
||||||
|
"resume": "Lebenslauf",
|
||||||
'toc.title': 'Inhaltsverzeichnis',
|
'toc.title': 'Inhaltsverzeichnis',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -74,11 +74,44 @@ import "./global.css";
|
|||||||
body {
|
body {
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
body > * {
|
main,
|
||||||
|
header,
|
||||||
|
footer {
|
||||||
background: var(--background-dark);
|
background: var(--background-dark);
|
||||||
padding: 0.5rem 3rem;
|
padding: 0.5rem 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body::after {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
width: 200px;
|
||||||
|
top: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background: red;
|
||||||
|
background: linear-gradient(
|
||||||
|
to left,
|
||||||
|
var(--background-dark),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -200px;
|
||||||
|
right: -200px;
|
||||||
|
bottom: -100px;
|
||||||
|
width: 200px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--background-dark),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 700px) {
|
||||||
body > * {
|
body > * {
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
@ -90,10 +123,10 @@ import "./global.css";
|
|||||||
<header class="sticky bottom-0 sm:top-0 z-2 order-last sm:order-first">
|
<header class="sticky bottom-0 sm:top-0 z-2 order-last sm:order-first">
|
||||||
<Nav />
|
<Nav />
|
||||||
</header>
|
</header>
|
||||||
<main id="main-content" class="flex flex-col gap-4">
|
<main id="main-content" class="relative flex flex-col gap-6">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<footer class="px-4 flex gap-8">
|
<footer class="mx-8 mb-4 mt-2 flex gap-8">
|
||||||
<LanguagePicker />
|
<LanguagePicker />
|
||||||
<a
|
<a
|
||||||
href="https://git.max-richter.dev/max/website"
|
href="https://git.max-richter.dev/max/website"
|
||||||
|
Loading…
Reference in New Issue
Block a user