-
diff --git a/src/consts.ts b/src/consts.ts
index 33b4e60..44cf218 100644
--- a/src/consts.ts
+++ b/src/consts.ts
@@ -1,10 +1,14 @@
// Place any global data in this file.
// You can import this data from anywhere in your site by using the `import` keyword.
-export const SITE_TITLE = 'Nicholai Vogel | VFX Artist & Technical Generalist';
-export const SITE_DESCRIPTION = 'VFX Artist & Technical Generalist specializing in Houdini, Nuke, and AI/ML integration. Founder of Biohazard VFX.';
+// SEO-optimized title (under 60 characters for full display in search results)
+export const SITE_TITLE = 'Nicholai Vogel — VFX Supervisor & Technical VFX Artist';
+
+// SEO-optimized description (under 160 characters, includes keywords and CTA)
+export const SITE_DESCRIPTION = 'VFX Supervisor specializing in both 2D and 3D VFX, AI and highend technical visualization. Clients: G-Star Raw, Interscope, Ralph Lauren. Founder of Biohazard VFX.';
+
export const SOCIAL_LINKS = {
email: 'nicholai@nicholai.work',
website: 'https://nicholai.work',
- linkedin: '#' // Update when available
+ linkedin: 'https://www.linkedin.com/in/nicholai-vogel-7a6b85112/'
};
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index 638f494..1ad9aca 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -1,4 +1,5 @@
---
+import type { ImageMetadata } from 'astro';
import BaseHead from '../components/BaseHead.astro';
import Footer from '../components/Footer.astro';
import GridOverlay from '../components/GridOverlay.astro';
@@ -10,15 +11,35 @@ interface Props {
title?: string;
description?: string;
usePadding?: boolean;
+ image?: ImageMetadata;
+ type?: 'website' | 'article';
+ publishedTime?: Date;
+ modifiedTime?: Date;
}
-const { title = SITE_TITLE, description = SITE_DESCRIPTION, usePadding = true } = Astro.props;
+const {
+ title = SITE_TITLE,
+ description = SITE_DESCRIPTION,
+ usePadding = true,
+ image,
+ type = 'website',
+ publishedTime,
+ modifiedTime,
+} = Astro.props;
---
-
+
+
diff --git a/src/layouts/BlogPost.astro b/src/layouts/BlogPost.astro
index 6593aee..571e2e7 100644
--- a/src/layouts/BlogPost.astro
+++ b/src/layouts/BlogPost.astro
@@ -37,6 +37,7 @@ interface Props {
prevPost?: NavPost;
nextPost?: NavPost;
relatedPosts?: RelatedPost[];
+ readTime?: string;
}
const {
@@ -51,13 +52,47 @@ const {
prevPost,
nextPost,
relatedPosts = [],
+ readTime = '5 min read',
} = Astro.props;
-// Estimated read time (rough calculation)
-const readTime = '5 min read';
+// Article structured data (JSON-LD)
+const articleSchema = {
+ "@context": "https://schema.org",
+ "@type": "Article",
+ "headline": title,
+ "description": description,
+ "datePublished": pubDate.toISOString(),
+ "dateModified": (updatedDate || pubDate).toISOString(),
+ "author": {
+ "@type": "Person",
+ "name": "Nicholai Vogel",
+ "url": "https://nicholai.work"
+ },
+ "publisher": {
+ "@type": "Person",
+ "name": "Nicholai Vogel",
+ "url": "https://nicholai.work"
+ },
+ "mainEntityOfPage": {
+ "@type": "WebPage",
+ "@id": Astro.url.href
+ },
+ ...(heroImage && { "image": new URL(heroImage.src, Astro.url).toString() }),
+ ...(category && { "articleSection": category }),
+ ...(tags && tags.length > 0 && { "keywords": tags.join(", ") })
+};
---
-
+
+
+
diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro
index 94aef83..c3f931a 100644
--- a/src/pages/blog/[...slug].astro
+++ b/src/pages/blog/[...slug].astro
@@ -89,6 +89,12 @@ interface Props {
const { post, prevPost, nextPost, relatedPosts } = Astro.props;
const { Content, headings } = await render(post);
+
+// Calculate reading time (average 200 words per minute)
+const wordsPerMinute = 200;
+const wordCount = post.body?.split(/\s+/).length || 0;
+const readingTime = Math.max(1, Math.ceil(wordCount / wordsPerMinute));
+const readTimeText = `${readingTime} min read`;
---