diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index d9418e9a..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,253 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (8.0.2) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) - base64 (0.2.0) - benchmark (0.4.0) - bibtex-ruby (6.1.0) - latex-decode (~> 0.0) - racc (~> 1.7) - bigdecimal (3.1.9) - citeproc (1.1.0) - date - forwardable - json - namae (~> 1.0) - observer (< 1.0) - open-uri (< 1.0) - citeproc-ruby (1.1.14) - citeproc (~> 1.0, >= 1.0.9) - csl (~> 1.6) - colorator (1.1.0) - concurrent-ruby (1.3.5) - connection_pool (2.5.0) - csl (1.6.0) - namae (~> 1.0) - rexml - csl-styles (1.0.1.11) - csl (~> 1.0) - csv (3.3.3) - date (3.4.1) - drb (2.2.1) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - eventmachine (1.2.7) - faraday (2.12.2) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.0) - net-http (>= 0.5.0) - ffi (1.17.1-aarch64-linux-gnu) - ffi (1.17.1-aarch64-linux-musl) - ffi (1.17.1-arm-linux-gnu) - ffi (1.17.1-arm-linux-musl) - ffi (1.17.1-arm64-darwin) - ffi (1.17.1-x86_64-darwin) - ffi (1.17.1-x86_64-linux-gnu) - ffi (1.17.1-x86_64-linux-musl) - forwardable (1.3.3) - forwardable-extended (2.6.0) - gemoji (4.1.0) - google-protobuf (4.30.1) - bigdecimal - rake (>= 13) - google-protobuf (4.30.1-aarch64-linux) - bigdecimal - rake (>= 13) - google-protobuf (4.30.1-arm64-darwin) - bigdecimal - rake (>= 13) - google-protobuf (4.30.1-x86_64-darwin) - bigdecimal - rake (>= 13) - google-protobuf (4.30.1-x86_64-linux) - bigdecimal - rake (>= 13) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.14.7) - concurrent-ruby (~> 1.0) - jekyll (4.4.1) - addressable (~> 2.4) - base64 (~> 0.2) - colorator (~> 1.0) - csv (~> 3.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (>= 2.0, < 4.0) - jekyll-watch (~> 2.0) - json (~> 2.6) - kramdown (~> 2.3, >= 2.3.1) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.3, >= 0.3.6) - pathutil (~> 0.9) - rouge (>= 3.0, < 5.0) - safe_yaml (~> 1.0) - terminal-table (>= 1.8, < 4.0) - webrick (~> 1.7) - jekyll-archives (2.3.0) - jekyll (>= 3.6, < 5.0) - jekyll-data (1.1.1) - jekyll (>= 3.3, < 5.0.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-paginate (1.1.0) - jekyll-sass-converter (3.1.0) - sass-embedded (~> 1.75) - jekyll-scholar (7.1.3) - bibtex-ruby (~> 6.0) - citeproc-ruby (~> 1.0) - csl-styles (~> 1.0) - jekyll (~> 4.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jekyll-webp (1.0.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - json (2.10.2) - kramdown (2.5.1) - rexml (>= 3.3.9) - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - latex-decode (0.4.0) - liquid (4.0.4) - listen (3.9.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.6) - mercenary (0.4.0) - minimal-mistakes-jekyll (4.26.2) - jekyll (>= 3.7, < 5.0) - jekyll-feed (~> 0.1) - jekyll-gist (~> 1.5) - jekyll-include-cache (~> 0.1) - jekyll-paginate (~> 1.1) - jekyll-sitemap (~> 1.3) - minitest (5.25.5) - namae (1.2.0) - racc (~> 1.7) - net-http (0.6.0) - uri - nokogiri (1.18.5-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.5-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.18.5-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.5-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.18.5-arm64-darwin) - racc (~> 1.4) - nokogiri (1.18.5-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.18.5-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.5-x86_64-linux-musl) - racc (~> 1.4) - observer (0.1.2) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) - open-uri (0.5.0) - stringio - time - uri - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (6.0.1) - racc (1.8.1) - rake (13.2.1) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) - rexml (3.4.1) - rouge (4.5.1) - safe_yaml (1.0.5) - sass-embedded (1.86.0-aarch64-linux-gnu) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-aarch64-linux-musl) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-arm-linux-gnueabihf) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-arm-linux-musleabihf) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-arm64-darwin) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-x86_64-darwin) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-x86_64-linux-gnu) - google-protobuf (~> 4.30) - sass-embedded (1.86.0-x86_64-linux-musl) - google-protobuf (~> 4.30) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - stringio (3.1.5) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - time (0.4.1) - date - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unicode-display_width (2.6.0) - uri (1.0.3) - webrick (1.9.1) - -PLATFORMS - aarch64-linux - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-gnueabihf - arm-linux-musl - arm-linux-musleabihf - arm64-darwin - x86_64-darwin - x86_64-linux-gnu - x86_64-linux-musl - -DEPENDENCIES - http_parser.rb (~> 0.6.0) - jekyll - jekyll-archives - jekyll-data - jekyll-include-cache - jekyll-scholar - jekyll-webp - jemoji - json - minimal-mistakes-jekyll - tzinfo (>= 1, < 3) - tzinfo-data - wdm (~> 0.1.1) - -BUNDLED WITH - 2.6.6 diff --git a/content/research/2024-01-13-aquarium-marl-environment.mdx b/content/research/2024-01-13-aquarium-marl-environment.mdx index 1624b550..7ca557bd 100644 --- a/content/research/2024-01-13-aquarium-marl-environment.mdx +++ b/content/research/2024-01-13-aquarium-marl-environment.mdx @@ -1,12 +1,27 @@ --- title: "Aquarium MARL Environment" -tags: [multi-agent-reinforcement-learning, MARL, simulation, emergence, complex-systems] +tags: [MARL, simulation, emergence, complex-systems, environment] excerpt: "Aquarium: Open-source MARL environment for predator-prey studies." teaser: /figures/20_aquarium.png --- + The study of complex interactions using Multi-Agent Reinforcement Learning (MARL), particularly **predator-prey dynamics**, often requires specialized simulation environments. To streamline research and avoid redundant development efforts, we introduce **Aquarium**: a versatile, open-source MARL environment specifically designed for investigating predator-prey scenarios and related **emergent behaviors**. + Key Features of Aquarium: @@ -17,15 +32,13 @@ Key Features of Aquarium: * **Environmental Parameters:** Key dynamics like agent speeds, prey reproduction rates, predator starvation mechanisms, sensor ranges, and more are fully adjustable. * **Visualization & Recording:** Includes a resource-efficient visualizer and supports video recording of simulation runs, facilitating qualitative analysis and understanding of agent behaviors. -
-
- Diagram detailing the construction of the observation vector for an agent -
Construction details of the agent observation vector.
-
-
- Graphs showing average captures or rewards per prey agent under different training regimes -
Performance metrics (e.g., average captures/rewards) comparing training strategies.
-
-
+ -To demonstrate its capabilities, we conducted preliminary studies using **Proximal Policy Optimization (PPO)** to train multiple prey agents learning to evade a predator within Aquarium. Consistent with findings in existing MARL literature, our results showed that training agents with **individual policies led to suboptimal performance**, whereas utilizing **parameter sharing** among prey agents significantly improved coordination, sample efficiency, and overall evasion success. \ No newline at end of file +To demonstrate its capabilities, we conducted preliminary studies using **Proximal Policy Optimization (PPO)** to train multiple prey agents learning to evade a predator within Aquarium. Consistent with findings in existing MARL literature, our results showed that training agents with **individual policies led to suboptimal performance**, whereas utilizing **parameter sharing** among prey agents significantly improved coordination, sample efficiency, and overall evasion success. diff --git a/src/app/connect/page.tsx b/src/app/connect/page.tsx new file mode 100644 index 00000000..a95579ea --- /dev/null +++ b/src/app/connect/page.tsx @@ -0,0 +1,71 @@ +import { DATA } from "@/data/resume"; +import Image from "next/image"; +import Link from "next/link"; +import BlurFade from "@/components/magicui/blur-fade"; +import { Button } from "@/components/ui/button"; +import { CenteredImage } from "@/components/centered-image"; + +const BLUR_FADE_DELAY = 0.05; + +export default function ConnectPage() { + const featuredSocials = ["Email", "LinkedIn", "GoogleScholar", "arXiv", "ResearchGate", "Gitea"]; + const socialLinks = Object.entries(DATA.contact.social) + .filter(([name]) => featuredSocials.includes(name)); + + return ( +
+
+ + + Dr. Steffen Illium's headshot + + + +

+ Dr. Steffen Illium +

+
+ + +
+ {socialLinks.map(([name, social]) => ( + + + + ))} +
+
+ +
+ +
+
+ + + + QR Code to connect + + +
+ +
+
+ ); +} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 456d957c..3e7cb819 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,7 +8,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import { DATA } from "@/data/resume"; import Markdown from "react-markdown"; -import {ContactCard} from "@/components/contact-card"; +//import {ContactCard} from "@/components/contact-card"; import {Button} from "@/components/ui/button"; import Link from "next/link"; @@ -170,34 +170,34 @@ export default function Page() {
-
- -
-
- Contact -
-

Get in Touch

-

- Want to collaborate or have a question?
I'd love to hear from you. -

+
+ +
+
+ Contact
- - -
- {Object.entries(DATA.contact.social) - .filter(([_, social]) => social.navbar) - .map(([name, social]) => ( - - - - {name} - - - ))} +

Get in Touch

+

+ Want to collaborate or have a question?
I'd love to hear from you. +

-
+ + +
+ {Object.entries(DATA.contact.social) + .filter(([_, social]) => social.navbar) + .map(([name, social]) => ( + + + + {name} + + + ))}
-
+ + + ); } diff --git a/src/components/Article.tsx b/src/components/Article.tsx index 619a3de6..45abcd3d 100644 --- a/src/components/Article.tsx +++ b/src/components/Article.tsx @@ -3,10 +3,11 @@ import { CitationProvider } from '@/context/citation-context'; import { ReferencesContainer } from '@/components/references-container'; import { CustomMDX } from '@/components/custom-mdx'; +import { Breadcrumbs } from "./breadcrumbs"; import Link from 'next/link'; import { Publication } from '@/lib/publications'; import { ProjectNavigation } from './project-navigation'; -// --- FIX: Import the Image component --- +import { Tag } from 'lucide-react'; import Image from 'next/image'; interface Post { @@ -16,8 +17,8 @@ interface Post { excerpt?: string; teaser?: string; tags?: string[]; - // --- FIX: Add the optional 'icon' property to the interface --- icon?: string; + date?: string; }; } @@ -32,45 +33,70 @@ interface ArticleProps { export function Article({ post, publications, navigation, basePath }: ArticleProps) { return ( -
-
-
-

{post.frontmatter.title}

- {post.frontmatter.excerpt && (

{post.frontmatter.excerpt}

)} -
- - {post.frontmatter.icon && ( -
- {`${post.frontmatter.title} +
+
+
+ + {/* MOVED: The date is now on the right side of the container */} + {post.frontmatter.date && ( + + )}
- )} +
+

+ {post.frontmatter.title} +

+ {post.frontmatter.excerpt && ( +

+ {post.frontmatter.excerpt} +

+ )} +
+
+ {post.frontmatter.icon && ( +
+ {`${post.frontmatter.title} +
+ )} + + +
-
- + {/* Tags, References, and Navigation now live outside the `prose` scope for better control */} + {post.frontmatter.tags && ( +
+ + {post.frontmatter.tags.map((tag: string) => ( + + {tag} + + ))} +
+ )} + + + + {navigation && ( + + )}
- - {post.frontmatter.tags && ( -
- {post.frontmatter.tags.map((tag: string) => ( - - {tag} - - ))} -
- )} - - - - {navigation && ( - - )} -
+
); diff --git a/src/components/breadcrumbs.tsx b/src/components/breadcrumbs.tsx new file mode 100644 index 00000000..b41c493d --- /dev/null +++ b/src/components/breadcrumbs.tsx @@ -0,0 +1,21 @@ +import { ChevronRight, HomeIcon } from "lucide-react"; +import Link from "next/link"; + +interface BreadcrumbsProps { + basePath: string; + baseLabel: string; +} + +export function Breadcrumbs({ basePath, baseLabel }: BreadcrumbsProps) { + return ( + + ); +} \ No newline at end of file diff --git a/src/components/centered-image.tsx b/src/components/centered-image.tsx new file mode 100644 index 00000000..5556256f --- /dev/null +++ b/src/components/centered-image.tsx @@ -0,0 +1,51 @@ +"use client"; + +import Image from "next/image"; +import { cn } from "@/lib/utils"; + +interface CenteredImageProps { + src: string; + alt: string; + width: number; + height: number; + caption?: string; + // New prop to control the max width as a percentage + maxWidth?: "50%" | "75%" | "100%"; +} + +export function CenteredImage({ + src, + alt, + width, + height, + caption, + maxWidth = "100%", // Default to 100% of the column width +}: CenteredImageProps) { + // Map the user-friendly prop to actual TailwindCSS classes + const widthClasses = { + "50%": "sm:max-w-[50%]", + "75%": "sm:max-w-[75%]", + "100%": "max-w-full", // `max-w-full` is the default for responsive images + }; + + return ( + // Use
for the image and its caption + // `not-prose` escapes Tailwind Typography styles + // `mx-auto` is the key to centering the block +
+ {alt} + {caption && ( +
+ {caption} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/components/header.tsx b/src/components/header.tsx index 1cf8096d..09fca3c6 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -8,6 +8,7 @@ import { usePathname } from "next/navigation"; export function Header() { const [isVisible, setIsVisible] = useState(false); const pathname = usePathname(); + if (pathname === "/connect") return null; const isMainPage = pathname === "/"; useEffect(() => { diff --git a/src/components/mdx.tsx b/src/components/mdx.tsx index 383ec391..03b9812b 100644 --- a/src/components/mdx.tsx +++ b/src/components/mdx.tsx @@ -6,6 +6,7 @@ import React from "react"; import { InfoBox } from "./infobox"; import { Cite } from "./cite"; import { FloatingImage } from "./floating-image"; +import { CenteredImage } from "./centered-image"; function CustomLink(props: any) { @@ -77,4 +78,5 @@ export const mdxComponents = { InfoBox, Cite, FloatingImage: FloatingImage, + CenteredImage: CenteredImage, }; diff --git a/src/components/references-container.tsx b/src/components/references-container.tsx index 051ddcff..fb4f11b9 100644 --- a/src/components/references-container.tsx +++ b/src/components/references-container.tsx @@ -40,7 +40,7 @@ export function ReferencesContainer() { year={pub.year} pdfUrl={pub.pdfUrl} bibtex={pub.bibtex} - // The pdfAvailable prop is now safely omitted + pdfAvailable={pub.pdfAvailable} /> ); })} diff --git a/src/lib/mdx.ts b/src/lib/mdx.ts index d194d22f..8baec86c 100644 --- a/src/lib/mdx.ts +++ b/src/lib/mdx.ts @@ -40,13 +40,16 @@ export async function getPostBySlug(type: 'projects' | 'research' | 'teaching', const fullPath = path.join(typeDirectory, fileName); const fileContents = fs.readFileSync(fullPath, 'utf8'); + const dateMatch = fileName.match(/^\d{4}-\d{2}-\d{2}/); + const dateFromFilename = dateMatch ? dateMatch[0] : new Date().toISOString(); + const { code, frontmatter } = await bundleMDX({ source: fileContents, }); return { slug, - frontmatter: frontmatter as Frontmatter, + frontmatter: { ...frontmatter, date: dateFromFilename } as Frontmatter, code, }; } diff --git a/src/lib/publications.ts b/src/lib/publications.ts index 888e3ca8..5a04691e 100644 --- a/src/lib/publications.ts +++ b/src/lib/publications.ts @@ -2,8 +2,10 @@ import { parse } from "@retorquere/bibtex-parser"; import fs from "fs"; import path from "path"; +// Your existing path is correct. const bibliographyPath = path.join(process.cwd(), "_bibliography.bib"); +// --- FIX: Add `pdfAvailable` to the Publication interface --- export interface Publication { key: string; title: string; @@ -12,6 +14,8 @@ export interface Publication { year: string; bibtex: string; pdfUrl: string; + url?: string; // Also make url optional to be safe + pdfAvailable?: boolean; // This will hold the result of our check } export function getPublicationsData(): Publication[] { @@ -25,7 +29,6 @@ export function getPublicationsData(): Publication[] { ) : []; - // A simple way to reconstruct the bibtex string for a single entry let bibtexEntryString = `@${entry.type}{${entry.key},\n`; for (const [key, value] of Object.entries(entry.fields)) { if (key === 'author') { @@ -42,8 +45,10 @@ export function getPublicationsData(): Publication[] { } bibtexEntryString += `}` - const journalField = entry.fields.booktitle || entry.fields.journal; + + const pdfPath = path.join(process.cwd(), "public", "publications", `${entry.key}.pdf`); + const pdfExists = fs.existsSync(pdfPath); return { key: entry.key, @@ -54,6 +59,7 @@ export function getPublicationsData(): Publication[] { url: Array.isArray(entry.fields.url) ? entry.fields.url.join(" ") : entry.fields.url, bibtex: bibtexEntryString, pdfUrl: `/publications/${entry.key}.pdf`, + pdfAvailable: pdfExists, // <-- Add the result here }; }); -} +} \ No newline at end of file