From a2ce84707d610ed319b56f4082c7113329a02573 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sun, 25 Jan 2026 20:28:13 -0500 Subject: [PATCH] css and posts --- src/main.rs | 17 ++- static/home.typ | 26 +--- static/{posts/gamedev => network}/network.md | 0 static/{ => posts}/drone/graphing.jpg | Bin static/posts/drone/post.typ | 59 ++++++++ static/{ => posts}/drone/top.jpg | Bin static/posts/gamedev/phobos.md | 53 -------- static/posts/gamedev/post.typ | 2 + static/posts/gamedev/uav.md | 59 -------- static/{ => posts}/phobos/demo.mp4 | Bin static/posts/phobos/phobos.png | Bin 0 -> 23469 bytes static/posts/phobos/post.typ | 60 ++++++++ static/style.css | 136 ++++++++++++++++--- static/{posts/gamedev => }/work-history.md | 0 templates/base.html | 10 +- templates/post-preview.html | 11 +- templates/post.html | 2 - templates/posts.html | 2 +- 18 files changed, 264 insertions(+), 173 deletions(-) rename static/{posts/gamedev => network}/network.md (100%) rename static/{ => posts}/drone/graphing.jpg (100%) create mode 100644 static/posts/drone/post.typ rename static/{ => posts}/drone/top.jpg (100%) delete mode 100644 static/posts/gamedev/phobos.md delete mode 100644 static/posts/gamedev/uav.md rename static/{ => posts}/phobos/demo.mp4 (100%) create mode 100644 static/posts/phobos/phobos.png create mode 100644 static/posts/phobos/post.typ rename static/{posts/gamedev => }/work-history.md (100%) diff --git a/src/main.rs b/src/main.rs index 637d18f..9ef3abc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,10 +16,11 @@ fn load_posts() -> Result, Error> { let re_title = Regex::new(r#"#let\s+post_title\s*=\s*"([^"]*)""#).unwrap(); let re_summary = Regex::new(r#"#let\s+post_summary\s*=\s*"([^"]*)""#).unwrap(); + let re_img = Regex::new(r#"#let\s+post_preview_image\s*=\s*"([^"]*)""#).unwrap(); let mut posts: HashMap = HashMap::new(); for dir in dirs { - let typst_path = dir?.path().join("post.typ"); + let typst_path = dir.as_ref().unwrap().path().join("post.typ"); let typst = fs::read_to_string(typst_path).expect("Failed reading post"); let title = re_title.captures(&typst) .expect("Post title not found") @@ -27,16 +28,19 @@ fn load_posts() -> Result, Error> { let summary = re_summary.captures(&typst) .expect("Post summary not found") .get(1).unwrap().as_str().trim().to_string(); + let img = dir?.path().join( + re_img.captures(&typst) + .expect("Post preview image not found") + .get(1).unwrap().as_str().trim().to_string()); let slug = title.clone().replace(" ", "-").to_lowercase(); posts.insert( slug.clone(), Post { title: title.clone(), slug: slug, - preview_image: "NA".to_string(), + preview_image: img.to_str().expect("Failed converting path to string").to_string(), summary: summary, render: Html(PostTemplate { - title: title, content: typst_to_html(typst), }.render().expect("Failed rendering post")), } @@ -48,7 +52,6 @@ fn load_posts() -> Result, Error> { #[derive(Template)] #[template(path = "post.html")] struct PostTemplate { - title: String, content: String, } @@ -126,11 +129,7 @@ async fn main() { .route("/", get(home_html)) .route("/posts", get(posts_html)) .route("/posts/{title}", get(|title| get_post(title, posts))) - .nest_service("/static", ServeDir::new("static")) - // .with_state(posts) - ; - - + .nest_service("/static", ServeDir::new("static")); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); println!("Running on http://127.0.0.1:3000"); diff --git a/static/home.typ b/static/home.typ index 7670cdc..b1b036d 100644 --- a/static/home.typ +++ b/static/home.typ @@ -1,26 +1,14 @@ = About me +I enjoy competeing in capture the flag competitions (cybersecurity and the backyard game), working with robotics, automating tasks and thinking about problems. +I've competed in a few hackathons which are cool, but I prefer spending large time frames incrementally understand solutions to much larger problems, and attempting solutions to those. +I think automation is one of the most powerful abilities we have. As a species we are on the brink of mass automation, which can either liberate our lives into a post-scarcity utopia, or give a small percentage of us more control over the rest than anyone ever has had. +An odd and maybe abstract thing I enjoy is design philosphy. Some examples are creating software to building moral structures through logic to methods of learning new skills. +NixOS has to be my favourite distribution of Linux. My attraction to its design philosphy is that if something works, it will always work anywhere, and can still be worked on long after everything around it has moved on. Its hard to put into words but this feels like debian level stability with arch-like freedom to explore software. +When I'm not nerding out on math, software, ethics, and optimal ways of learning things, I manage to get outdoors. I like mountain biking through trails, snowboarding, hiking through scenic areas, swimming, and basketball. The next thing I'll be getting into is likely SCUBA diving. - - -Hey! I'm someone that likes to know my tools well. - -I also beleive in fairness and doing what is right. I'm frequently -= Skills - -= Hobbies -My free time is split into working on projects and touching grass. - - -= What I want to do -What I've found most interesting has to be the oppurtunities I get - - - -// Software engineering is a passion of mine, and people tend to reflect the things they do. -// My desktop and homelab run NixOS. I wrote this site in Rust, and add posts using Typst files. The whole thing is hosted on my gitea, and runs in a container defined by Nix. -// I wrote this myself. While AI communicates ideas better than I do, I want to ensure that my and only my thoughts are written. \ No newline at end of file +I wrote this myself. While AI communicates ideas better than I do, I want to ensure that my and only my thoughts are written. That is true for anything on this site. diff --git a/static/posts/gamedev/network.md b/static/network/network.md similarity index 100% rename from static/posts/gamedev/network.md rename to static/network/network.md diff --git a/static/drone/graphing.jpg b/static/posts/drone/graphing.jpg similarity index 100% rename from static/drone/graphing.jpg rename to static/posts/drone/graphing.jpg diff --git a/static/posts/drone/post.typ b/static/posts/drone/post.typ new file mode 100644 index 0000000..e90e67a --- /dev/null +++ b/static/posts/drone/post.typ @@ -0,0 +1,59 @@ +#let post_title = "Building a drone" +#let post_preview_image = "top.jpg" +#let post_summary = "Using a raspberry pi and 3d printer to build a drone from scratch" + += Building a Drone + +I chose to build a drone from scratch for my AP Physics final project. +We were given an open ended assignment to _build something cool_ +and I wanted a drone. My choice was much more ambitious than the course required, +and took quite a while to complete. + +For the drones frame I finally had an excuse to purchase a 3d printer. I +modelled the frame and arms modularly to support future upgrades and +replacements from damage, reducing the cost of operation. Initially I +was using some 3d printed torodial propellers due to their higher +efficiency and lower sounds usage. Due to safety concerns of the +propellers not withstanding tension at higher RPMs and exploding I +switched to some generic acrylic propellers I bought. A challenge in +designing the frame was leaving enough room to contain the volume of the +wires. I went with the Elegoo Neptune 3 as the printer was open-source +and had a much better cost-to-utility than proprietary printers such as +the Ender series. I am not sponsored I just really like the printer. + + +The flight computer was the most difficult part to program. Using an +ultrasonic distance sensor, gyroscope, and accelerometer the drone has +enough information to probably never crash. The autopilot is implemented +on an Arduino UNO using a +#link("https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller")[PID Controller] +for stabolization. The autopilot quality is currently impacted every time +the drones mass distribution changes, which can be fixed with a reinforcement +machine learning algorithm. For the higher level programming such as flight +automation, video transmission and WiFi communications I used a Raspberry +Pi Pico. There is also a 2.4GHz line of sight receiver for manual control. +A future upgrade may contain a SIM card for near-infinite remote control +connection, but drone regulations would make this difficult. + +The power system is the most physically challenging portion of the +drone. The motors took 14.6 Volts, while the UNO microcontroller took 5 +Volts, and the Pico and most sensors run at 3.3 Volts. All of the power +to the motors ran through the power distribution board, which I modified +to also output the lower voltages and used Bidirectional Logic Level +Converters to shift between 3.3 and 5V signals where needed. A potential +flaw with having all the power coming from the same source is spikes in +energy consumption to the motors may cause the microcomputers to receive +too little power, which could be fixed with a capacitor. Luckily, I +haven't experienced this yet as the 2C discharge rate on the 2.5Ah +capacity battery is more than enough. Having a battery this big does +mean it takes up about half the internal electronics volume and is half +of the drones mass, but it can also maintain full throttle for half an +hour making for long flights. + +The motors I used were a bit overkill for a 1.1kg drone, as going past +20% throttle sends it shooting through the sky, which is not a bad +issue to have. Here's the technical numbers behind that: I have +propellers with a 6cm radius on motors with a 2450KV rating (2450 rpm +per volt) and peaking at 14.6 Volts. From this the tip speed is ~225m/s +under no load at max throttle, quite a lot more than what +is safe or necessary to get into the air. diff --git a/static/drone/top.jpg b/static/posts/drone/top.jpg similarity index 100% rename from static/drone/top.jpg rename to static/posts/drone/top.jpg diff --git a/static/posts/gamedev/phobos.md b/static/posts/gamedev/phobos.md deleted file mode 100644 index e803bcf..0000000 --- a/static/posts/gamedev/phobos.md +++ /dev/null @@ -1,53 +0,0 @@ -

Phobos

-

- One of the coolest things I've developed is a game, fully written in - assembly.

- I say this because it is the perfect intersection of many things I enjoy; - low level programming, physics, space, simulation development, and game design. - Also small enough of a project that I could complete it in under a couple - of months, so another win. I even named the game based on the emulator, as - Phobos is a moon of Mars

The instructions for this - assignment were very broad, to develop a platformer game in assembly. - This left a lot of room for creative freedom, especially due to the - loose definition of platformer. With infinite time I would have - developed a whole rocket simulator, and used the justification that the - launchpad was a platform. -
-
On the technical side this was a very difficult project. There are - only about 16 variables actually usable in MIPS, and a lot of them are reserved - to specific logical controls under best practice. Then following the many - loops and recursive, real-time functionality required extensive and efficient - use of the stack. Ideally accessing a few bytes shouldn't strike the fear - of low framerates to mind, but the Mars-MIPS emulator I was using was far - from efficient. -

-

Notable Features

-
    -
  • Raycast collision detection and repositioning
  • -
  • Sub-pixel velocity and positioning
  • -
  • Awesome pixel graphics (the rocket shoots fire!)
  • -
  • High framerates (for a low-performance emulator)
  • -
  • Enemies shooting at you!
  • -
  • Loot pickups
  • -
-

- Probably the most annoying part of this was that the emulator couldn't - handle simutaineous key inputs. Fortunately I have over a thousand hours - experience landing rockets on the Mün - so I was comfortable giving a few unique key inputs per second. I never imagined - this is something I would be proud, and I still don't think I am. However, - it works.

At this point you may have realized I am a bit of a - space nerd. Enjoy this recording I made at 1am demonstrating the - features of my game to a TA, compressed to the point that the audio has - texture. -

-
- The - source code is also available - for your enjoyment. \ No newline at end of file diff --git a/static/posts/gamedev/post.typ b/static/posts/gamedev/post.typ index 30cb8c0..803ef69 100644 --- a/static/posts/gamedev/post.typ +++ b/static/posts/gamedev/post.typ @@ -1,6 +1,8 @@ #let post_title = "Game Dev" +#let post_preview_image = "flying.webp" #let post_summary = "Creating an open world multiplayer terrain destruction game in Godot and Rust" += Game Development I am currently developing an underground-submarine openworld multiplayer physics inspired game. As a gamer and enjoyer of large, rich maps and diff --git a/static/posts/gamedev/uav.md b/static/posts/gamedev/uav.md deleted file mode 100644 index 3c3ba14..0000000 --- a/static/posts/gamedev/uav.md +++ /dev/null @@ -1,59 +0,0 @@ -

Building a UAV

-

- I chose to build a drone from scratch for my AP Physics final project. - We were given an open ended assignment to build something cool - and I wanted a drone. My choice was much more ambitious than the course required, - and took quite a while to complete.

- - For the drones frame I finally had an excuse to purchase a 3d printer. I - modelled the frame and arms modularly to support future upgrades and - replacements from damage, reducing the cost of operation. Initially I - was using some 3d printed torodial propellers due to their higher - efficiency and lower sounds usage. Due to safety concerns of the - propellers not withstanding tension at higher RPMs and exploding I - switched to some generic acrylic propellers I bought. A challenge in - designing the frame was leaving enough room to contain the volume of the - wires. I went with the Elegoo Neptune 3 as the printer was open-source - and had a much better cost-to-utility than proprietary printers such as - the Ender series. I am not sponsored I just really like the printer.

- - The flight computer was the most difficult part to program. Using an - ultrasonic distance sensor, gyroscope, and accelerometer the drone has - enough information to probably never crash. The autopilot is implemented - on an Arduino UNO using a - PID controller - for stabolization. The autopilot quality is currently impacted every time - the drones mass distribution changes, which can be fixed with a reinforcement - machine learning algorithm. For the higher level programming such as flight - automation, video transmission and WiFi communications I used a Raspberry - Pi Pico. There is also a 2.4GHz line of sight receiver for manual control. - A future upgrade may contain a SIM card for near-infinite remote control - connection, but drone regulations would make this difficult.

- - The power system is the most physically challenging portion of the - drone. The motors took 14.6 Volts, while the UNO microcontroller took 5 - Volts, and the Pico and most sensors run at 3.3 Volts. All of the power - to the motors ran through the power distribution board, which I modified - to also output the lower voltages and used Bidirectional Logic Level - Converters to shift between 3.3 and 5V signals where needed. A potential - flaw with having all the power coming from the same source is spikes in - energy consumption to the motors may cause the microcomputers to receive - too little power, which could be fixed with a capacitor. Luckily, I - haven't experienced this yet as the 2C discharge rate on the 2.5Ah - capacity battery is more than enough. Having a battery this big does - mean it takes up about half the internal electronics volume and is half - of the drones mass, but it can also maintain full throttle for half an - hour making for long flights.

- - The motors I used were a bit overkill for a 1.1kg drone, as going past - 20% throttle sends it shooting through the sky -- which is not a bad - issue to have. Here's the technical numbers behind that: I have - propellers with a 6cm radius on motors with a 2450KV rating (2450 rpm - per volt) at peaking at 14.6 Volts. From this the tip speed is computed - to be ~225m/s under no load at max throttle, quite a lot more than what - is safe or necessary to get into the air. -

\ No newline at end of file diff --git a/static/phobos/demo.mp4 b/static/posts/phobos/demo.mp4 similarity index 100% rename from static/phobos/demo.mp4 rename to static/posts/phobos/demo.mp4 diff --git a/static/posts/phobos/phobos.png b/static/posts/phobos/phobos.png new file mode 100644 index 0000000000000000000000000000000000000000..2f933c9ccb2f7e7f659f931e24c24cdfd8691b3b GIT binary patch literal 23469 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 literal 0 HcmV?d00001 diff --git a/static/posts/phobos/post.typ b/static/posts/phobos/post.typ new file mode 100644 index 0000000..8d3c28f --- /dev/null +++ b/static/posts/phobos/post.typ @@ -0,0 +1,60 @@ +#let post_title = "Phobos" +#let post_preview_image = "phobos.png" +#let post_summary = "Making a rocket platformer in assembly" + += Phobos + +One of the coolest things I've developed is a game, fully written in +assembly. + + +I say this because it is the perfect intersection of many things I enjoy; +low level programming, physics, space, simulation development, and game design. +Also small enough of a project that I could complete it in under a couple +of months, so another win. I even named the game based on the emulator, as +Phobos is a moon of Mars. + +The instructions for this +assignment were very broad, to develop a platformer game in assembly. +This left a lot of room for creative freedom, especially due to the +loose definition of platformer. With infinite time I would have +developed a whole rocket simulator, and used the justification that the +launchpad was a platform. + +On the technical side this was a very difficult project. There are +only about 16 variables actually usable in MIPS, and a lot of them are reserved +to specific logical controls under best practice. Then following the many +loops and recursive, real-time functionality required extensive and efficient +use of the stack. Ideally accessing a few bytes shouldn't strike the fear +of low framerates to mind, but the Mars-MIPS emulator I was using was far +from efficient. + +=== Notable Features + +- Raycast collision detection and repositioning +- Sub-pixel velocity and positioning +- Awesome pixel graphics (the rocket shoots fire!) +- High framerates (for a low-performance emulator) +- Enemies shooting at you! +- Loot pickups + +Probably the most annoying part of this was that the emulator couldn't +handle simutaineous key inputs. Fortunately I have over a thousand hours +experience landing rockets on the #link("https://kerbalspaceprogram.fandom.com/wiki/Mun")[Mün] +so I was comfortable giving a few unique key inputs per second. I never imagined +this is something I would be proud, and I still don't think I am. However, +it works. + +At this point you may have realized I am a bit of a +space nerd. Enjoy this recording I made at 1am demonstrating the +features of my game to a TA, compressed to the point that the audio has +texture. + +//
+// The +// source code is also available +// for your enjoyment. diff --git a/static/style.css b/static/style.css index 8d2a921..db60427 100644 --- a/static/style.css +++ b/static/style.css @@ -12,18 +12,109 @@ text-align: center; } -header { - background-color: transparent; - border-bottom: 1px solid whitesmoke; - padding: 1rem 1rem; +#navbar { + display: flex; + background: #000; + border: 1px solid whitesmoke; + border-radius: 32px; + padding: 10px 20px; + margin: 0 auto; + width: 95%; + justify-content: space-between; + align-items: center; + + position: fixed; + top: 10; + left: 0; + right: 0; + z-index: 9999; } -nav { - display: flex; /* Aligns logo and menu horizontally */ - justify-content: space-between; /* Pushes logo to left, menu to right */ - align-items: center; - max-width: 1000px; - margin: 0 auto; /* Centers the header content */ +@keyframes hoverShadow { + 0% { + text-shadow: none; + box-shadow: none; + } + 50% { + text-shadow: + -6px -3px cornflowerblue, + 6px 3px orangered; + box-shadow: + -6px -3px cornflowerblue, + 6px 3px orangered; + } +} + +img { + width: 100%; + max-height: 400px; + object-fit: cover; +} + +.postpreview { + border: 1px solid whitesmoke; + border-radius: 32px; + margin: auto; + margin-top: 1rem; + margin-bottom: 1rem; + padding-bottom: 1rem; + background-color: linear-gradient(150deg, #222, #040404); + text-align: center; + +} + +.postpreview:hover { + /* border: 10px solid whitesmoke; + background-color: yellow; + font-size: 18px; */ + background-color: linear-gradient(330deg, #222, #040404); + animation: hoverShadow 0.4s linear ; +} + +a { + text-decoration: none; +} + +.hover-underline { + position: relative; + display: inline-block; +} + +.hover-underline::after, +.hover-underline::before { + content: ''; + position: absolute; + width: 100%; + height: 2px; + background: linear-gradient(to right, cornflowerblue, orangered); + bottom: -5px; + left: 0; + +.hover-underline::before { + top: -5px; + transform-origin: left; +} + transform: scaleX(0); + transform-origin: left; + transition: transform 0.2s linear; +} + +.hover-underline:hover::after, +.hover-underline:hover::before { + transform: scaleX(1); +} + +.content { + width: 80%; + margin: auto; +} + +.content p { + text-align: left; +} + +.content li { + text-align: left; } nav ul { @@ -34,18 +125,6 @@ nav ul { padding: 0; } -#name { - text-align: center; - font-size: 5rem; - margin: 20px; - padding: 0px; - animation: nameShadow 5s linear infinite; - letter-spacing: 2px; - color: whitesmoke; - font-family: "Ethnocentric", sans-serif; - transform: skewX(-20deg); -} - @keyframes nameShadow { 0% { text-shadow: none; @@ -57,7 +136,20 @@ nav ul { } } +#name { + font-size: 5rem; + margin: 20px; + padding: 0px; + animation: nameShadow 5s linear infinite; + letter-spacing: 2px; + color: whitesmoke; + font-family: "Ethnocentric", sans-serif; + transform: skewX(-20deg); + text-align: center; +} + body { min-height: 100vh; background-image: linear-gradient(330deg, #222, #040404); } + diff --git a/static/posts/gamedev/work-history.md b/static/work-history.md similarity index 100% rename from static/posts/gamedev/work-history.md rename to static/work-history.md diff --git a/templates/base.html b/templates/base.html index 4c3ff38..a1b1a00 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,17 +4,19 @@ + Jeremy Janella
-
-
+
{% block body %}{% endblock %}
diff --git a/templates/post-preview.html b/templates/post-preview.html index 7bff97f..ecbd8ab 100644 --- a/templates/post-preview.html +++ b/templates/post-preview.html @@ -1,4 +1,7 @@ -
-

{{ post.title }}

- {{ post.summary }} -
\ No newline at end of file + +
+

{{ post.title }}

+ + {{ post.summary }} +
+
\ No newline at end of file diff --git a/templates/post.html b/templates/post.html index b8949f4..0a14c63 100644 --- a/templates/post.html +++ b/templates/post.html @@ -2,8 +2,6 @@ {% block body %} -{{ title|safe }} - {{ content|safe }} {% endblock %} diff --git a/templates/posts.html b/templates/posts.html index 640ad43..c97ce4d 100644 --- a/templates/posts.html +++ b/templates/posts.html @@ -3,7 +3,7 @@ {% block body %} -
+
{% for post in posts %} {% include "post-preview.html" %} {% endfor %}