Compare commits

..
72 Commits
Author SHA1 Message Date
jjanella 625e064285 Merge remote-tracking branch 'refs/remotes/origin/main'
Build / build (push) Successful in 11s
2026-09-22 20:38:51 -04:00
jjanella b54e752cfb trigger rebuild 2026-09-22 20:38:36 -04:00
Jeremy Janella 2150e9a0cd updated home
Build / build (push) Successful in 9s
2026-08-19 20:59:58 -04:00
jjanella 48f643a45b font fix
Build / build (push) Successful in 7s
2026-07-30 00:39:13 -04:00
jjanella b79bfc78f0 pe2 and css
Build / build (push) Failing after 12m0s
2026-07-30 00:33:03 -04:00
jjanella c41ae4da75 fix-math
Build / build (push) Failing after 14m29s
2026-07-29 18:15:35 -04:00
jjanella 5ed08ed8ef project euclid problem 1 general solution
Build / build (push) Successful in 8s
2026-07-29 18:12:54 -04:00
jjanella c00fd5ac4f fix font
Build / build (push) Successful in 8s
2026-07-29 13:33:49 -04:00
jjanella 7a7cf24dad fixed post summary
Build / build (push) Successful in 9s
2026-07-29 11:54:31 -04:00
jjanella f840b25347 dynaimc vision post
Build / build (push) Successful in 5m51s
2026-07-29 11:43:05 -04:00
jjanella 758d9b234f Update static/infinite-vision/post.typ
Build / build (push) Successful in 7s
2026-07-28 16:59:56 -04:00
jjanella 98fd81bd01 scroll overflow
Build / build (push) Failing after 11m4s
2026-06-10 10:44:03 -04:00
jjanella 1b54a93d03 Line height update
Build / build (push) Successful in 7s
2026-06-10 10:41:50 -04:00
jjanella c61fec03da fixed missing link in tree
Build / build (push) Failing after 14m32s
2026-06-10 10:20:35 -04:00
jjanella d8c664b9e0 fix mobile line height and wrapping
Build / build (push) Failing after 11m27s
2026-06-10 10:18:40 -04:00
jjanella bce09e45c2 fix mobile tree view
Build / build (push) Failing after 13m40s
2026-06-10 10:01:27 -04:00
Jeremy Janella 9c38c61f56 updated treet spacing
Build / build (push) Failing after 13m22s
2026-06-10 09:01:31 -04:00
jjanella 007fe255c3 Update static/home.typ
Build / build (push) Failing after 10m55s
2026-05-27 16:14:14 -04:00
jjanella ee555c07bf Treet monospace bold
Build / build (push) Failing after 10m50s
2026-05-26 11:14:18 -04:00
Jeremy Janella f947049144 increased directness of profile
Build / build (push) Canceled after 48s
2026-05-26 04:54:31 -04:00
Jeremy Janella 21ea975ccc cleaned typst
Build / build (push) Failing after 13m11s
2026-05-24 16:31:51 -04:00
Jeremy Janella 2a84fafca6 ci remove typst devshell dep
Build / build (push) Successful in 4s
2026-05-24 12:31:48 -04:00
Jeremy Janella 852b625878 ci restart logs
Build / build (push) Canceled after 4m8s
2026-05-24 12:27:45 -04:00
Jeremy Janella a33430a4a8 ci sha256 fix
Build / build (push) Canceled after 8m4s
2026-05-24 12:19:46 -04:00
Jeremy Janella 91b6b46d4f ci fenix flake
Build / build (push) Canceled after 1m10s
2026-05-24 12:18:45 -04:00
Jeremy Janella 526cf942c8 ci push output
Build / build (push) Failing after 3s
2026-05-24 12:10:40 -04:00
Jeremy Janella 35b1f42a31 ci auto repo create
Build / build (push) Canceled after 1m17s
2026-05-24 12:09:21 -04:00
Jeremy Janella d498fceaa9 ci typst in env
Build / build (push) Canceled after 4m30s
2026-05-24 11:55:21 -04:00
Jeremy Janella 6dda0a2b62 ci env
Build / build (push) Canceled after 1m12s
2026-05-24 11:48:29 -04:00
Jeremy Janella 8cff5de85e ci env
Build / build (push) Canceled after 1m37s
2026-05-24 11:46:55 -04:00
Jeremy Janella 3e602844f8 ci env
Build / build (push) Canceled after 6m52s
2026-05-24 11:37:55 -04:00
Jeremy Janella c6c3f90f89 ci nix env
Build / build (push) Canceled after 4m26s
2026-05-24 11:33:08 -04:00
Jeremy Janella b0750c3c79 ci git conf
Build / build (push) Failing after 1s
2026-05-24 11:15:01 -04:00
Jeremy Janella 9b3ed7e034 ci setup
Build / build (push) Canceled after 1m10s
2026-05-24 11:13:47 -04:00
Jeremy Janella 84057a4434 ci debug
Build / build (push) Canceled after 45s
2026-05-24 11:10:27 -04:00
Jeremy Janella d48352ced2 ci debug
Build / build (push) Canceled after 14s
2026-05-24 11:02:56 -04:00
Jeremy Janella 800bd38adb ci switch to bare metal
Build / build (push) Canceled after 54s
2026-05-24 11:00:24 -04:00
Jeremy Janella 9734614396 ci test
Build / build (push) Canceled after 4m24s
2026-05-24 10:48:14 -04:00
Jeremy Janella 20c71c46ab ci test
Build / build (push) Failing after 14m42s
2026-05-24 10:10:23 -04:00
Jeremy Janella f1cbe1faf4 ci env
Build / build (push) Failing after 13m49s
2026-05-22 19:18:55 -04:00
Jeremy Janella 368f4d9ea6 flake update typst
Build / build (push) Failing after 11m3s
2026-05-22 18:49:01 -04:00
Jeremy Janella 3472a9ca77 ci fix
Build / build (push) Failing after 13m22s
2026-05-22 18:36:37 -04:00
Jeremy Janella 9363bff72c ci fix
Build / build (push) Failing after 14m54s
2026-05-22 18:27:47 -04:00
Jeremy Janella 6556cfd313 updated flake
Build / build (push) Canceled after 12m16s
2026-05-22 18:21:47 -04:00
Jeremy Janella 92696c31bc ci test
Build / build (push) Failing after 11m57s
2026-05-22 17:43:08 -04:00
Jeremy Janella 1125ef2d9e ci test
Build / build (push) Failing after 14m41s
2026-05-22 17:40:24 -04:00
Jeremy Janella e8dd33484a ci test
Build / build (push) Canceled after 10m18s
2026-05-22 17:22:59 -04:00
Jeremy Janella 06d77cc51b ci test
Build / build (push) Canceled after 1m11s
2026-05-22 17:22:49 -04:00
Jeremy Janella 8a5ddceef5 ci test
Build / build (push) Canceled after 3m34s
2026-05-22 17:16:03 -04:00
Jeremy Janella ce3a225c47 ci test
Build / build (push) Canceled after 4m0s
2026-05-22 17:08:05 -04:00
Jeremy Janella f8ffb0475c ci test
Build / build (push) Failing after 10m16s
2026-05-22 17:01:26 -04:00
Jeremy Janella 6dc840a3f7 ci test
Build / build (push) Failing after 0s
2026-05-22 15:18:36 -04:00
Jeremy Janella 70239a83cd ci test
Build / build (push) Failing after 0s
2026-05-22 15:16:34 -04:00
Jeremy Janella bdce9ba496 ci test
Build / build (push) Failing after 0s
2026-05-22 15:13:24 -04:00
Jeremy Janella 08f079b4e2 ci test
Build / build (push) Failing after 0s
2026-05-22 15:12:17 -04:00
Jeremy Janella dd4b41b3a7 ci test 2026-05-22 14:40:53 -04:00
Jeremy Janella f308864967 ci test
Build / build (push) Failing after 0s
2026-05-22 14:16:43 -04:00
Jeremy Janella 5e06dcfc15 ci test
Build / build (push) Failing after 0s
2026-05-22 14:09:03 -04:00
Jeremy Janella 6b73704925 ci test
Build / build (push) Failing after 0s
2026-05-22 14:07:23 -04:00
Jeremy Janella d9e0bb7b76 ci test
Build / build (push) Failing after 0s
2026-05-22 14:05:56 -04:00
Jeremy Janella bb3496584e ci test
Build / build (push) Failing after 0s
2026-05-22 14:02:25 -04:00
Jeremy Janella 1fb94729f4 ci test
Build / build (push) Failing after 0s
2026-05-22 13:59:29 -04:00
Jeremy Janella 03a8ac049c fixed bash path setup
Build / build (push) Failing after 0s
2026-05-22 08:44:46 -04:00
Jeremy Janella 1d740f4226 path fix for predator bash
Build / build (push) Failing after 0s
2026-05-22 08:39:29 -04:00
jjanella 03b84351d7 ip test
Build / build (push) Failing after 0s
2026-05-21 13:05:39 -04:00
jjanella 12060a97c6 ci config
Build / build (push) Failing after 0s
2026-05-21 13:03:58 -04:00
jjanella 971ef3dd1c updated runner name
Build / build (push) Failing after 0s
2026-05-21 12:57:22 -04:00
jjanella af6076a24c Merge remote-tracking branch 'refs/remotes/origin/main'
Build / build (push) Canceled after 0s
2026-05-21 12:45:46 -04:00
jjanella cce76ffdc0 profile update 2026-05-21 12:44:43 -04:00
jjanella a06f527398 Update static/home.typ
Build / build (push) Successful in 2s
2026-02-23 01:47:53 +00:00
jjanella 66f839a6b7 Merge remote-tracking branch 'refs/remotes/origin/main'
Build / build (push) Successful in 4s
2026-02-21 23:01:19 -05:00
jjanella 62463c2f61 source 2026-02-21 23:00:52 -05:00
15 changed files with 571 additions and 80 deletions
+22 -7
View File
@@ -6,23 +6,38 @@ on:
pull_request:
branches: [main]
defaults:
run:
shell: /bin/sh -e {0}
env:
PATH: /run/current-system/sw/bin:/run/wrappers/bin:/usr/bin:/bin
jobs:
build:
runs-on: self-hosted
runs-on: homelab
steps:
- name: Configure git
run: git config --global --add safe.directory /servers/site
- name: Create repo
run: |
[ ! -d /servers/site ] && git clone https://git.jeremyjanella.com/jjanella/site.git /servers/site || true
- name: Pull
working-directory: /opt/site
working-directory: /servers/site
run: git pull origin main
- name: Build
working-directory: /opt/site
run: cargo build --release
working-directory: /servers/site
run: |
nix develop --command cargo build --release 2>&1
- name: Restart site
working-directory: /opt/site
working-directory: /servers/site
run: |
pkill site || true
export RUNNER_TRACKING_ID=self-managed
nohup ./target/release/site > server.log 2>&1 &
setsid ./target/release/site > server.log 2>&1 &
sleep 1
pgrep site && echo "Site is running!"
Generated
+117
View File
@@ -0,0 +1,117 @@
{
"nodes": {
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1779612045,
"narHash": "sha256-+7lfNVnmXJDkiRYHd5NoNwYoyUcc0LcXPaIJqjO7VWM=",
"owner": "nix-community",
"repo": "fenix",
"rev": "d7be747f0a65af378de515fc3cee131bf99a008f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1779508470,
"narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29916453413845e54a65b8a1cf996842300cd299",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1785090369,
"narHash": "sha256-m0pDuRJG7EDo9ri+4Ksu83VsI+PlxNC9lNBfydejce4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "624af665418d3c65d544145b4d34ad696439570e",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"fenix": "fenix",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1779569060,
"narHash": "sha256-NSnk5D+3KEfRdbgPijs33N2RAKSG6A74SwfnynLcouo=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "987ea33645ab1c709b1df6823038abcb2fe8973e",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+43
View File
@@ -0,0 +1,43 @@
{
description = "Rust development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils, fenix }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
toolchain = fenix.packages.${system}.fromToolchainFile {
file = ./rust-toolchain.toml;
sha256 = "sha256-A1abGIbOtcBSdrUMhDGrER3pRM1hQP4fp9gh3Y4PKc8=";
};
in
{
devShells.default = pkgs.mkShell rec {
nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = with pkgs; [
toolchain
llvmPackages.bintools
clang
nixpkgs-unstable.legacyPackages.${pkgs.system}.typst
];
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') []);
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (buildInputs ++ nativeBuildInputs);
BINDGEN_EXTRA_CLANG_ARGS =
(builtins.map (a: ''-I"${a}/include"'') [ pkgs.glibc.dev ])
++ [
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
''-I${pkgs.glib.out}/lib/glib-2.0/include/''
];
};
}
);
}
-48
View File
@@ -1,48 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
let
overrides = (builtins.fromTOML (builtins.readFile ./rust-toolchain.toml));
libPath = with pkgs; lib.makeLibraryPath [
# load external libraries that you need in your rust project here
];
in
pkgs.mkShell rec {
nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = with pkgs; [
clang
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16)
llvmPackages.bintools
rustup
typst
];
RUSTC_VERSION = overrides.toolchain.channel;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
shellHook = ''
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
'';
# Add precompiled library to rustc search path
RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [
# add libraries here (e.g. pkgs.libvmi)
]);
LD_LIBRARY_PATH = libPath;
# Add glibc, clang, glib, and other headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
# Includes normal include path
(builtins.map (a: ''-I"${a}/include"'') [
# add dev libraries here (e.g. pkgs.libvmi.dev)
pkgs.glibc.dev
])
# Includes with special directory paths
++ [
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
''-I${pkgs.glib.out}/lib/glib-2.0/include/''
];
}
+3 -2
View File
@@ -3,8 +3,6 @@ use axum::{
};
use tower_http::services::ServeDir;
use askama::Template;
// use typst::model;
// use typst_html;
use std::{collections::HashMap, fs, io::{Error, Write}, process::{Command, Stdio}};
use regex::Regex;
@@ -117,6 +115,9 @@ async fn get_post(
#[tokio::main]
async fn main() {
// unsafe {
// std::env::set_var("TYPST_FEATURES", "html");
// }
let home_html = Html(
HomeTemplate {
+74 -11
View File
@@ -1,17 +1,80 @@
#import "@preview/treet:1.0.0": *
#show list: set text(font: "DejaVu Sans Mono", weight: "bold")
= About me
I enjoy competing in capture the flag competitions (cybersecurity and the backyard game), working with robotics, automating tasks and thinking through problems.
Computer Science student at the University of Toronto with experience in cybersecurity, firmware, low-level development and software engineering. Interested in deep technical work, solutions architecting. A continuous learner interested in owning problems, researching and implementing solutions.
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.
// === What can I do
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 philosophy. 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 philosophy 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.
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.
=== Interests & Skills
#html.elem("div", attrs: (class: "tree"))[
#tree-list(
indent: "│ ",
empty-indent: " "
)[
- Research
- Computer Science
- Linux
- Nix & NixOS
- Perfectly reproducible, time independent environments
- IoT / microcomputers & microcontrollers
- Hosting servers
- Docker
- Nix OCI images
- Cyber security
- Reverse engineering assembly
- Binary patching
- Anticheat
- CTF's
- CompTIA PenTest+ certified
- AI exploitation
- Tricking image classifiers
- Prompt injection techniques
- Extracting sensitive data with statistics
- Side channel attacks
- Van Eck Phreaking / TEMPEST
- RF Sensing
- SPECTRE
- OSINT
- Machine learning & algorithms
- UTAT Satellite Firmware Development
- Automation
- Robotics
- Programming and computing paths & trajectories etc
- AI - how much can this actually do, when orchestrated into a full platform?
- Langchain
- Random conjectures & problems
- Collatz Conjecture
- Travelling salesman
- Graph Reconstruction
- Math
- Stats
- Philosophy
- Ethics
- Development
- Infrastructure
- Programming
- Rust
- C/C++
- Python
- Bash
- Assembly
- Functional
- Object Oriented
- Design patterns
- SQL
- GDScript
- Game development - problem solving outlet
- Multiplayer Architecture
- Data transfer optimization
- Security
- High performance code
- Touching grass
- Mountain biking - especially technical trails
- Hiking
- Snowboarding
- Swimming (Used to lifeguard & teach lessons!)
]
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

+126
View File
@@ -0,0 +1,126 @@
#let post_slug = "dynamic-vision-shader"
#let post_preview_image = "image2.png"
#let post_summary = "Improvements to Orebit's dynamic vision"
#let post_date = "2026-07-28"
#import "@preview/cetz:0.5.2"
#import "@preview/cetz-plot:0.1.4"
#let stroke_color = white
#let canvas_style = (
circle: (fill: stroke_color),
stroke: stroke_color,
)
= Dynamic Vision
== The problem
In 3d, objects occlude your vision, and you cannot see behind them. This isn't really implemented in most 2D games as it can be disorienting, confusing, and therefore unnecessary.
For Orebit, disorientation is a mechanic. Careless piloting in unfamiliar territory may cost the player a collision with the terrain or hostiles. Lack of spatial awareness can make it hard to detect your neighbors, which is great for hiding from potential enemies. As much of the players time is underground, the claustrophobia induced by occluding vision is also useful. With this in mind, it adds to the immersion to not know what lies around corners, and dynamic 2D vision is necessary.
== Solution 1
Lighting mechanics can simulate dynamic vision, using darkness to represent hidden areas. First, the whole world needs to be dark. Then, emit light where the player should be able to see. Objects with light occluders on cast shadows, which effectively blocks vision behind objects like terrain.
In Godot, this is implemented by applying a black CanvasModulate node to a scene to create darkness. Objects with collision polygons can reuse their polygon in a light occluder. PointLights using a circular texture can emit light around the character.
#image("/static/posts/dynamic-vision/image.png")
== Solution 1 Flaws
The world in Orebit is massive, which becomes a problem when trying to light the entire area. The radius of the circular texture used must be at least as large as the farthest point visible, which can be tens of thousands of pixels away. This means a texture tens of thousands of pixels squared (for the x and y axis) must be used, which severely impacts performance even on high end hardware.
The solution to this is to scale up a lower resolution light texture, but this has its own issues. The texture is made of discrete pixels, each one black or white if it is occluded or not occluded. As these pixels scale the shadow edges go from smooth, high resolution edges to pixelated, jagged edges. The other problem with scaling light maps is that light clips through objects close to the light source.
== Solution 2
Another way to understand the problem is to think of every vision-occluding polygon as a set of vision-occluding line segments, ie $overline(A B)$.
#set text(fill: stroke_color)
#html.frame(
align(center,
cetz.canvas({
import cetz.draw: *
set-style(..canvas_style)
circle((0, 6), radius: (0.1), name: "C")
line((1, 4), "C", (2, 5), stroke: (dash: "dashed"))
line((0, 2), (2, 2), (3, 4), (2, 5), (1, 4), (0, 4), (-1, 3), (0, 2))
line((2,5), (1, 4), name: "AB", stroke: (paint: blue, thickness: 4pt))
content("AB", $ overline(A B) $, anchor: "south-east", padding: .2)
})))
#set text(fill: black)
Each line segment occludes a quad (a shape with four vertices) composed of one point on each end of the line segment, and another point at each line end projected away from the character.
$
d & >> 1\
p_1 &= A\
p_2 &= C + d (A-C)\
p_3 &= C + d (B-C)\
p_4 &= B\
$
#set text(fill: stroke_color)
#html.frame(
align(center,
cetz.canvas({
import cetz.draw: *
set-style(..canvas_style)
circle((0, 6), radius: (0.1), name: "C")
content("C", $ C $, anchor: "east", padding: .2)
circle((2, 5), radius: (0.1), name: "A")
content("A", $ p_1 $, anchor: "south-west", padding: .2)
circle((1, 4), radius: (0.1), name: "B")
content("B", $ p_4 $, anchor: "north-east", padding: .2)
circle((6, 3), radius: (0.1), name: "p2")
content("p2", $ p_2 $, anchor: "west", padding: .2)
circle((3, 0), radius: (0.1), name: "p3")
content("p3", $ p_3 $, anchor: "north", padding: .2)
line((0, 2), (2, 2), (3, 4), (2, 5), (1, 4), (0, 4), (-1, 3), (0, 2))
// circle((2, 5), radius: (0.08), fill: black, name: "p1")
line((2, 5), (6, 3), (3, 0), (1, 4),
fill: rgb(50, 50, 255, 100),
stroke: 0pt
)
line("A", "C", "B", stroke: (dash: "dashed"))
// content((0, 2), $ p_1 $, anchor: "south", padding: .2)
})))
#set text(fill: black)
Solution 2 can be implemented in Godot using ImmediateMesh's for each line in the polygon, with two triangles composing each quad for each line in the occluders polygon. Setting vertex color allows the shader to differentiate which vertices to project away from the character.
To update the mesh each frame, a shader on the ImmediateMesh can take the line segment and live character position. Despite running on thousands of line segments, the ImmediateMesh and gpu-shader exist to efficiently solve problems like this.
```glsl
shader_type canvas_item;
# use the global coordinate system
render_mode world_vertex_coords;
# updated each physics frame
uniform vec2 character_position;
void vertex() {
if (COLOR.r > 0.5) {
VERTEX = VERTEX + (1e6 * (VERTEX - character_position));
}
}
```
(Solution 1 overlaid on solution 2)
#image("/static/posts/dynamic-vision/image2.png")
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

+71
View File
@@ -0,0 +1,71 @@
#let post_slug = "pe-p1"
#let post_preview_image = "image.png"
#let post_summary = "General solution to Project Euler Problem 1"
#let post_date = "2026-07-29"
= Project Euler Problem 1
== Statement
If we list all the natural numbers below $10$ that are multiples of $3$ or $5$, we get $3, 5, 6,$ and $9$. The sum of these multiples is $23$. Find the sum of all the multiples of $3$ or $5$ below $1000$.
== Solution
Suppose the base numbers were $2$ and $3$ below $10$ so $9$, they would create duplicates, ie $6$ is counted twice. Therefore take the sum of each multiple to the limit, and one time remove the numbers counted twice:
#text(fill: white, html.frame(
$
&2+4+6+8+3+cancel(6)+9 = 32\
&sum_(i=1)^(floor(9/(2)))2i + sum_(i=1)^(floor(9/(3))) 3i - sum_(i=1)^(floor(9/(6))) 6i \
= 2&sum_(i=1)^(floor(9/(2)))2i + 3sum_(i=1)^(floor(9/(3))) i - 6sum_(i=1)^(floor(9/(6))) i \
= 2&sum_(i=1)^4 i + 3sum_(i=1)^3 i - 6sum_(i=1)^(1) i\
= 2& (4(5))/2 + 3 (3(4))/2 - 6 (1(2))/2\
= 3&2
$
))
This revealed a general solution, for base numbers $n, m$ below $L$:
#text(fill: white, html.frame(
$
f(n,m,L) =&n sum_(i=1)^floor((L-1)/n) i + m sum_(i=1)^floor((L-1)/m) i- n m sum_(i=1)^floor((L-1)/(n m))i \
"Define "&a = floor((L-1)/n), b = floor((L-1)/m), c = floor((L-1)/(n m)) \
=> f(n,m,L) =& (n a(a+1) + m b(b+1) - n m (c)(c+1))/2
$
))
Testing this as code:
```py
>>> def f(n,m,L):
... a = floor((L-1)/n)
... b = floor((L-1)/m)
... c = floor((L-1)/(n*m))
... return ((n*a*(a+1)) + (m*b*(b+1)) - (n*m*c*(c+1)))/2
...
>>> f(2,3,10)
44.0
>>> f(3,5,10)
23.0
```
This general solution passes the two tests above.
```py
>>> f(3,5,1000)
233168.0
```
Testing against the question, this result is successful. But what about for more than 2 numbers? How can this be approached?
Given a set $A$ of base numbers, a multiple would be counted once for each of its divisors present in $A$.
An easy solution is that in code, a hashmap could track the number of times each number is counted, and iteratively remove duplicates.
The goal is to not add the number if it was already added.
Mathamatically this can be done piecewise. If a previous element of $A$ divides $A_i k$, skip that number.
#text(fill: white, html.frame(
$
f(A, L) = sum_(i)^abs(A)[sum_(k=1)^floor((L-1)/A_i) cases(0 quad & A_j divides A_i k and j < k, A_i k quad & A_j divides.not A_i k and j < k)]
$
))
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

+79
View File
@@ -0,0 +1,79 @@
#let post_slug = "pe-p2"
#let post_preview_image = "image.png"
#let post_summary = "Solution to Project Euler Problem 2"
#let post_date = "2026-07-29"
#set math.mat(delim: "[")
= Project Euler Problem 2
== Statement
Each new term in the Fibonacci sequence is generated by adding the previous two terms.
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
== Exploration
The even terms in the sequence are:
#text(fill: white, html.frame(
$ cal(F) = {0, cancel(1), cancel(1), 2, cancel(3), cancel(5), 8, cancel(13), cancel(21), 34, cancel(55), ...} $
))
This can be computed quickly with code, some Fibonacci sequence equations would be interesting to derive.
Notice every 3rd number is even, as the previous two numbers are odd, which sums to even. A similar statement can be said about the odd numbers.
The Fibonacci sequence can be generated with the equation:
#text(fill: white, html.frame(
$ mat(cal(F)_i; cal(F)_(i+1)) = mat(0, 1; 1, 1) mat(cal(F)_(i-1); cal(F)_i) $
))
Then every third number can be defined with the equation:
#text(fill: white, html.frame(
$
&mat(cal(F)_(i+2); cal(F)_(i+3)) = mat(0, 1; 1, 1)^3 mat(cal(F)_(i-1); cal(F)_i)\
=>&mat(cal(F)_(i+2); cal(F)_(i+3)) = mat(1, 2; 2, 3) mat(cal(F)_(i-1); cal(F)_i)
$
))
Also something interesting I noticed for #text(fill: white, html.frame($cal(F) = {0, 1, 1, 2, 3, 5, 8, ...} (cal(F)_0 = 0, i>= 1)$)) is:
#text(fill: white, html.frame(
$
mat(0, 1; 1, 1)^i = mat(cal(F)_(i-1), cal(F)_(i); cal(F)_(i), cal(F)_(i+1))
$
))
Playing with that leads to the similar equation
#text(fill: white, html.frame(
[$cal(F)_(i+j) = cal(F)_(i) cal(F)_(j+1) + cal(F)_(i-1) cal(F)_(j)$,\ thus $cal(F)_(i+3) = 3cal(F)_i + 2cal(F)_(i-1)$]
))
An equation to represent this problem is as follows, however this would need a computer to finish in reasonable time.
#text(fill: white, html.frame(
$
sum_(i=1)^(n: cal(F)_(3n)<4 times 10^6) cal(F)_(3i)
$
))
== Solution
Since every third number is even, take each third element of the sequence until four million. Three step jumps can be taken as defined by the matrix above.
```py
>>> class Pair:
... def __init__(self, fi_m1, fi):
... self.fi_m1 = fi_m1
... self.fi = fi
>>> def f_3(pair):
... return Pair(
... pair.fi_m1 + (2 * pair.fi),
... (2 * pair.fi_m1) + (3 * pair.fi)
... )
>>> x = Pair(1, 2)
>>> s = 0
>>> while x.fi < 4e6:
... s += x.fi
... x = f_3(x)
>>> print(s)
4613732
```
+35 -11
View File
@@ -12,6 +12,15 @@
text-align: center;
}
.post a {
text-decoration: underline;
color:orangered;
}
.post * {
text-align: left;
}
#navbar {
display: flex;
background: #000;
@@ -73,6 +82,21 @@ a {
text-decoration: none;
}
math * {
font-family: serif;
}
.multiline-equation {
text-align: center;
margin-left: 50%;
margin-right: 50%;
}
svg {
margin: auto;
}
.hover-underline {
position: relative;
display: inline-block;
@@ -114,15 +138,6 @@ a {
margin-top: 3.5rem;
}
.post a {
text-decoration: underline;
color:orangered;
}
.post * {
text-align: left;
}
pre {
overflow-x: auto;
background-color: #000;
@@ -130,7 +145,7 @@ pre {
padding: 2pt;
}
code {
code, pre code span {
font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", "Source Code Pro", monospace;
font-variant-ligatures: normal;
white-space: pre;
@@ -144,12 +159,16 @@ code {
max-width: 1000px;
}
nav ul {
#navbar ul li:last-child {
margin-left: auto;
}
#navbar ul {
list-style: none;
display: flex;
gap: 20px;
margin: 0;
padding: 0;
width: 100%;
}
@keyframes nameShadow {
@@ -180,3 +199,8 @@ body {
background-image: linear-gradient(330deg, #222, #040404);
}
.tree {
font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", "Source Code Pro", monospace;
line-height: 1.05;
overflow-x: scroll;
}
+1 -1
View File
@@ -12,7 +12,7 @@
<ul>
<li><a class="hover-underline" href="/">Home</a></li>
<li><a class="hover-underline" href="/posts">Posts</a></li>
<!-- <li><a>Contact</a></li> -->
<li><a class="hover-underline" href="https://git.jeremyjanella.com/jjanella/site">Source</a></li>
</ul>
</nav>
</header>