Compare commits

..

6 Commits

Author SHA1 Message Date
79c5a1f06e chore: use Video component in roadmap post
All checks were successful
Build and Deploy Blog / build-and-deploy-local (push) Successful in 3m8s
2026-03-31 14:52:35 +02:00
6ae23fb783 feat: register Video component in MDXRemote 2026-03-31 14:51:30 +02:00
aee0035a4f fix: video a11y and valid width attribute 2026-03-31 14:50:59 +02:00
7f04b1befd feat: add Video component 2026-03-31 14:49:55 +02:00
f6819b42bd docs: add video component implementation plan 2026-03-31 14:48:45 +02:00
650164e412 docs: add video component design spec 2026-03-31 14:48:05 +02:00
5 changed files with 212 additions and 0 deletions

View File

@@ -7,6 +7,7 @@ import { MDXRemote } from "next-mdx-remote/rsc";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeSlug from "rehype-slug";
import remarkGfm from "remark-gfm";
import Video from "@/components/video";
interface PageProps {
params: Promise<{ slug: string }>;
@@ -63,6 +64,7 @@ export default async function Post({ params }: PageProps) {
<div className="prose lg:prose-lg max-w-none">
<MDXRemote
source={postData.content}
components={{ Video }}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],

28
components/video.tsx Normal file
View File

@@ -0,0 +1,28 @@
interface VideoProps {
src: string;
caption?: string;
}
export default function Video({ src, caption }: VideoProps) {
return (
<figure className="my-4">
<div className="rounded-lg border border-white/30 bg-white/10 backdrop-blur-sm overflow-hidden shadow-md">
<video
src={src}
className="w-full"
aria-label={caption ?? src}
preload="metadata"
controls
loop
muted
playsInline
/>
</div>
{caption && (
<figcaption className="mt-2 text-center text-sm text-gray-500 italic">
{caption}
</figcaption>
)}
</figure>
);
}

View File

@@ -0,0 +1,142 @@
# Video Component Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Create a reusable `<Video>` MDX component with sensible defaults and an optional caption.
**Architecture:** A single React component in `components/video.tsx` registered in the MDXRemote `components` prop in `app/posts/[slug]/page.tsx`. No per-post imports needed.
**Tech Stack:** Next.js 15, React 19, Tailwind v4, next-mdx-remote
---
### Task 1: Create Video component
**Files:**
- Create: `components/video.tsx`
- [ ] **Step 1: Create the component**
```tsx
interface VideoProps {
src: string;
caption?: string;
}
export default function Video({ src, caption }: VideoProps) {
return (
<figure className="my-4">
<div className="rounded-lg border border-white/30 bg-white/10 backdrop-blur-sm overflow-hidden shadow-md">
<video
src={src}
width="100%"
controls
loop
muted
playsInline
/>
</div>
{caption && (
<figcaption className="mt-2 text-center text-sm text-gray-500 italic">
{caption}
</figcaption>
)}
</figure>
);
}
```
- [ ] **Step 2: Commit**
```bash
git add components/video.tsx
git commit -m "feat: add Video component"
```
---
### Task 2: Register Video in MDXRemote
**Files:**
- Modify: `app/posts/[slug]/page.tsx`
- [ ] **Step 1: Add import at top of file**
After the existing imports, add:
```tsx
import Video from "@/components/video";
```
- [ ] **Step 2: Add components prop to MDXRemote**
Find the `<MDXRemote ... />` call (around line 64) and add a `components` prop:
```tsx
<MDXRemote
source={postData.content}
components={{ Video }}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
rehypePrettyCode,
{
theme: "github-dark-dimmed",
keepBackground: false,
},
],
],
},
}}
/>
```
- [ ] **Step 3: Verify dev server compiles without errors**
```bash
bun dev
```
Expected: server starts, no TypeScript errors.
- [ ] **Step 4: Commit**
```bash
git add app/posts/[slug]/page.tsx
git commit -m "feat: register Video component in MDXRemote"
```
---
### Task 3: Use component in a post
**Files:**
- Modify: `posts/my-2024-and-2025-roadmap.mdx`
- [ ] **Step 1: Replace raw video tag with component**
Find (around line 54):
```html
<video width="100%" height="auto" controls loop muted playsInline>
<source src="/posts/rts.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
```
Replace with:
```mdx
<Video src="/posts/rts.mp4" caption="My failed RTS engine attempt" />
```
- [ ] **Step 2: Verify in browser**
Open the post in the dev server and confirm the video renders with styling and caption.
- [ ] **Step 3: Commit**
```bash
git add posts/my-2024-and-2025-roadmap.mdx
git commit -m "chore: use Video component in roadmap post"
```

View File

@@ -0,0 +1,30 @@
# Video Component Design
## Summary
A reusable `<Video>` MDX component for embedding videos in blog posts with sensible defaults and optional caption.
## Component
**File:** `components/video.tsx`
**Props:**
- `src: string` — video file path (required)
- `caption?: string` — text displayed below video (optional)
**Video defaults:** `controls loop muted playsInline width="100%"`
**Styling:**
- Container: `rounded-lg border border-white/30 bg-white/10 backdrop-blur-sm overflow-hidden shadow-md`
- Caption: small, muted, italic, centered
## Integration
Register `Video` in `page.tsx` MDXRemote `components` prop so it's available in all MDX posts without per-post imports.
## Usage in MDX
```mdx
<Video src="/posts/rts.mp4" />
<Video src="/posts/rts.mp4" caption="My failed RTS attempt" />
```

View File

@@ -25,6 +25,8 @@ But that wasn't all I did in the first month of 2024. I had this crazy idea to c
Next, I wrote a **Minesweeper** game in C++ using Raylib. That was pretty fun! The code, however, isn't really good—it's not idiomatic C++, more like C with classes—but the point of the project was just to have fun. Thats why Im not going to link the repo. However, if someone is interested, they can easily find it on my GitHub.
![minesweeper](/posts/minesweeper.webp)
## February - Small but Fun Projects
February, the shortest month of the year! I hopped from project to project, but some were actually finished and published.
@@ -37,18 +39,26 @@ You might ask, _Why use Rust for that instead of JavaScript?_ Great question! Th
Next, I started working on a **Missile Commander clone**—a recreation of the old Atari game **Missile Command**. I actually managed to replicate the core gameplay, but since Im terrible at designing games and coming up with new mechanics, levels, and features, I abandoned it pretty quickly. I even wrote a **level editor** for it! The game and editor were both written in Rust using **macroquad**, as I wanted to export it to the web. Unfortunately, I ran into some errors when trying to export and gave up.
![missile_commander](/posts/missile_commander.webp)
## March - A Sokoban Game in Java
In March, I only worked on one toy project—a **Sokoban game in Java** using Raylib. Why Java? No idea. I guess I just wanted to refresh my skills in the language.
![Sokoban](/posts/sokoban.webp)
## April - The RTS Struggle
In April, I really wanted to create an **RTS game**. Unfortunately, I didnt succeed. Nevertheless, I made an attempt at creating an **RTS engine in Rust** using the _comfy_ crate. Later, I tried moving to Bevy, but pathfinding defeated me. I haven't given up on the idea completely, though—I may go back to it in the future, because I love RTS and strategy games so much.
<Video src="/posts/rts.mp4" caption="My failed RTS engine attempt" />
While researching RTS mechanics, I wrote my own **quadtree** in Rust and visualized it using Raylib. That was pretty fun and easy.
I also got into **ray tracing** and, thanks to _Ray Tracing in One Weekend_, I wrote my own **software ray tracer** in Rust.
![raytracer](/posts/raytracer.webp)
Another Rust project from April was an **Otodom scraper** with a frontend in React. Otodom is a website listing real estate for sale or rent, and since I was house-hunting, I needed a better way to filter available listings. So I wrote a simple service using _Axum_ that scrapes the data every ten minutes, allowing me to easily filter through listings.
Last but not least, I created **better_notepad**, a Notepad-like app because I was annoyed that the default Windows Notepad didnt close tabs when the app was closed. I wrote mine in C++ with wxWidgets. Later, I learned that you can actually turn that behavior off in the Notepad settings... oops.