diff --git a/app/forge/page.tsx b/app/forge/page.tsx
index 0b26d93..877fc70 100644
--- a/app/forge/page.tsx
+++ b/app/forge/page.tsx
@@ -1,79 +1,31 @@
-"use client";
-import { Hammer, History, Target, Code2 } from "lucide-react";
+import ForgeUI from "@/components/ForgeUI";
import PageLayout from "@/components/PageLayout";
+import { getAllForgeProjects } from "@/lib/git";
+import { Hammer } from "lucide-react";
+
+export default async function ForgePage() {
+ const projects = await getAllForgeProjects();
-export default function ForgePage() {
return (
-
- TheForge
+
+ The Forge
-
-
- The Forge is where I document my current engineering focus. This space
- reflects active builds, experimental prototypes and gives a taste of
- my next releases.
+
+ The Forge is my active development logs, providing a glimpse into my
+ current projects and future potential releases.
- {/* Main Project Card */}
-
-
-
-
- Project: PixelPals
-
-
-
- Build Phase: Alpha 0.1
-
-
- Engine: Godot / GDScript
-
-
-
-
-
- Active Focus
-
-
-
-
-
- Exploring procedural generation and state-machine-driven AI behaviors.
- The goal is to bridge my experience in systems architecture with
- real-time game loops and interactive storytelling.
-
-
- {/* Milestones / Changelog */}
-
-
- Development_Log
-
-
-
-
+
+ {projects.map((project) => (
+
+ ))}
+
);
}
diff --git a/components/ForgeUI copy.tsx b/components/ForgeUI copy.tsx
new file mode 100644
index 0000000..df6e063
--- /dev/null
+++ b/components/ForgeUI copy.tsx
@@ -0,0 +1,131 @@
+"use client";
+
+import Image from "next/image";
+import { History, ExternalLink, Cpu } from "lucide-react";
+import { ForgeProject } from "@/types";
+
+export default function ForgeUI({ project }: { project: ForgeProject }) {
+ return (
+
+ {/* Upper Section: Hero Area */}
+
+
+
+
+
+ {project.projectName}
+
+
+
+ {/* Version Badge */}
+
+ {project.currentVersion}
+
+
+ {/* Engine Tag */}
+
+ {project.engine}
+
+
+ {/* Status Indicator (Now part of the tag row) */}
+
+
+
+
+
+ ACTIVE STREAM
+
+
+
+
+ {project.externalLink && (
+
+ Project Details
+
+ )}
+
+
+
+ {project.description}
+
+
+
+ {project.imagePath && (
+
+ )}
+
+
+ {/* Technical Highlights */}
+
+ {project.highlights.map((tag) => (
+
+ {`// ${tag}`}
+
+ ))}
+
+
+ {/* Lower Section: Logs with Gradient Fade */}
+
+
+ Dev_Log
+
+
+ {/* This container handles the fade effect */}
+
+ {project.changelog.map((entry) => (
+
+
+
+
+ {entry.version}
+
+
+ {entry.date}
+
+
+
+ {entry.changes.map((change, idx) => (
+ -
+ {change}
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/ForgeUI.tsx b/components/ForgeUI.tsx
new file mode 100644
index 0000000..aeb3dd6
--- /dev/null
+++ b/components/ForgeUI.tsx
@@ -0,0 +1,136 @@
+"use client";
+
+import Image from "next/image";
+import { History, ExternalLink, Cpu } from "lucide-react";
+import { ForgeProject } from "@/types";
+
+export default function ForgeUI({ project }: { project: ForgeProject }) {
+ return (
+
+ {/* Upper Section: Hero Area */}
+
+ {" "}
+ {/* Added pt-8 here to replace the p-8 pt-0 conflict */}
+
+
+
+
+ {project.projectName}
+
+
+
+
+ {project.currentVersion}
+
+
+
+ {project.engine}
+
+
+
+
+
+
+
+ ACTIVE STREAM
+
+
+
+
+ {project.externalLink && (
+
+ Project Details
+
+ )}
+
+
+
+ {project.description}
+
+
+ {project.imagePath && (
+
+ )}
+
+
+ {/* Technical Highlights */}
+
+ {project.highlights.map((tag) => (
+
+ {`// ${tag}`}
+
+ ))}
+
+
+ {/* Lower Section: Logs */}
+
+
+ Dev_Log
+
+
+
+ {project.changelog.map((entry) => (
+
+ {/* The Version Indicator Circle */}
+
+
+
+
+ {entry.version}
+
+
+ {entry.date}
+
+
+
+ {/* Individual Changes with Bullet Points */}
+
+ {entry.changes.map((change, idx) => (
+ -
+ {/* The Bullet Character */}
+
+ •
+
+ {change}
+
+ ))}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/data/forge.ts b/data/forge.ts
index b9ecc09..ae947d7 100644
--- a/data/forge.ts
+++ b/data/forge.ts
@@ -1,26 +1,21 @@
-import { ForgeProject } from "@/types";
+import { ForgeProjectMetadata } from "@/types";
-export const ACTIVE_BUILD: ForgeProject = {
- id: "pixelpals",
- name: "PixelPals",
- status: "Alpha",
- engine: "Godot 4.x",
- description:
- "A mobile-first creature collection game focusing on procedural behaviors and lightweight state-management.",
- highlights: [
- "State-machine AI",
- "Custom Shader Pipelines",
- "Mobile-optimized Loops",
- ],
- externalLink: "/projects/pixelpals", // Link to your internal portfolio or a dedicated site
- changelog: [
- {
- date: "2026-02-03",
- update: "Refined touch-input latency for mobile devices.",
- },
- {
- date: "2026-01-25",
- update: "Integrated local SQLite database for creature persistence.",
- },
- ],
-};
+export const FORGE_PROJECTS: ForgeProjectMetadata[] = [
+ {
+ id: "pixelpals",
+ projectName: "PixelPals",
+ repoName: "pixel-pals",
+ status: "Alpha",
+ engine: "Flutter / Firebase",
+ imagePath: "/forge/pixel-pals.png",
+ description:
+ "A GPS-driven, cooperative creature collection game built to encourage exercise. Features turn-based tactical combat, class-based progression, and AI-generated companion art based on player descriptions.",
+ highlights: [
+ "GPS / Mapbox Integration",
+ "Generative AI (Pet Synthesis)",
+ "Real-time Firebase Sync",
+ "Turn-based Battle Engine",
+ ],
+ externalLink: "https://pixelpals.app",
+ },
+];
diff --git a/lib/git.ts b/lib/git.ts
new file mode 100644
index 0000000..95ab0d4
--- /dev/null
+++ b/lib/git.ts
@@ -0,0 +1,91 @@
+import { FORGE_PROJECTS } from "@/data/forge";
+import { ChangelogEntry, ForgeProject } from "@/types";
+import "server-only";
+
+export async function getAllForgeProjects(): Promise {
+ // We use Promise.all to fetch all changelogs in parallel for speed
+ return Promise.all(
+ FORGE_PROJECTS.map(async (metadata) => {
+ const changelog = await getPrivateChangelog(metadata.repoName);
+ const latestVersion =
+ changelog.length > 0 ? changelog[0].version : "0.0.0";
+
+ return {
+ ...metadata,
+ currentVersion: `${latestVersion}_${metadata.status}`,
+ changelog: changelog,
+ };
+ }),
+ );
+}
+
+export async function getPrivateChangelog(
+ repoName: string,
+): Promise {
+ const repoOwner = "georgew";
+ const filePath = "changelog.md";
+ const url = `https://git.georgew.dev/api/v1/repos/${repoOwner}/${repoName}/contents/${filePath}`;
+ const headers = {
+ headers: {
+ Authorization: `token ${process.env.FORGEJO_TOKEN}`,
+ Accept: "application/vnd.forgejo.raw",
+ },
+ next: { revalidate: 3600 },
+ };
+
+ try {
+ const response = await fetch(url, headers);
+
+ if (!response.ok) {
+ return [
+ {
+ version: "v0.0.0",
+ date: new Date().toISOString().split("T")[0],
+ changes: ["Documentation currently synchronizing with the Forge..."],
+ },
+ ];
+ }
+
+ const data = await response.json();
+
+ // 2. Forgejo returns the content as a base64 string
+ // We need to decode it to UTF-8
+ const markdownText = Buffer.from(data.content, "base64").toString("utf-8");
+
+ return parseMarkdown(markdownText);
+ } catch (error) {
+ console.error("Git Fetch Error:", error);
+ return [];
+ }
+}
+
+// Simple parser for your ## [Version] - YYYY-MM-DD format
+function parseMarkdown(text: string): ChangelogEntry[] {
+ // Split by "## " at the start of a line to isolate version blocks
+ const sections = text.split(/\n(?=## )/g);
+
+ return sections
+ .map((section) => {
+ const lines = section
+ .split("\n")
+ .map((l) => l.trim())
+ .filter(Boolean);
+ if (lines.length === 0) return null;
+
+ // Match the pattern: ## [Version] - YYYY-MM-DD
+ const headerMatch = lines[0].match(/## \[(.*?)\] - (.*)/);
+ if (!headerMatch) return null;
+
+ const version = headerMatch[1];
+ const date = headerMatch[2];
+
+ // Collect all lines starting with "- " anywhere in this version block
+ const changes = lines
+ .filter((line) => line.startsWith("- "))
+ .map((line) => line.replace("- ", ""));
+
+ return { version, date, changes };
+ })
+ .filter((entry): entry is ChangelogEntry => entry !== null)
+ .slice(0, 3);
+}
diff --git a/public/forge/pixel-pals.png b/public/forge/pixel-pals.png
new file mode 100644
index 0000000..247437a
Binary files /dev/null and b/public/forge/pixel-pals.png differ
diff --git a/types/index.ts b/types/index.ts
index 93c1690..496e741 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -50,11 +50,31 @@ export interface LabService {
export interface ForgeProject {
id: string;
- name: string;
status: "Alpha" | "Beta" | "R&D";
engine: string;
description: string;
+ imagePath?: string;
highlights: string[];
externalLink?: string;
- changelog: { date: string; update: string }[];
+ projectName: string;
+ currentVersion: string; // Dynamically parsed
+ changelog: ChangelogEntry[]; // Dynamically fetched
+}
+
+export interface ForgeProjectMetadata {
+ id: string;
+ projectName: string;
+ repoName: string;
+ status: "Alpha" | "Beta" | "R&D";
+ engine: string;
+ imagePath?: string;
+ description: string;
+ highlights: string[];
+ externalLink?: string;
+}
+
+export interface ChangelogEntry {
+ version: string;
+ date: string;
+ changes: string[];
}