Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
name="description"
content="Real-time performance engineer with 13+ years in Unity. Shipped mobile titles, XR/VR optimization, GPU/CPU bottleneck isolation, and frame pacing research with profiler-validated measurements."
/>
<link rel="canonical" href="https://jamesderaja.com/" />
<link rel="canonical" href="https://james.alphaden.club/" />
<meta name="robots" content="index,follow" />
<meta name="author" content="James De Raja" />
<meta
Expand All @@ -23,7 +23,7 @@
content="13+ years and 100+ shipped titles. GPU/CPU bottleneck isolation, XR stereo rendering, and frame pacing research with profiler evidence."
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://jamesderaja.com/" />
<meta property="og:url" content="https://james.alphaden.club/" />
<meta property="og:image" content="/og-image.png" />
<meta property="og:site_name" content="James De Raja Portfolio" />
<meta name="twitter:card" content="summary_large_image" />
Expand Down
2 changes: 1 addition & 1 deletion public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
User-agent: *
Allow: /
Sitemap: https://jamesderaja.com/sitemap.xml
Sitemap: https://james.alphaden.club/sitemap.xml
34 changes: 20 additions & 14 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -1,87 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://jamesderaja.com/</loc>
<loc>https://james.alphaden.club/</loc>
<lastmod>2026-03-06</lastmod>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://jamesderaja.com/case-studies/xr-stress-lab</loc>
<loc>https://james.alphaden.club/case-studies/xr-stress-lab</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://jamesderaja.com/case-studies/softmaskpro</loc>
<loc>https://james.alphaden.club/case-studies/softmaskpro</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://jamesderaja.com/case-studies/profiling-toolkit</loc>
<loc>https://james.alphaden.club/case-studies/profiling-toolkit</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://jamesderaja.com/case-studies/sneaky-warrior-3d</loc>
<loc>https://james.alphaden.club/case-studies/sneaky-warrior-3d</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/case-studies/published-mobile-projects</loc>
<loc>https://james.alphaden.club/case-studies/published-mobile-projects</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/overdraw</loc>
<loc>https://james.alphaden.club/lab/overdraw</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/msaa</loc>
<loc>https://james.alphaden.club/lab/msaa</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/msaa-overdraw</loc>
<loc>https://james.alphaden.club/lab/msaa-overdraw</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/instancing</loc>
<loc>https://james.alphaden.club/lab/instancing</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/frame-pacing</loc>
<loc>https://james.alphaden.club/lab/frame-pacing</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/frame-pacing-vs-fps</loc>
<loc>https://james.alphaden.club/lab/frame-pacing-vs-fps</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/xr-frame-timing</loc>
<loc>https://james.alphaden.club/lab/xr-frame-timing</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://jamesderaja.com/lab/overdraw-stereo</loc>
<loc>https://james.alphaden.club/lab/overdraw-stereo</loc>
<lastmod>2025-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://james.alphaden.club/visual-journey</loc>
<lastmod>2026-04-28</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import XRFrameTimingLabPage from './lab/pages/XRFrameTimingLabPage';
import SiteLayout from './layouts/SiteLayout';
import HomePage from './pages/HomePage';
import NotFoundPage from './pages/NotFoundPage';
import VisualJourney from './pages/VisualJourney';

function App() {
return (
Expand All @@ -43,6 +44,7 @@ function App() {
<Route path="/lab/frame-pacing-vs-fps" element={<FramePacingVsFPSLabPage />} />
<Route path="/lab/xr-frame-timing" element={<XRFrameTimingLabPage />} />
<Route path="/lab/overdraw-stereo" element={<OverdrawStereoLabPage />} />
<Route path="/visual-journey" element={<VisualJourney />} />
<Route path="*" element={<NotFoundPage />} />
</Route>
</Routes>
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/ProfilingToolkitCaseStudyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function ProfilingToolkitCaseStudyPage() {
<Seo
title="Profiling Toolkit Case Study — James De Raja"
description="Case study on a Unity runtime profiling overlay that shortens bottleneck triage from symptom capture to mitigation-ready evidence."
url="https://jamesderaja.com/case-studies/profiling-toolkit"
url="https://james.alphaden.club/case-studies/profiling-toolkit"
keywords="Unity profiler toolkit, runtime overlay, bottleneck triage, performance telemetry"
type="article"
structuredData={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function PublishedMobileProjectsCaseStudyPage() {
<Seo
title="Sneaky Warrior 3D Case Study — James De Raja"
description="Mobile performance case study covering frame budget stabilization for Sneaky Warrior 3D under heavy AI, ragdoll, and projectile load."
url="https://jamesderaja.com/case-studies/published-mobile-projects"
url="https://james.alphaden.club/case-studies/published-mobile-projects"
keywords="mobile performance, Unity optimization, frame budget, Sneaky Warrior 3D, frame pacing"
type="article"
structuredData={{
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/SoftMaskProCaseStudyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default function SoftMaskProCaseStudyPage() {
<Seo
title="SoftMaskPro Optimization Case Study — James De Raja"
description="SoftMaskPro profiling and patching case study focused on UI mask draw calls, render pass overhead, and frame-time stabilization in Unity."
url="https://jamesderaja.com/case-studies/softmaskpro"
url="https://james.alphaden.club/case-studies/softmaskpro"
keywords="SoftMaskPro, Unity UI optimization, draw calls, frame timing, profiling"
type="article"
structuredData={{
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/UpdateStrategiesCaseStudyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export default function UpdateStrategiesCaseStudyPage() {
<Seo
title="Update Strategies at Scale — James De Raja"
description="Profiler-driven comparison of 4 Unity update architectures (MonoBehaviour, Manager, ECS) across 10,000 entities. Frame time reduced from ~40 ms to ~9.4 ms."
url="https://jamesderaja.com/case-studies/update-strategies-scale"
url="https://james.alphaden.club/case-studies/update-strategies-scale"
keywords="Unity ECS, MonoBehaviour update, central manager, DOTS, performance, 10000 entities, Unity profiling"
type="article"
structuredData={{
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/UpdateStrategiesVariantAPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function UpdateStrategiesVariantAPage() {
<Seo
title="Variant A — Lifecycle Control | Update Strategies at Scale"
description="Deep dive into Scene A of the Unity update architecture study: 10,000 passive enemies with bullet lifecycle churn. Establishes the render and GC baseline."
url="https://jamesderaja.com/case-studies/update-strategies-scale/variant-a"
url="https://james.alphaden.club/case-studies/update-strategies-scale/variant-a"
keywords="Unity lifecycle, MonoBehaviour baseline, Instantiate Destroy, GC alloc, Unity profiling, 10000 entities"
type="article"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/UpdateStrategiesVariantBPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function UpdateStrategiesVariantBPage() {
<Seo
title="Variant B — Per-Object Update | Update Strategies at Scale"
description="Deep dive into Scene B: 10,000 MonoBehaviour Update calls, 8.62 ms ScriptRunBehaviourUpdate, and why per-object update does not scale in Unity."
url="https://jamesderaja.com/case-studies/update-strategies-scale/variant-b"
url="https://james.alphaden.club/case-studies/update-strategies-scale/variant-b"
keywords="MonoBehaviour Update, ScriptRunBehaviourUpdate, Unity performance, 10000 entities, update dispatch overhead"
type="article"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/UpdateStrategiesVariantCPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default function UpdateStrategiesVariantCPage() {
<Seo
title="Variant C — Central Manager | Update Strategies at Scale"
description="Deep dive into Scene C: a single manager MonoBehaviour replaces 10,000 per-object Updates. Script cost drops from 8.62 ms to 4.34 ms, but Transform iteration remains the bottleneck."
url="https://jamesderaja.com/case-studies/update-strategies-scale/variant-c"
url="https://james.alphaden.club/case-studies/update-strategies-scale/variant-c"
keywords="Unity central manager, MonoBehaviour optimization, Transform iteration, Unity performance, update pattern"
type="article"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/UpdateStrategiesVariantDPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export default function UpdateStrategiesVariantDPage() {
<Seo
title="Variant D — ECS (DOTS) | Update Strategies at Scale"
description="Deep dive into Scene D: Unity ECS replaces MonoBehaviours entirely. Frame time drops from ~40 ms to ~9.4 ms — a 4× improvement under 10,000 enemies and maximum bullet pressure."
url="https://jamesderaja.com/case-studies/update-strategies-scale/variant-d"
url="https://james.alphaden.club/case-studies/update-strategies-scale/variant-d"
keywords="Unity ECS, DOTS, entity component system, Burst compiler, chunk iteration, MonoBehaviour replacement, Unity performance"
type="article"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/caseStudies/pages/XRStressLabCaseStudyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function XRStressLabCaseStudyPage() {
<Seo
title="XR Stress Lab Case Study — James De Raja"
description="Controlled XR stress tests isolating overdraw, MSAA bandwidth, submission overhead, and frame pacing variance with profiler-backed evidence."
url="https://jamesderaja.com/case-studies/xr-stress-lab"
url="https://james.alphaden.club/case-studies/xr-stress-lab"
keywords="XR stress lab, overdraw, MSAA, instancing, frame pacing, Unity profiling"
type="article"
structuredData={{
Expand Down
1 change: 1 addition & 0 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default function Footer() {
<SmartLink href="https://www.linkedin.com/in/james-de-raja/" className="transition hover:text-neon">LinkedIn</SmartLink>
<SmartLink href="https://github.com/JamesDeRaja" className="transition hover:text-neon">GitHub</SmartLink>
<SmartLink href="/resume/viewer.html?file=James%20DeRaja%20Resume.pdf" className="transition hover:text-neon">Resume</SmartLink>
<SmartLink href="/visual-journey" className="transition hover:text-neon">Visual Journey</SmartLink>
</div>
</div>
</footer>
Expand Down
13 changes: 13 additions & 0 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ export default function Navbar() {

{/* Actions */}
<div className="flex items-center gap-2">
<SmartLink
href="/visual-journey"
className="hidden rounded-lg border border-neon/20 bg-neon/10 px-3 py-2 text-sm font-medium text-neon transition hover:border-neon/40 hover:bg-neon/15 lg:inline-flex"
>
Visual Resume
</SmartLink>
<SmartLink
href="/resume/viewer.html?file=James%20DeRaja%20Resume.pdf"
className="btn-primary hidden rounded-lg px-4 py-2 text-sm font-medium sm:inline-flex"
Expand Down Expand Up @@ -121,6 +127,13 @@ export default function Navbar() {
className="overflow-hidden border-t border-white/5 bg-void-950/95 backdrop-blur-xl md:hidden"
>
<div className="px-4 py-4 space-y-1">
<SmartLink
href="/visual-journey"
className="mb-2 block w-full rounded-lg border border-neon/20 bg-neon/10 px-3 py-3 text-left text-sm font-medium text-neon transition hover:border-neon/40 hover:bg-neon/15"
onClick={() => setMobileOpen(false)}
>
Visual Resume
</SmartLink>
{navItems.map((item) => (
<button
key={item.label}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Seo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function Seo({
'@type': 'Person',
name: 'James De Raja',
jobTitle: 'Senior Real-Time Performance Engineer',
url: 'https://jamesderaja.com',
url: 'https://james.alphaden.club',
email: 'jamesderaja@gmail.com',
address: {
'@type': 'PostalAddress',
Expand Down
2 changes: 1 addition & 1 deletion src/components/SmartLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type SmartLinkProps = AnchorHTMLAttributes<HTMLAnchorElement> & {
children: ReactNode;
};

const INTERNAL_HOSTNAMES = new Set(['jamesderaja.com', 'www.jamesderaja.com']);
const INTERNAL_HOSTNAMES = new Set(['james.alphaden.club', 'www.james.alphaden.club']);

function isHttpUrl(href: string) {
return href.startsWith('http://') || href.startsWith('https://');
Expand Down
29 changes: 29 additions & 0 deletions src/components/visual-journey/FloatingMetric.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { motion, useReducedMotion } from 'framer-motion';

type FloatingMetricProps = {
text: string;
index?: number;
};

export default function FloatingMetric({ text, index = 0 }: FloatingMetricProps) {
const reduceMotion = useReducedMotion();

return (
<motion.div
className="rounded-xl border border-neon/20 bg-neon/5 px-3 py-2 text-xs font-semibold text-slate-100"
initial={{ opacity: 0, scale: 0.96 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true, amount: 0.2 }}
transition={{ duration: 0.3, delay: index * 0.07 }}
animate={
reduceMotion
? undefined
: {
y: [0, -4, 0],
}
}
>
{text}
</motion.div>
);
}
80 changes: 80 additions & 0 deletions src/components/visual-journey/JourneyStage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { motion, useReducedMotion } from 'framer-motion';
import FloatingMetric from './FloatingMetric';
import ThoughtBubble from './ThoughtBubble';
import VisualJourneyCharacter from './VisualJourneyCharacter';
import type { JourneyStageData } from './types';

type JourneyStageProps = {
stage: JourneyStageData;
index: number;
isActive: boolean;
isMobile: boolean;
onEnter: (index: number) => void;
progress: number;
};

export default function JourneyStage({
stage,
index,
isActive,
isMobile,
onEnter,
progress,
}: JourneyStageProps) {
const reduceMotion = useReducedMotion();

return (
<motion.section
id={stage.id}
className="scroll-mt-24 rounded-3xl border border-white/10 bg-void-900/60 p-6 backdrop-blur-xl md:p-8"
initial={{ opacity: 0, y: reduceMotion ? 0 : 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ amount: 0.45 }}
transition={{ duration: 0.45, ease: 'easeOut' }}
onViewportEnter={() => onEnter(index)}
>
<div className="mb-5 flex flex-wrap items-center gap-3">
<span className="rounded-full border border-neon/20 bg-neon/10 px-3 py-1 text-xs font-mono uppercase tracking-wide text-neon">
Phase {index + 1}
</span>
<h3 className="text-xl font-semibold text-white">{stage.title}</h3>
</div>
<p className="mb-5 text-sm leading-relaxed text-slate-300">{stage.description}</p>

{isMobile && (
<div className="mb-6 md:hidden">
<VisualJourneyCharacter stage={stage} progress={progress} mobile />
</div>
)}

{!!stage.chips?.length && (
<div className="mb-4 flex flex-wrap gap-2">
{stage.chips.map((chip) => (
<span
key={chip}
className="rounded-full border border-white/15 bg-white/5 px-3 py-1 text-xs font-semibold text-slate-200"
>
{chip}
</span>
))}
</div>
)}

<div className="mb-4 flex flex-wrap gap-2">
{stage.bubbles.map((bubble, bubbleIndex) => (
<ThoughtBubble key={bubble} text={bubble} index={bubbleIndex} />
))}
</div>

{!!stage.metrics?.length && (
<div className="grid gap-2 sm:grid-cols-2">
{stage.metrics.map((metric, metricIndex) => (
<FloatingMetric key={metric} text={metric} index={metricIndex} />
))}
</div>
)}

{isActive && <div className="mt-6 h-px bg-gradient-to-r from-neon/80 via-electric/70 to-transparent" />}
</motion.section>
);
}
Loading