feat: add some stuff
This commit is contained in:
0
src/content/projects/_gamez/index.md
Normal file
0
src/content/projects/_gamez/index.md
Normal file
10
src/content/projects/argenti/index.md
Normal file
10
src/content/projects/argenti/index.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: "Argenti"
|
||||
date: 2023-08-21
|
||||
draft: true
|
||||
links:
|
||||
[
|
||||
["live", "https://invoice.app.max-richter.dev"],
|
||||
["git", "https://git.max-richter.dev/max/invoice"],
|
||||
]
|
||||
---
|
BIN
src/content/projects/invoice/bg.jpg
(Stored with Git LFS)
Executable file
BIN
src/content/projects/invoice/bg.jpg
(Stored with Git LFS)
Executable file
Binary file not shown.
17
src/content/projects/invoice/bg.svg
Executable file
17
src/content/projects/invoice/bg.svg
Executable file
@ -0,0 +1,17 @@
|
||||
<svg width="1156" height="520" viewBox="0 0 1156 520" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_301_9)">
|
||||
<g opacity="0.8">
|
||||
<circle cx="574.678" cy="416.283" r="156.283" fill="url(#paint0_linear_301_9)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M597.005 307.443C597.005 304.361 599.504 301.862 602.586 301.862L718.403 301.862C733.816 301.862 746.311 314.356 746.311 329.769L746.311 446.982C746.311 450.064 743.812 452.563 740.729 452.563L696.077 452.563C692.994 452.563 690.495 450.064 690.495 446.982L690.495 410.619C690.495 405.647 684.483 403.156 680.967 406.673L594.412 493.228C583.638 504.001 566.214 504.143 555.267 493.545L480.884 421.535C477.342 418.107 471.42 420.616 471.42 425.546L471.42 546.054C471.42 549.137 468.921 551.635 465.838 551.635L421.186 551.635C418.104 551.635 415.605 549.137 415.605 546.054L415.605 346.514C415.605 335.309 422.307 325.19 432.624 320.818C442.941 316.446 454.873 318.669 462.923 326.463L570.415 430.524C572.605 432.644 576.09 432.615 578.244 430.461L641.5 367.205C645.016 363.689 642.526 357.677 637.553 357.677L602.586 357.677C599.504 357.677 597.005 355.178 597.005 352.095L597.005 307.443Z" fill="black"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_301_9" x1="472.815" y1="265.582" x2="675.146" y2="557.217" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FF8E3C"/>
|
||||
<stop offset="1" stop-color="#D9376E"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_301_9">
|
||||
<rect width="1156" height="520" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
41
src/content/projects/invoice/index.md
Normal file
41
src/content/projects/invoice/index.md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: "Invoice"
|
||||
date: 2023-08-21
|
||||
headerImg: "bg.jpg"
|
||||
draft: true
|
||||
links:
|
||||
[
|
||||
["live", "https://invoice.app.max-richter.dev"],
|
||||
["git", "https://git.max-richter.dev/max/invoice"],
|
||||
]
|
||||
---
|
||||
In meiner Freizeit übernehme ich gerne kleinere Aufträge und erledige Botengänge, Aufbauten und Abholungen für andere.
|
||||
|
||||
Ein unvermeidlicher Bestandteil dieser Tätigkeiten ist das Erstellen von Rechnungen im PDF-Format. Anfangs habe ich mich dem manuellen Prozess hingegeben und die ersten Rechnungen in Figma erstellt. Doch wie es unter Programmierer*innen oft heißt:
|
||||
|
||||
> Wieso sollte ich etwas manuell in 5 Minuten erledigen, was ich in 24 Stunden automatisieren kann?
|
||||
|
||||
Aus dieser Überlegung heraus entstand mein neuestes Hobbyprojekt – **"Invoice."**
|
||||
|
||||
## Entwicklung
|
||||
|
||||
In der Entwicklung habe ich stets das Prinzip 'K.I.S.S.' im Hinterkopf behalten: Keep it simple, stupid. Für dieses Projekt bedeutete das die Auswahl von "langweiligen", aber mir bestens vertrauten Technologien:
|
||||
|
||||
[-> SvelteKit](https://kit.svelte.dev)
|
||||
Für eine effiziente und reaktive Benutzeroberfläche.
|
||||
|
||||
[-> UNOcss](https://unocss.dev/)
|
||||
Die schnellere Tailwind Alternative.
|
||||
|
||||
[-> TypesafeI18n]()
|
||||
Um mehrsprachige Unterstützung ohne komplizierte Logik zu integrieren.
|
||||
|
||||
[-> Prisma](https://prisma.io)
|
||||
Als Datenbankzugriffslayer für eine reibungslose Datenverwaltung.
|
||||
|
||||
[-> SQLite](https://www.sqlite.org/index.html)
|
||||
Als zuverlässiges Backend, das sich ideal für kleinere Projekte eignet.
|
||||
|
||||
Diese bewährten Technologien bildeten das robuste Fundament, auf dem "Invoice" aufgebaut wurde.
|
||||
|
||||
|
BIN
src/content/projects/karl/images/Indicatrices_of_Distortion.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/karl/images/Indicatrices_of_Distortion.png
(Stored with Git LFS)
Normal file
Binary file not shown.
322
src/content/projects/karl/images/Indicatrices_of_Distortion.svg
Normal file
322
src/content/projects/karl/images/Indicatrices_of_Distortion.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 425 KiB |
BIN
src/content/projects/karl/images/crosswalk.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/karl/images/crosswalk.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/karl/images/crosswalk_mask.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/karl/images/crosswalk_mask.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/karl/images/formel.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/karl/images/formel.png
(Stored with Git LFS)
Normal file
Binary file not shown.
135
src/content/projects/karl/index.md
Normal file
135
src/content/projects/karl/index.md
Normal file
@ -0,0 +1,135 @@
|
||||
---
|
||||
title: "K.A.R.L"
|
||||
date: 2021-04-01
|
||||
headerImg: "images/Indicatrices_of_Distortion.png"
|
||||
license: "CC-BY-SA:4.0"
|
||||
comments: true
|
||||
links:
|
||||
[
|
||||
["live", "https://max-richter.dev/karl"],
|
||||
["git", "https://git.max-richter.dev/max/karl"],
|
||||
]
|
||||
---
|
||||
|
||||
*[Header by Justin Kunimune - Own work, CC BY-SA 4.0](https://commons.wikimedia.org/w/index.php?curid=66467577*)*
|
||||
|
||||
|
||||
{{<toc>}}
|
||||
|
||||
```
|
||||
K.A.R.L ist eine WebApp die einem dabei hilft 360Grad Panoramas in Sektionen einzuteilen, (Himmel, Boden, Bäume usw...) und dann den Anteil der einzelnen Sektionen am Gesamtbild festzustellen.
|
||||
```
|
||||
|
||||
## Einleitung
|
||||
|
||||
Das Projekt ist aus der Zusammenarbeit mit zwei Freunden entstanden. Der eine steckt gerade mitten in der Konzeptionsphase seiner Bachelorarbeit (Geographie), die sich mit der Auswirkung von Vegetation auf das Stadtklima beschäftigt. Dazu hat er an verschiedenen Orten in Köln Albedo Messungen vorgenommen, also quasi "wieviel Licht kommt vom Himmel, und wieviel davon wird vom Boden reflektiert". Um diese Messungen in den richtigen Kontext zu setzen hat er von jedem Messort 360 Panoramas angelegt, diese sehen ungefähr so aus:
|
||||
|
||||
{{<figure src="images/crosswalk.jpg" alt="Image of a crosswalk" caption="bild von hdrihaven.com">}}
|
||||
|
||||
Dazu brauchte er jetzt Angaben wieviel Prozent der Sicht zum Beispiel Vegetation, Himmel und Boden sind. Um das zu messen hat er in Gimp per Hand eine Segmentationsmap erstellt, eine Segmentationsmap sieht etwas so aus:
|
||||
|
||||
{{<figure src="images/crosswalk_mask.png" alt="Segmentationsmap">}}
|
||||
|
||||
## Problemstellung
|
||||
|
||||
Wenn wir jetzt einfach naiv hingehen und die Pixel der einzelnen Farben zählen und daraus eine prozentuale Verteilung machen kriegen wir das klassische Problem mit der Verzerrung das die Menschheit schon seit Jahrhunderten mit Karten hat. Undzwar lassen sich Kugeln nur sehr ungern zwei dimensional darstellen, dabei kommt es immer zu Verzerrungen, wie folgendes Bild visualisiert.
|
||||
|
||||
{{<figure src="images/Indicatrices_of_Distortion.png" alt="Image of a crosswalk" caption="by Justin Kunimune - Own work, CC BY-SA 4.0">}}
|
||||
|
||||
Zum Glück passiert diese Verzerrung nur in der Breite, wir brauchen also eine Formel die uns für die Höhe eines Pixels eine Gewichtung gibt um diese Verzerrung auszugleichen. Nach vielen Versuchen sind wir bei dieser Formel gelandet:
|
||||
|
||||
```javascript
|
||||
/*
|
||||
height: height of the image in pixels
|
||||
calibrationFactor: 1.333, somehow this works, dont ask why, we dont either
|
||||
y: y position of the pixel
|
||||
*/
|
||||
const pixelValue = Math.cos(
|
||||
(((360 / height ** 2) * y ** 2 + (-360 / height) * y + 90) / 360) *
|
||||
(2 + calibrationFaktor) *
|
||||
Math.PI
|
||||
)
|
||||
```
|
||||
|
||||
Diese Formel ist eigentlich dafür gedacht für einen bestimmten Breitengrad den Abstand zwischen zwei Längengraden zu berechnen, aber für unsere Zwecke funktioniert sie auch sehr gut.
|
||||
|
||||
Hier noch einiger der ersten Versuch in Desmos (fantastisches Tool btw):
|
||||
|
||||
{{<iframe "https://www.desmos.com/calculator/52ph4thjah?embed" >}}
|
||||
|
||||
## Die Technologien
|
||||
|
||||
Ich hatte den Wunsch eine WebApp zu bauen die reintheoretisch auch komplett offline funktioniert. Deswegen werden nach dem ersten laden der Website keine weiteren Daten mehr verschickt, sondern alles wird im Browser ausgeführt. Dies ist bei einer Anwendung die sehr viele Pixel bearbeiten und so sehr viel Performance braucht schwierig da die Ressourcen des Browsers begrenzt sind. Folgende Technologien haben mir dabei geholfen die User Experience trotzdem halbwegs okay zu gestalten:
|
||||
|
||||
### Canvas
|
||||
|
||||
Wenn es um irgendwas mit Pixeln im Browser geht kommt man an Canvas2D eigentlich gar nicht vorbei. Canvas ist durch seine programmatische Schnittstelle optimal für diesen Job geeignet.
|
||||
|
||||
### Web Workers
|
||||
|
||||
Normalerweise werden im Browser alle Operationen einer Website in einem Thread ausgeführt. Dies führt dazu eine rechenintensive Aufgabe die komplette Website zum erliegen bringen kann. Dabei können WebWorker Abhilfe schaffen. WebWorker können beliebigen Code in einem seperaten Thread ausführen mit dem einzigen Hinderniss das die Kommunikation mit dem Haupt Thread etwas schwierig ist.
|
||||
|
||||
Bei K.A.R.L werden zwei WebWorker eingesetzt, der pixel-worker ist für das Analysieren der Segmentationsmap und für das Eimer Werkzeug verantwortlich und der ai-worker fürs ausführen des Tensorflow Codes.
|
||||
|
||||
### Tensorflow
|
||||
|
||||
Warum per Hand malen nach zahlen machen wenn der Rechner das ganz automagisch kann? Hab ich mir auch gedacht und Tensorflow mit dem [ade20k](https://groups.csail.mit.edu/vision/datasets/ADE20K/) eingebaut. Dieses Netwerk ist super darin Bäume, Boden, Beton und Himmel zu erkennen. In der Editor Ansicht versteckt sich diese Funktion rechts unter dem "AI" Knopf.
|
||||
|
||||
### IndexDB
|
||||
|
||||
Wenn es darum geht größere Mengen an Daten (vorallem Bilder), lokal im Browser zu speichern geht das eigentlich nur richtig mit IndexDB *(ja, localStorage mit Base64 Bildern könnte auch gehen, ist aber in machen Browsern auf 5mb beschränkt)*. Da die IndexDB Api aber zu einer der [verwirrensten Browser Api's weit und breit gehört](https://nolanlawson.github.io/offlinefirst-2016-03/#/27) benutze ich [idb](npmjs.com/package/idb), eine fantastische kleine Wrapperlibrary um IndexDB rum die auch noch Promises unterstützt.
|
||||
|
||||
## Interessantes...
|
||||
|
||||
### FloodFill Allgorithmus
|
||||
|
||||
Nachdem ich einige Panoramas per Hand mit den Tools segmentiert habe ist mir aufgefallen das man sehr oft einfach Regionen die eine ähnliche Farbe haben anmalt. Das brachte mich auf die Idee ein Fill Tool ähnlich wie in Photoshop zu bauen, aber vieeel besser.
|
||||
|
||||
Das Tool funktioniert ungefähr so:
|
||||
1. Der User klickt mit dem Fill Tool auf das Bild
|
||||
2. Die x/y Koordinaten des Klicks sowie alles Pixel des Bildes werden an einen WebWorker gesendet
|
||||
3. Dieser erstellt ein Graustufen Bild, bei dem der Wert jedes Pixels der Abstand (räumlich und farblich) zu dem Bereich ist der geklickt wurde.
|
||||
4. Das Bild wird zurückgeschickt
|
||||
5. Im Canvas Code wird dann aufgrund des Wertes der einzelnen Pixel entschieden ob dies gefüllt werden oder nicht
|
||||
|
||||
### Svelte Bindings
|
||||
|
||||
Ich fand es immer kompliziert State über mehrere Komponenten hinweg zu regeln. Ein Beispiel wäre der Editor, er besteht aus drei einzelnen Komponenten (Toolbar, Topbar, PaintArea) die alle wissen müssen welches Farbe und welches Werkzeug gerade aktiv sind. Man könnte diesen State in einen globalen Store schreiben und in jedem der einzelnen Komponenten darauf zugreifen, aber eigentlich ist das aktive Werkzeug nur in dem Editor Kontext wichtig. Also liegt dieser State jetzt in dem Editor Komponent der in per binding an seine Unterkomponenten weitergibt, das ganze sieht dan ungefähr so aus:
|
||||
|
||||
```html
|
||||
<!-- Editor.svelte -->
|
||||
<script lang="ts">
|
||||
import TopBar from "./TopBar.svelte";
|
||||
|
||||
let activeColor = "ff0000";
|
||||
let _activeColor = localStorage.getItem("activeColor");
|
||||
if (_activeColor) {
|
||||
activeColor = _activeColor;
|
||||
}
|
||||
</script>
|
||||
|
||||
<TopBar bind:activeColor/>
|
||||
|
||||
|
||||
<!-- TopBar.svelte -->
|
||||
<script>
|
||||
export let activeColor = "ff0000";
|
||||
</script>
|
||||
|
||||
{{activeColor}}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Svelte Stores
|
||||
|
||||
Für einige andere Sachen kann man hingegen super Stores verwenden, zum Beispiel für Toasts/Modals. So kann man den State für die Toasts (Dass sind die Nachrichten unten Links) super in einem Komponent packen und muss sie nicht über mehrere hinweg verteilen.
|
||||
|
||||
|
||||
### Wofür steht K.A.R.L?
|
||||
|
||||
W.I.P
|
||||
|
||||
### Wofür steht W.I.P
|
||||
|
||||
Work in Progress
|
BIN
src/content/projects/modern/images/screenshot.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/modern/images/screenshot.png
(Stored with Git LFS)
Normal file
Binary file not shown.
26
src/content/projects/modern/index.md
Normal file
26
src/content/projects/modern/index.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
title: "Modern"
|
||||
date: 2020-06-09T11:55:24+02:00
|
||||
headerImg: "images/screenshot.png"
|
||||
links:
|
||||
[
|
||||
["live", "https://max-richter.dev/modern?scene=modern"],
|
||||
["git", "https://git.max-richter.dev/max/modern"],
|
||||
]
|
||||
---
|
||||
|
||||
Ein sehr altes Projekt von mir, damals habe ich als Azubi bei des Wahnsinns Fette Beute gearbeitet. Muss so rund 2017 gewesen sein. Einige Sachen die ich echt cool find an dem Projekt:
|
||||
|
||||
1. Lazyloading
|
||||
|
||||
Alle Texturen werden erst als placeholder geladen und dann in großer Auflösung. Führt dazu das der Nutzer insgesamt etwas mehr Daten laden muss aber die Website ist deutlich schneller interaktiv.
|
||||
|
||||
2. Die Controls
|
||||
|
||||
Three.js, das Framework mit dem ich die Website umgesetzt habe hat eine eingebaute OrbitControl Klasse die man in den meisten Fällen nutzen kann für diesen Usecase aber leider nicht flexibel genug war. Deswegen habe ich eine eigene Control Klasse implementiert und muss sagen ich bin mit der Usability echt zufrieden.
|
||||
|
||||
3. Die Settings
|
||||
|
||||
Ich finde die Settings animieren schön und sind schön gelayoutet. Vorallem der Qualitäts Slider mit seinem schnellen Feedback find ich gut.
|
||||
|
||||
Für ein so altes Projekt gar nicht schlecht, über die Code Qualität will ich jetzt hier gar nichts sagen. Wer sich das selber angucken will, hier ist der [Link](https://git.max-richter.dev/max/modern).
|
101
src/content/projects/plantarium/images/architecture.svg
Normal file
101
src/content/projects/plantarium/images/architecture.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 77 KiB |
BIN
src/content/projects/plantarium/images/branches.jpg
(Stored with Git LFS)
Executable file
BIN
src/content/projects/plantarium/images/branches.jpg
(Stored with Git LFS)
Executable file
Binary file not shown.
BIN
src/content/projects/plantarium/images/dataflow.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/dataflow.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
72
src/content/projects/plantarium/images/nodes.svg
Normal file
72
src/content/projects/plantarium/images/nodes.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 85 KiB |
BIN
src/content/projects/plantarium/images/page01-0.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-0.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-1.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-1.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-2.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-2.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-3.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-3.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-4.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-4.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-5.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-5.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-6.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-6.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-7.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-7.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-8.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-8.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/page01-9.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/page01-9.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/plant-2.png
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/plant-2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/screenshot-davinci.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/screenshot-davinci.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/screenshot-geometry-nodes.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/screenshot-geometry-nodes.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/screenshot-houdini.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/screenshot-houdini.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/content/projects/plantarium/images/screenshot-unreal.jpg
(Stored with Git LFS)
Normal file
BIN
src/content/projects/plantarium/images/screenshot-unreal.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
18
src/content/projects/plantarium/index.en.mdx
Normal file
18
src/content/projects/plantarium/index.en.mdx
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
title: "Plantarium"
|
||||
date: 2022-08-31
|
||||
headerImg: "/projects/plantarium/plantarium.png"
|
||||
featured: true
|
||||
links: [["website", "https://plant.max-richter.com"], ["git", "https://github.com/jim-fx/plantarium"]]
|
||||
draft: true
|
||||
---
|
||||
|
||||
One of the projects I spent the most time with. As a Waldorf student and village kid, a bit cliché, I know, but I've always been passionate about plants, their structure and aesthetics. I'm also an absolute [Blender](https://blender.org) nerd and from these two interests Plantarium was born.
|
||||
|
||||
Plantarium is a tool that allows users to generate procedural plants. The first prototype was finished within two weeks of intensive work and looked something like this:
|
||||
|
||||
<img src="images/page01-0.jpg"/>
|
||||
|
||||
|
||||
The interface was divided into 4 different levels, "Stems", "Branches", "Leaves" and "Import/Export". The idea was not bad because parts of the interface belonged to parts of the plant and you could quickly find the right settings if you wanted to change something. This way of designing the interface limits the freedom of the user(s) to generate the plants they want. Also, the interface code was unattractive, to say the least. It worked but it was not fun to work on. Also, I was mixing UI code with code that generated the plant.
|
||||
|
80
src/content/projects/plantarium/index.mdx
Normal file
80
src/content/projects/plantarium/index.mdx
Normal file
@ -0,0 +1,80 @@
|
||||
---
|
||||
title: "Plantarium"
|
||||
date: 2022-08-31T20:46:26+02:00
|
||||
headerImg: "/projects/plantarium/plantarium.png"
|
||||
featured: true
|
||||
links: [["website", "https://plant.max-richter.dev"], ["git", "https://github.com/jim-fx/plantarium"]]
|
||||
tags: ["Web", "3D", "Svelte", "Node-Systeme"]
|
||||
draft: true
|
||||
---
|
||||
|
||||
# Einführung
|
||||
|
||||
Plantarium ist wohl das Hobby Projekt, mit dem ich am meisten Zeit verbracht habe. Als Waldorfschüler und Dorfkind ein bisschen Klischeemäßig, ich weiß, aber der Aufbau und die Ästhetik von Pflanzen haben mich schon immer begeistert. Außerdem bin ich bekennender [Blender](https://blender.org) (das 3D Programm) Fan und aus diesen beiden Interessen entstand dieses Projekt.
|
||||
|
||||
Plantarium ist eine WebApp mit der Nutzer 3D Model von Pflanzen generieren können. Der erste Prototyp war innerhalb von zwei Wochen intensiver Arbeit fertig und sah ungefähr so aus:
|
||||
|
||||
<svelte component="image-slider" title="Prototype Design">
|
||||
<img src="./images/page01-0.jpg" alt="Stem Page"/>
|
||||
<img src="./images/page01-1.jpg" alt="Branches page"/>
|
||||
<img src="./images/page01-2.jpg" alt="Leaves page"/>
|
||||
<img src="./images/page01-3.jpg" alt="Import/Export page"/>
|
||||
<img src="./images/page01-5.jpg" alt="Design of UI Components"/>
|
||||
<img src="./images/page01-6.jpg" alt="Data flow inside app"/>
|
||||
</svelte>
|
||||
|
||||
Schon gar nicht schlecht, aber wie das mit Prototypen so ist gab es noch einiges zu verbessern. Also eine Kurze Historie der größten Änderungen bis heute:
|
||||
|
||||
## Refactors
|
||||
|
||||
### Svelte Rewrite
|
||||
|
||||
Der erste Prototyp war handgeschriebenes ungetestes Javascript. Das kann man sich etwa so vorstellen als ob man ein Auto nur aus Zahnstochern und Ducttape bauen muss.
|
||||
Man kriegt es eventuell hin, ist vielleicht sogar ganz begeistert von seiner Kreation, wenn man sich das ganze aber dann ne Woche später nochmal anschaut oder schlimmer noch Verbesserungen daran machen will wird es recht schnell schwierig. Das hieß es war Zeit für die Lieblingsbeschäftigung eines jeden Web Entwicklers; herausfinden was gerade der heiße Scheiß in der Welt der Webentwicklung ist. Sobald man sich dann für eine der tausenden möglichen Technologien entschieden hat, macht man diese zu seiner persönlichen Religion und verteidigt sie mit religiösem Fanatismus. Ganz einfach, oder?
|
||||
|
||||
Also hab ich mich für das einfachste, schnellste und rundherum beste Framework entschieden: ["Svelte"](https://svelte.dev).
|
||||
|
||||
Im Grunde helfen einem Frameworks die Daten einer App, also zum Beispiel Nutzernamen, Loginstatus usw. in HTML und CSS zu verwandeln, was der Browser dann anzeigt.
|
||||
|
||||
|
||||
### Node-Systeme
|
||||
|
||||
Das Interface war in 4 verschiedene Stufen aufgeteilt, "Stamm", "Äste","Blätter" und "Import/Export".
|
||||
Die Idee war gar nicht schlecht da jeder Teil an der Pflanze eine eigene Ansicht hatte und man recht schnell die richtigen Einstellungen fand, wenn man etwas ändern wollte.
|
||||
Leider werden dadurch die Nutzer extrem eingeschränkt und man kann nur Pflanzen bauen die dem Schema Stam->Ast->Blatt entsprechen. Was ist aber wenn ich mehrere Ebenen von Ästen haben will oder unterschiedliche Blätter an Stamm und Ast? Das war mit dem Model nicht möglich also wie man so schön sagt:
|
||||
"Back to the drawing board."
|
||||
Im Hinterkopf hatte ich eigentlich schon die Lösung für das Problem, war mir nur nicht ganz sicher, ob ich die nötigen Skills hatte um es zu implementieren.
|
||||
|
||||
Die Lösung sind Node-Systeme! Hmm, was ist das denn?
|
||||
|
||||

|
||||
|
||||
Node-Systeme bestehen aus Nodes und Connections. Nodes haben inputs und outputs und man kann diese miteinander verbinden.
|
||||
|
||||
In der Beispielgrafik haben wir zwei `input-color` nodes die jeweils eine Farbe produzieren und eine `mix-color` node die farben miteinander vermixt.
|
||||
|
||||
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
|
||||
|
||||
<img src="/projects/plantarium/screenshot-plantarium.png" alt="Plantariums uses nodes to create plants"/>
|
||||
|
||||
<svelte component="image-slider" title="Beispiele von Node Systemen">
|
||||
<img src="images/screenshot-geometry-nodes.jpg" alt="Blenders uses nodes to create geometry"/>
|
||||
<img src="images/screenshot-houdini.jpg" alt="Houdini uses nodes for vfx/simulations"/>
|
||||
<img src="images/screenshot-unreal.jpg" alt="Unreal uses nodes for game logic"/>
|
||||
<img src="images/screenshot-davinci.jpg" alt="Davinvi uses nodes for vfx"/>
|
||||
</svelte>
|
||||
|
||||
### Svelte-Kit Rewrite
|
||||
|
||||
## Architektur
|
||||
|
||||
## Design
|
||||
|
||||
## Zukunft
|
||||
|
||||
## Abschluss
|
||||
|
||||
Aktuell sieht die Architectur in etwa so aus:
|
||||
|
||||

|
||||
|
Reference in New Issue
Block a user