-
Notifications
You must be signed in to change notification settings - Fork 212
Blog #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Blog #13
Conversation
WalkthroughThis update introduces a comprehensive overhaul of the portfolio site, shifting its focus to AI/ML engineering and research. It adds new technical blog and publication sections, replaces previous branding and content, introduces device-aware 3D/2D previews, enhances error handling, and expands documentation. Numerous new React components, hooks, utilities, and markdown files are added for content management and user experience. Changes
Changes Table (Grouped)
Sequence Diagram(s)Blog Post Viewing and FilteringsequenceDiagram
participant User
participant BlogSection
participant BlogUtils
participant BlogCard
participant BlogPost
User->>BlogSection: Loads Blog Section
BlogSection->>BlogUtils: getBlogCategories(), getBlogPostsByCategory()
BlogSection->>BlogCard: Render list of posts
User->>BlogSection: Selects category or enters search
BlogSection->>BlogUtils: Filter/Search blogPosts
BlogSection->>BlogCard: Update post list
User->>BlogCard: Clicks "Read More"
BlogSection->>BlogPost: Render detailed post view
User->>BlogPost: Clicks "Back"
BlogSection->>BlogCard: Return to post list
Device-Aware Project PreviewsequenceDiagram
participant User
participant ProjectsSection
participant useMobileDetection
participant MobileProjectDisplay
participant DemoComputer
User->>ProjectsSection: Loads Projects
ProjectsSection->>useMobileDetection: Detect device type
alt On mobile
ProjectsSection->>MobileProjectDisplay: Render 2D preview
else On desktop
ProjectsSection->>DemoComputer: Render 3D preview in Canvas
end
Canvas Error HandlingsequenceDiagram
participant User
participant Canvas
participant CanvasErrorBoundary
participant EnhancedCanvasLoader
User->>Canvas: Loads 3D content
Canvas->>EnhancedCanvasLoader: Show loading progress
alt Error occurs
Canvas->>CanvasErrorBoundary: Throw error
CanvasErrorBoundary->>User: Show fallback UI with retry option
else Timeout
EnhancedCanvasLoader->>User: Show timeout message and retry button
end
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 20
♻️ Duplicate comments (4)
src/components/HuggingFaceLogo.jsx (2)
8-11
: Samedispose={null}
issue as noted inPythonLogo.jsx
See previous comment – remove the prop for correctness.
1-16
: Consider consolidating logo componentsThis file repeats the pattern already highlighted; extract shared behaviour into a single component.
src/components/ClaudeLogo.jsx (1)
8-11
: Remove ineffectivedispose={null}
Same rationale as earlier logo components.
src/components/PyTorchLogo.jsx (1)
8-11
: Remove ineffectivedispose={null}
Same rationale as earlier logo components.
🧹 Nitpick comments (31)
src/components/HackerRoom.jsx (1)
21-30
: Consider extracting magic numbers into named constants.The texture configuration uses hardcoded values that could benefit from being extracted into named constants for better maintainability and readability.
+// Texture configuration constants +const PHOTO_TEXTURE_CONFIG = { + WRAP_MODE: 1001, // ClampToEdgeWrapping + OFFSET: { x: 0.1, y: 0.2 }, // Center face, prevent hair cutoff + REPEAT: { x: 1.2, y: 1.2 }, // Scale up slightly + CENTER: { x: 0.5, y: 0.5 } // Center point for transformations +}; + useEffect(() => { if (screenTxt) { - // Center the face and prevent hair cutoff - screenTxt.wrapS = screenTxt.wrapT = 1001; // ClampToEdgeWrapping - screenTxt.offset.set(0.1, 0.2); // Shift more left and slightly up to center face - screenTxt.repeat.set(1.2, 1.2); // Scale up slightly to show more of the image - screenTxt.center.set(0.5, 0.5); // Set center point for transformations + screenTxt.wrapS = screenTxt.wrapT = PHOTO_TEXTURE_CONFIG.WRAP_MODE; + screenTxt.offset.set(PHOTO_TEXTURE_CONFIG.OFFSET.x, PHOTO_TEXTURE_CONFIG.OFFSET.y); + screenTxt.repeat.set(PHOTO_TEXTURE_CONFIG.REPEAT.x, PHOTO_TEXTURE_CONFIG.REPEAT.y); + screenTxt.center.set(PHOTO_TEXTURE_CONFIG.CENTER.x, PHOTO_TEXTURE_CONFIG.CENTER.y); screenTxt.needsUpdate = true; } }, [screenTxt]);src/sections/Footer.jsx (1)
18-18
: Consider moving inline style to CSS.The inline style for the LinkedIn icon works but could be better managed via CSS for consistency and maintainability.
-<img src="/assets/linkedin.svg" alt="linkedin" className="w-1/2 h-1/2" style={{filter: 'invert(1)'}} /> +<img src="/assets/linkedin.svg" alt="linkedin" className="w-1/2 h-1/2 invert" />Add to your CSS:
.invert { filter: invert(1); }src/components/PythonLogo.jsx (1)
3-5
: Pre-warm texture to avoid first-frame blank
useTexture.preload('/assets/python.png')
can be called once at module scope to cache the image before the component mounts, eliminating a frame drop in WebGL on first render.debug_jan_model.js (2)
7-10
: Missing dependency array item –clone
useEffect
depends onclone
, not onlynodes
andmaterials
.
Whileclone
is memoised, adding it to the deps array is semantically correct and avoids future ESLint-react-hooks warnings.- }, [nodes, materials]); + }, [clone, nodes, materials]);
1-34
: Optional cleanup to prevent leaked geometries/materials during hot-reloadEven though this is a dev-only tool, calling
dispose()
on geometries/materials in a cleanup function safeguards memory in hot-module reload sessions.useEffect(() => { ... -}, [clone, nodes, materials]); + return () => { + clone.traverse((obj) => { + if (obj.geometry) obj.geometry.dispose(); + if (obj.material?.dispose) obj.material.dispose(); + }); + }; +}, [clone, nodes, materials]);src/components/MongoDBLogo.jsx (1)
4-4
: Consider adding error handling for texture loading.While the texture loading follows the established pattern from other logo components, there's no error handling if the texture fails to load. This could cause the component to break silently.
Consider adding error handling similar to other components:
- const texture = useTexture('/assets/MongoDB_SpringGreen.png'); + const texture = useTexture('/assets/MongoDB_SpringGreen.png', (texture) => { + // Optional: Handle successful load + }, (error) => { + console.warn('Failed to load MongoDB texture:', error); + });Alternatively, you could use a try-catch wrapper or implement a fallback texture mechanism.
src/sections/Publications.jsx (1)
11-13
: Add handling for empty publications array.The component doesn't handle the case where the publications array is empty, which could result in a poor user experience.
<div className="publications-container"> + {publications.length === 0 ? ( + <div className="text-center py-8"> + <p className="text-white-600">No publications available at this time.</p> + </div> + ) : ( {publications.map((publication) => ( <div key={`publication-${publication.id}`} className="publication-item"> {/* ... existing content ... */} </div> ))} + )} </div>src/hooks/useMobileDetection.js (1)
20-21
: Optimize useEffect dependencies.The effect uses
navigator.userAgent
which doesn't change during the component lifecycle, but the dependencies include media queries that do change. Consider splitting the logic or memoizing the user agent detection.useEffect(() => { const userAgent = navigator.userAgent || navigator.vendor || window.opera; - - // Detect mobile devices - const isMobile = isMobileQuery || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); + + // Device detection (static) + const isMobileDevice = /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); + const isTabletDevice = /iPad/i.test(userAgent); + const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream; + const isAndroid = /Android/i.test(userAgent); + const isSafari = /Safari/.test(userAgent) && !/Chrome/.test(userAgent); + const isChrome = /Chrome/.test(userAgent); + + // Combine with media queries + const isMobile = isMobileQuery || (isMobileDevice && !isTabletDevice); const isTablet = isTabletQuery && !isMobile;This makes the dependency relationship clearer.
src/components/DemoComputerSimple.jsx (1)
23-29
: Consider removingtxt
from useGSAP dependency array.The animation will re-trigger every time the video texture object changes, which may cause unintended re-animations. Since this appears to be a mount animation, consider using an empty dependency array or a more specific condition.
- useGSAP(() => { - gsap.from(group.current.rotation, { - y: Math.PI / 2, - duration: 1, - ease: 'power3.out', - }); - }, [txt]); + useGSAP(() => { + gsap.from(group.current.rotation, { + y: Math.PI / 2, + duration: 1, + ease: 'power3.out', + }); + }, []); // Empty dependency array for mount-only animationsrc/content/README.md (1)
117-117
: Minor style consideration: excessive exclamation marks.While the enthusiasm is appreciated, consider reducing the number of exclamation marks for a more professional tone in technical documentation.
-That's it! Super simple content management. 🎉 +That's it! Super simple content management. 🎉src/components/GlobalErrorBoundary.jsx (1)
21-21
: Consider implementing error reporting service.The comment suggests logging errors to an error reporting service, but this functionality is not implemented. Consider adding error reporting for production monitoring.
// You can also log the error to an error reporting service here + // Example: Sentry, LogRocket, or similar service + if (process.env.NODE_ENV === 'production') { + // errorReportingService.captureException(error, errorInfo); + }src/components/Developer.jsx (1)
34-50
: Remove debug logging before production deploymentThis debug logging appears to be development code. Consider removing it or placing it behind a debug flag to avoid console noise in production.
- // Debug: Log available nodes and materials - useEffect(() => { - console.log('=== JAN.GLB MODEL STRUCTURE ==='); - console.log('Available nodes:', Object.keys(nodes)); - console.log('Available materials:', Object.keys(materials)); - - // Log each node with its properties - Object.entries(nodes).forEach(([name, node]) => { - console.log(`Node: ${name}`, { - type: node.type, - hasGeometry: !!node.geometry, - hasMaterial: !!node.material, - hasChildren: node.children?.length > 0, - childrenCount: node.children?.length || 0 - }); - }); - }, [nodes, materials]); + // Debug logging (only in development) + useEffect(() => { + if (process.env.NODE_ENV === 'development') { + console.log('=== JAN.GLB MODEL STRUCTURE ==='); + console.log('Available nodes:', Object.keys(nodes)); + console.log('Available materials:', Object.keys(materials)); + + // Log each node with its properties + Object.entries(nodes).forEach(([name, node]) => { + console.log(`Node: ${name}`, { + type: node.type, + hasGeometry: !!node.geometry, + hasMaterial: !!node.material, + hasChildren: node.children?.length > 0, + childrenCount: node.children?.length || 0 + }); + }); + } + }, [nodes, materials]);src/utils/projectFallbacks.js (1)
20-23
: Use optional chaining for cleaner codeThe static analysis tool correctly identified an opportunity to use optional chaining for more concise code.
// Fallback to pattern matching const matches = videoPath.match(/project(\d+)\.mp4/); - if (matches && matches[1]) { + if (matches?.[1]) { return `/assets/project-logo${matches[1]}.png`; }EMAILJS_SETUP.md (1)
109-114
: Fix markdown formatting issue.The fenced code block is missing a language specification, which can cause rendering issues in some markdown parsers.
-``` +```env VITE_EMAILJS_SERVICE_ID=your_service_id_here VITE_EMAILJS_TEMPLATE_ID=your_contact_template_id_here VITE_EMAILJS_NEWSLETTER_TEMPLATE_ID=your_newsletter_template_id_here VITE_EMAILJS_PUBLIC_KEY=your_public_key_here -``` +```src/components/CanvasErrorBoundary.jsx (1)
47-49
: Consider more graceful retry mechanism.While
window.location.reload()
is simple, consider implementing a more granular retry that only reloads the Canvas component rather than the entire page.- <button - onClick={() => window.location.reload()} - className="btn text-sm px-4 py-2" - > - Retry - </button> + <button + onClick={() => { + // Try to remount the component first + if (typeof onRetry === 'function') { + onRetry(); + } else { + window.location.reload(); + } + }} + className="btn text-sm px-4 py-2" + > + Retry + </button>src/content/blogPosts.js (1)
1-1616
: Consider performance optimization for large static data.The blog posts contain extensive content (~1400+ lines), which could impact initial bundle size and loading performance. Consider implementing lazy loading or code splitting for blog content.
// Consider dynamic imports for blog content const loadBlogPost = async (id) => { const { blogPost } = await import(`./posts/post-${id}.js`); return blogPost; }; // Or implement content pagination export const getBlogPostsByPage = (page = 1, limit = 3) => { const start = (page - 1) * limit; return blogPosts.slice(start, start + limit); };CHARACTER_REPLACEMENT_GUIDE.md (2)
1-1
: Heading typoExtraneous
can#
at the start of the document header.-can# 3D Character Replacement Guide +# 3D Character Replacement Guide
124-134
: Add language identifier to fenced blockMarkdown-lint (
MD040
) flags the “File Structure” block. Tag it as plain text for proper rendering.-``` +```text public/ ├── models/ ...</blockquote></details> <details> <summary>cv.txt (2)</summary><blockquote> `28-32`: **Make contact details clickable** `hyperref` is loaded but links aren’t active. Wrapping them improves usability. ```diff -heimann.ai\\[0.2em] -jan@heimann.ai +\href{https://heimann.ai}{heimann.ai}\\[0.2em] +\href{mailto:jan@heimann.ai}{jan@heimann.ai}
132-136
: Hyphenate compound adjective“Open Source Library” acts as a modifier; the conventional form is “Open-Source Library.”
-\textbf{ArchUnit TypeScript - Open Source Library} +\textbf{ArchUnit TypeScript – Open-Source Library}src/content/blog/openrlhf-blog-post.md (1)
60-65
: Use modern--gpus
Docker flag
--runtime=nvidia
is deprecated. The contemporary, distribution-agnostic flag is--gpus
.-docker run --runtime=nvidia -it --rm --shm-size="10g" --cap-add=SYS_ADMIN -v $PWD:/openrlhf nvcr.io/nvidia/pytorch:24.07-py3 bash +docker run --gpus all -it --rm --shm-size="10g" --cap-add=SYS_ADMIN -v "$PWD":/openrlhf nvcr.io/nvidia/pytorch:24.07-py3 bashsrc/content/blog/langchain-basics-blog-post.md (1)
324-333
: Missing import forStrOutputParser
Snippet will fail with
NameError
. Include the import to keep the example copy-pasteable.-from langchain.schema.runnable import RunnablePassthrough +from langchain.schema.runnable import RunnablePassthrough +from langchain.output_parsers import StrOutputParsersrc/content/blog/future-of-ai-blog-post.md (1)
131-131
: Add language specification to fenced code block.The fenced code block should specify a language identifier for better syntax highlighting and accessibility.
-### 1. Develop an AI-First Mindset +### 1. Develop an AI-First MindsetWait, I apologize for the diff error. Let me provide the correct location and fix:
Since this appears to be showing a file/directory structure or plain text, add a language identifier:
-Stop thinking of AI as a technology to implement and start thinking of it as a capability to cultivate. Every business process, customer interaction, and strategic decision should be examined through the lens of AI enhancement. +Stop thinking of AI as a technology to implement and start thinking of it as a capability to cultivate. Every business process, customer interaction, and strategic decision should be examined through the lens of AI enhancement.Actually, I don't see the code block at line 131. The static analysis might be referring to content not shown in the provided excerpt. However, if there is an unmarked code block, it should include a language identifier.
VIDEO_REPLACEMENT_GUIDE.md (1)
131-140
: Add language specification to the directory structure code block.The fenced code block showing the file structure should include a language identifier.
-## File Structure -``` +## File Structure +```plaintext public/ ├── textures/ ├── project/src/constants/index.js (1)
188-418
: Consider extracting blog content to separate markdown files.While the current implementation works, storing full blog content as template literals in the constants file could become difficult to maintain as the blog grows. Consider loading markdown content from separate files using the contentLoader utility that appears to be implemented elsewhere in the codebase.
src/content/blog/cuda-basics-blog-post.md (1)
365-377
: Consider adding CUDA capability checking.The error checking macro is excellent. Consider also demonstrating how to check for CUDA device availability before running kernels.
// Add device capability checking int deviceCount; cudaGetDeviceCount(&deviceCount); if (deviceCount == 0) { fprintf(stderr, "No CUDA-capable devices found\n"); exit(1); }src/utils/contentLoader.js (2)
10-11
: Remove or replace console.log statements with proper logging.Debug console.log statements should be removed from production code or replaced with a proper logging solution that can be controlled via log levels.
Also applies to: 19-19, 23-23
97-97
: Remove unnecessary empty line.- - // Get all unique categoriessrc/content/blog/building-ai-powered-saas.md (3)
94-116
: Unused state & per-attemptClientSession
creation inAPIRateLimiter
.
request_counts
andlast_reset
are never referenced—either remove or demonstrate their use.- Creating a fresh
ClientSession
for every retry is wasteful; keep a long-lived session instead.class APIRateLimiter: def __init__(self): self.semaphores = { 'openai': asyncio.Semaphore(50), 'anthropic': asyncio.Semaphore(30) } - - async def make_request(self, provider, endpoint, data): - async with self.semaphores[provider]: - # Implement exponential backoff - for attempt in range(3): - try: - async with aiohttp.ClientSession() as session: - response = await session.post(endpoint, json=data) + self.session = aiohttp.ClientSession() + + async def make_request(self, provider, endpoint, data): + async with self.semaphores[provider]: + for attempt in range(3): + try: + response = await self.session.post(endpoint, json=data) if response.status == 200: return await response.json()
216-222
: Missing React imports inApplicationProgress
snippet.
useState
anduseEffect
are referenced without being imported.-import React from 'react' +import React, { useState, useEffect } from 'react'
223-224
: Use secure WebSockets (wss://
) in production examples.Hard-coding
ws://
can mislead readers into insecure implementations. Preferwss://
or show environment-driven selection.- const ws = new WebSocket(`ws://api.autoapply.co/progress/${applicationId}`); + const ws = new WebSocket(`wss://api.autoapply.co/progress/${applicationId}`);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (20)
package-lock.json
is excluded by!**/package-lock.json
public/assets/MongoDB_SpringGreen.png
is excluded by!**/*.png
public/assets/autoapply.png
is excluded by!**/*.png
public/assets/claude.png
is excluded by!**/*.png
public/assets/deepmask.png
is excluded by!**/*.png
public/assets/getmobie.png
is excluded by!**/*.png
public/assets/huggingface.png
is excluded by!**/*.png
public/assets/jan_ghibli.png
is excluded by!**/*.png
public/assets/linkedin.svg
is excluded by!**/*.svg
public/assets/mit.png
is excluded by!**/*.png
public/assets/ohb.png
is excluded by!**/*.png
public/assets/publication1.png
is excluded by!**/*.png
public/assets/python.png
is excluded by!**/*.png
public/assets/pytorch.png
is excluded by!**/*.png
public/assets/rfa.png
is excluded by!**/*.png
public/assets/x.svg
is excluded by!**/*.svg
public/favicon.ico
is excluded by!**/*.ico
public/textures/jan_photo.png
is excluded by!**/*.png
public/textures/project/autoapply.mp4
is excluded by!**/*.mp4
public/vite.svg
is excluded by!**/*.svg
📒 Files selected for processing (53)
CHARACTER_REPLACEMENT_GUIDE.md
(1 hunks)CLAUDE.md
(1 hunks)EMAILJS_SETUP.md
(1 hunks)README.md
(1 hunks)VIDEO_REPLACEMENT_GUIDE.md
(1 hunks)cv.txt
(1 hunks)debug_jan_model.js
(1 hunks)index.html
(1 hunks)package.json
(1 hunks)src/App.jsx
(2 hunks)src/components/BlogCard.jsx
(1 hunks)src/components/BlogPost.jsx
(1 hunks)src/components/CanvasErrorBoundary.jsx
(1 hunks)src/components/ClaudeLogo.jsx
(1 hunks)src/components/DemoComputer.jsx
(1 hunks)src/components/DemoComputerSimple.jsx
(1 hunks)src/components/Developer.jsx
(2 hunks)src/components/EnhancedCanvasLoader.jsx
(1 hunks)src/components/GlobalErrorBoundary.jsx
(1 hunks)src/components/HackerRoom.jsx
(1 hunks)src/components/HuggingFaceLogo.jsx
(1 hunks)src/components/MobileOptimizedCanvas.jsx
(1 hunks)src/components/MobileProjectDisplay.jsx
(1 hunks)src/components/MongoDBLogo.jsx
(1 hunks)src/components/PyTorchLogo.jsx
(1 hunks)src/components/PythonLogo.jsx
(1 hunks)src/constants/index.js
(1 hunks)src/content/README.md
(1 hunks)src/content/blog/_template.md
(1 hunks)src/content/blog/building-ai-powered-saas.md
(1 hunks)src/content/blog/cuda-basics-blog-post.md
(1 hunks)src/content/blog/future-of-ai-blog-post.md
(1 hunks)src/content/blog/graph-neural-networks-materials.md
(1 hunks)src/content/blog/langchain-basics-blog-post.md
(1 hunks)src/content/blog/mlflow-docker-pipelines.md
(1 hunks)src/content/blog/openrlhf-blog-post.md
(1 hunks)src/content/blog/pytorch-basics-blog-post.md
(1 hunks)src/content/blog/react-three-fiber-performance.md
(1 hunks)src/content/blogPosts.js
(1 hunks)src/hooks/useMobileDetection.js
(1 hunks)src/hooks/useMobileVideoTexture.js
(1 hunks)src/index.css
(1 hunks)src/sections/About.jsx
(5 hunks)src/sections/Blog.jsx
(1 hunks)src/sections/Clients.jsx
(0 hunks)src/sections/Contact.jsx
(2 hunks)src/sections/Footer.jsx
(1 hunks)src/sections/Hero.jsx
(1 hunks)src/sections/Navbar.jsx
(1 hunks)src/sections/Projects.jsx
(1 hunks)src/sections/Publications.jsx
(1 hunks)src/utils/contentLoader.js
(1 hunks)src/utils/projectFallbacks.js
(1 hunks)
💤 Files with no reviewable changes (1)
- src/sections/Clients.jsx
🧰 Additional context used
🧬 Code Graph Analysis (19)
src/components/PyTorchLogo.jsx (4)
src/components/ClaudeLogo.jsx (1)
texture
(4-4)src/components/HuggingFaceLogo.jsx (1)
texture
(4-4)src/components/MongoDBLogo.jsx (1)
texture
(4-4)src/components/PythonLogo.jsx (1)
texture
(4-4)
debug_jan_model.js (2)
src/components/Developer.jsx (3)
useGLTF
(15-15)clone
(16-16)useGraph
(17-17)src/components/HackerRoom.jsx (1)
useGLTF
(11-11)
src/sections/Publications.jsx (1)
src/constants/index.js (2)
publications
(28-43)publications
(28-43)
src/components/HuggingFaceLogo.jsx (4)
src/components/ClaudeLogo.jsx (1)
texture
(4-4)src/components/PyTorchLogo.jsx (1)
texture
(4-4)src/components/MongoDBLogo.jsx (1)
texture
(4-4)src/components/PythonLogo.jsx (1)
texture
(4-4)
src/components/PythonLogo.jsx (4)
src/components/ClaudeLogo.jsx (1)
texture
(4-4)src/components/HuggingFaceLogo.jsx (1)
texture
(4-4)src/components/PyTorchLogo.jsx (1)
texture
(4-4)src/components/MongoDBLogo.jsx (1)
texture
(4-4)
src/components/DemoComputer.jsx (1)
src/components/DemoComputerSimple.jsx (1)
txt
(11-15)
src/components/ClaudeLogo.jsx (4)
src/components/HuggingFaceLogo.jsx (1)
texture
(4-4)src/components/PyTorchLogo.jsx (1)
texture
(4-4)src/components/MongoDBLogo.jsx (1)
texture
(4-4)src/components/PythonLogo.jsx (1)
texture
(4-4)
src/hooks/useMobileDetection.js (7)
src/components/CanvasErrorBoundary.jsx (1)
deviceInfo
(28-28)src/components/EnhancedCanvasLoader.jsx (1)
deviceInfo
(8-8)src/sections/Projects.jsx (1)
deviceInfo
(14-14)src/components/MobileOptimizedCanvas.jsx (1)
deviceInfo
(6-6)src/components/MobileProjectDisplay.jsx (1)
deviceInfo
(5-5)src/hooks/useMobileVideoTexture.js (1)
deviceInfo
(6-6)src/sections/Hero.jsx (2)
isMobile
(16-16)isTablet
(17-17)
src/sections/Blog.jsx (6)
src/content/blogPosts.js (5)
categories
(1620-1620)getBlogCategories
(1619-1622)getBlogCategories
(1619-1622)blogPosts
(1-1616)blogPosts
(1-1616)src/sections/Contact.jsx (2)
useAlert
(10-10)form
(13-13)src/hooks/useAlert.js (3)
showAlert
(6-6)hideAlert
(7-7)alert
(4-4)src/components/BlogPost.jsx (1)
BlogPost
(5-167)src/components/Alert.jsx (1)
Alert
(1-19)src/components/BlogCard.jsx (1)
BlogCard
(3-75)
src/components/EnhancedCanvasLoader.jsx (1)
src/hooks/useMobileDetection.js (3)
deviceInfo
(5-14)useMobileDetection
(4-62)useMobileDetection
(4-62)
src/components/BlogCard.jsx (1)
src/components/BlogPost.jsx (1)
formatDate
(6-13)
src/components/MongoDBLogo.jsx (4)
src/components/ClaudeLogo.jsx (1)
texture
(4-4)src/components/HuggingFaceLogo.jsx (1)
texture
(4-4)src/components/PyTorchLogo.jsx (1)
texture
(4-4)src/components/PythonLogo.jsx (1)
texture
(4-4)
src/components/CanvasErrorBoundary.jsx (1)
src/hooks/useMobileDetection.js (3)
deviceInfo
(5-14)useMobileDetection
(4-62)useMobileDetection
(4-62)
src/components/MobileOptimizedCanvas.jsx (1)
src/hooks/useMobileDetection.js (3)
deviceInfo
(5-14)useMobileDetection
(4-62)useMobileDetection
(4-62)
src/sections/Projects.jsx (5)
src/components/MobileProjectDisplay.jsx (2)
deviceInfo
(5-5)MobileProjectDisplay
(4-47)src/hooks/useMobileDetection.js (3)
deviceInfo
(5-14)useMobileDetection
(4-62)useMobileDetection
(4-62)src/constants/index.js (2)
myProjects
(45-186)myProjects
(45-186)src/components/Loading.jsx (1)
CanvasLoader
(3-27)src/components/DemoComputer.jsx (2)
group
(11-11)DemoComputer
(10-1017)
src/content/blogPosts.js (3)
src/constants/index.js (2)
blogPosts
(188-418)blogPosts
(188-418)src/utils/contentLoader.js (8)
getBlogCategories
(99-103)getBlogCategories
(99-103)categories
(101-101)getBlogPostsByCategory
(92-95)getBlogPostsByCategory
(92-95)searchBlogPosts
(113-123)searchBlogPosts
(113-123)searchTerm
(115-115)src/sections/Blog.jsx (2)
categories
(18-18)searchTerm
(11-11)
src/components/BlogPost.jsx (1)
src/components/BlogCard.jsx (1)
formatDate
(6-13)
src/components/DemoComputerSimple.jsx (1)
src/components/DemoComputer.jsx (3)
group
(11-11)useGLTF
(12-12)txt
(16-20)
src/utils/contentLoader.js (2)
src/content/blogPosts.js (8)
getBlogPostsByCategory
(1629-1632)getBlogPostsByCategory
(1629-1632)getBlogCategories
(1619-1622)getBlogCategories
(1619-1622)categories
(1620-1620)searchBlogPosts
(1634-1641)searchBlogPosts
(1634-1641)searchTerm
(1635-1635)src/sections/Blog.jsx (2)
categories
(18-18)searchTerm
(11-11)
🪛 LanguageTool
src/content/README.md
[style] ~117-~117: Using many exclamation marks might seem excessive (in this case: 5 exclamation marks for a text that’s 2092 characters long)
Context: ...Opinion", "Industry Analysis" That's it! Super simple content management. 🎉
(EN_EXCESSIVE_EXCLAMATION)
src/content/blog/react-three-fiber-performance.md
[style] ~100-~100: Consider a different adjective to strengthen your wording.
Context: ...rformant 3D web applications requires a deep understanding of both React and Three.j...
(DEEP_PROFOUND)
src/content/blog/building-ai-powered-saas.md
[style] ~296-~296: Consider using a less common alternative to make your writing sound more unique and professional.
Context: ...bout building AI-powered SaaS products? Feel free to reach out – I'm always happy to share i...
(FEEL_FREE_TO_STYLE_ME)
cv.txt
[uncategorized] ~132-~132: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...itemize} \textbf{ArchUnit TypeScript - Open Source Library} \begin{itemize}[leftmargin=*, ...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 Biome (1.9.4)
src/utils/projectFallbacks.js
[error] 21-21: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 markdownlint-cli2 (0.17.2)
EMAILJS_SETUP.md
131-131: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
src/content/blog/future-of-ai-blog-post.md
131-131: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
CHARACTER_REPLACEMENT_GUIDE.md
16-16: Bare URL used
(MD034, no-bare-urls)
17-17: Bare URL used
(MD034, no-bare-urls)
38-38: Bare URL used
(MD034, no-bare-urls)
49-49: Bare URL used
(MD034, no-bare-urls)
61-61: Bare URL used
(MD034, no-bare-urls)
124-124: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
VIDEO_REPLACEMENT_GUIDE.md
131-131: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (64)
src/sections/Navbar.jsx (1)
28-28
: LGTM: Clean branding update.The navigation brand text has been properly updated to reflect the new portfolio owner. This change aligns with the broader rebranding effort across the application.
package.json (1)
18-18
: LGTM: Appropriate dependencies for blog functionality.The new dependencies are well-chosen for implementing markdown-based blog functionality:
gray-matter
for parsing frontmatter in markdown filesreact-markdown
for rendering markdown contentreact-syntax-highlighter
for code syntax highlightingThese are standard, well-maintained packages that align with the blog feature implementation described in the AI summary.
Also applies to: 26-26, 28-28
src/App.jsx (2)
18-18
: LGTM: Logical component restructuring.The component structure has been appropriately updated:
- Replaced
<Clients />
with<Publications />
to focus on research/academic work- Added
<Blog />
component positioned logically between work experience and contact sectionsThis restructuring aligns with the portfolio's shift towards AI/ML engineering and research focus.
Also applies to: 20-20
6-6
: Imports Verified: Publications and Blog components exist; Clients component removed
- src/sections/Publications.jsx found
- src/sections/Blog.jsx found
- src/sections/Clients.jsx not found (as expected)
All component imports are correct and the restructuring is approved.
index.html (2)
6-6
: LGTM: Favicon format improvement.The favicon has been updated from SVG to ICO format, which provides better cross-browser compatibility. Ensure the
favicon.ico
file exists in the public directory.
8-8
: LGTM: Professional title update.The page title has been properly updated to reflect the new portfolio owner and their specialization in AI/ML engineering. This enhances SEO and browser tab identification.
README.md (2)
14-14
: LGTM: Professional heading improvement.The heading has been refined from "A 3D Dev Portfolio" to "3D Developer Portfolio" for a more professional and concise presentation.
1-870
: LGTM: Appropriate content cleanup.The README has been streamlined by removing promotional content while maintaining all technical documentation. This makes the repository more focused on the actual project rather than external courses and tutorials, which is appropriate for a personal portfolio.
src/components/DemoComputer.jsx (1)
15-20
: Good refactoring - cleaner and more predictable.The direct usage of
props.texture
with the options object is cleaner than the previous fallback mechanism and aligns well with the pattern used inDemoComputerSimple.jsx
. This makes the component's behavior more explicit and predictable.src/components/HackerRoom.jsx (1)
35-40
: Material change is appropriate for photo display.The switch from
meshMatcapMaterial
tomeshBasicMaterial
withtoneMapped={false}
andside={2}
is well-suited for displaying a photo texture with proper lighting and visibility from both sides.src/sections/Contact.jsx (2)
25-34
: Environment variable and recipient updates look good.The simplified environment variable names (removing
_APP
segment) and updated recipient details are consistent with the project's rebranding to Jan Magnus Heimann's profile.
77-77
: Text update aligns with AI/ML focus.The updated descriptive text effectively communicates the new focus on AI/ML solutions and research opportunities, consistent with the overall rebranding.
src/sections/Hero.jsx (2)
25-25
: Greeting update is consistent with rebranding.The personalized greeting properly reflects the new identity as part of the coordinated rebranding effort.
27-27
: Subtitle effectively communicates the new professional focus.The updated subtitle clearly conveys the AI/ML engineering and research specialization, aligning with the project's thematic shift.
src/sections/Footer.jsx (2)
11-19
: Social media links are properly implemented.The anchor elements with external URLs,
target="_blank"
, andrel="noopener noreferrer"
are correctly implemented for security and user experience.
22-22
: Copyright update is consistent with rebranding.The updated copyright text properly reflects the new identity and current year.
src/components/MongoDBLogo.jsx (1)
8-14
: LGTM! Consistent implementation with other logo components.The component structure, positioning, and resource management are well-implemented and consistent with the pattern used in other logo components (PythonLogo, ClaudeLogo, etc.).
src/sections/Publications.jsx (1)
54-85
: LGTM! Good implementation of publication links with proper accessibility.The external links are properly implemented with
target="_blank"
,rel="noreferrer"
, and appropriate visual indicators. The conditional rendering for different link types (PDF, arXiv, code) provides good flexibility.src/content/blog/_template.md (3)
1-10
: LGTM! Comprehensive and well-structured frontmatter.The frontmatter includes all necessary fields for a blog system: title, excerpt, author, date, readTime, tags, category, and featured flag. The structure is consistent and follows markdown best practices.
31-62
: Excellent code examples demonstrating multiple languages.The code examples are well-structured and demonstrate proper syntax highlighting for both Python and JavaScript/React. The examples are practical and show realistic use cases.
82-92
: Clear and actionable template instructions.The usage instructions are comprehensive and provide clear guidance on filename conventions, frontmatter usage, and content formatting. This will help ensure consistency across blog posts.
src/hooks/useMobileDetection.js (1)
36-47
: Good video texture support logic.The logic for determining video texture support is well-thought-out, specifically targeting known problematic combinations (iOS Safari and small Android devices) while maintaining support for other devices.
src/components/MobileProjectDisplay.jsx (4)
8-10
: LGTM! Clean conditional rendering approach.The early return pattern for mobile-only rendering is clean and efficient. Non-mobile devices appropriately return null, allowing the 3D canvas to handle desktop rendering.
20-28
: Excellent error handling for image loading.The
onError
handler provides a good fallback mechanism, defaulting to a project logo when the generated fallback image fails to load. This ensures the component remains functional even with missing assets.
30-36
: Good UX messaging for mobile users.The text clearly communicates to mobile users that they're seeing a preview and can experience the full 3D demo on desktop. This sets appropriate expectations and encourages desktop usage for the full experience.
38-41
: Nice decorative elements for visual appeal.The positioned blur circles add subtle visual interest without being distracting. The use of low opacity and blur effects creates a polished look.
src/content/blog/mlflow-docker-pipelines.md (1)
1-59
: Well-structured technical blog post with comprehensive coverage.The article effectively covers MLflow and Docker integration for ML pipelines. The frontmatter is properly formatted with all required fields, the content structure is logical, and the Python code example demonstrates correct MLflow usage patterns.
src/components/DemoComputerSimple.jsx (1)
6-96
: Clean 3D component implementation with proper resource management.The component properly implements video texture loading, GSAP animation, and GLTF model preloading. The structure follows React Three Fiber best practices with proper disposal and ref management.
src/content/README.md (1)
1-117
: Excellent documentation with clear instructions and examples.The guide provides comprehensive coverage of the blog management system with helpful examples, field explanations, and pro tips. This will be valuable for contributors adding new content.
src/components/EnhancedCanvasLoader.jsx (1)
5-88
: Well-designed loading component with comprehensive error handling.The component effectively handles loading states, timeouts, and mobile-specific UX considerations. The timeout mechanism and retry functionality provide good user experience for loading failures.
src/components/BlogCard.jsx (1)
3-77
: Well-designed blog card with excellent user experience.The component implements clean hover effects, responsive design, and proper content truncation. The tag display logic with overflow handling and the interactive elements provide good UX.
src/index.css (1)
70-124
: Well-structured publications section styling!The new publication utility classes are comprehensive and follow Tailwind CSS conventions well. The hover effects, responsive design, and semantic naming make this a solid addition to the design system.
src/content/blog/graph-neural-networks-materials.md (1)
1-73
: Excellent technical blog post!The blog post is well-structured with comprehensive coverage of Graph Neural Networks for materials discovery. The PyTorch Geometric implementation example is accurate and the content flows logically from problem to solution to results.
src/components/GlobalErrorBoundary.jsx (1)
28-81
: Solid error boundary implementation!The error boundary provides a comprehensive fallback UI with clear user actions (refresh/retry) and development-only error details. The implementation follows React error boundary best practices.
src/sections/About.jsx (2)
36-54
: Nice improvement to the tech stack visualization!The new grid layout for technology logos is a significant visual improvement over the previous single image. The layout is responsive and well-organized.
10-113
: Consistent personal information updates!All personal information has been updated consistently throughout the component, including email, location, and professional focus. The changes align well with the AI/ML engineering rebrand.
src/sections/Blog.jsx (2)
20-32
: Efficient filtering and search implementation!The filtering logic is well-implemented with proper search across title, excerpt, and tags. The combination of search and category filtering provides a good user experience.
42-85
: Robust newsletter subscription handling!The email subscription implementation with EmailJS is well-structured with proper loading states, error handling, and user feedback. The form validation and async handling follow best practices.
src/components/Developer.jsx (2)
57-78
: Good defensive programming with the renderMesh helperThe
renderMesh
helper function properly handles missing nodes and materials, preventing potential runtime errors. This is a robust approach for handling dynamic 3D model structures.
100-104
: Excellent addition of animation preloadingPreloading the FBX animation files helps reduce loading warnings and improves the user experience by ensuring animations are ready when needed.
src/components/BlogPost.jsx (1)
84-93
: Good security practices for external linksThe anchor component properly includes
target="_blank"
withrel="noopener noreferrer"
to prevent security vulnerabilities and protect user privacy.src/components/MobileOptimizedCanvas.jsx (1)
74-86
: Excellent mobile-specific optimizationsThe mobile Canvas configuration properly limits pixel ratio, disables antialiasing, and uses low-power GPU preference. These optimizations will significantly improve performance on mobile devices.
src/sections/Projects.jsx (4)
14-14
: Good use of mobile detection for responsive UX.The integration of
useMobileDetection
enables a device-aware user experience, which is essential for 3D content that may not perform well on mobile devices.
17-18
: Animation approach correctly updated for new structure.The GSAP animation now triggers on mount for all project cards simultaneously with proper staggering, which is appropriate for the new multi-project display format.
64-83
: Well-implemented conditional rendering for mobile optimization.The logic clearly separates mobile 2D previews from desktop 3D canvas rendering. The Canvas configuration with proper lighting, controls, and Suspense wrapper is solid.
69-69
: Confirm camera defaults in Projects.jsx for consistencyI’ve verified that
Projects.jsx
sets the camera to{ position: [0, 0, 5], fov: 75 }
, and there are no other instances offov: 75
in this file. Note that the hero section (HeroCamera.jsx
) animates its camera toward[0, 0, 20]
, so the Projects canvas setting is standalone.• Please manually test the Projects canvas across different project models and screen sizes to ensure the framing and FOV remain appropriate.
• If you plan to standardize camera behavior across scenes, consider centralizing these default parameters or documenting this configuration.EMAILJS_SETUP.md (1)
1-151
: Excellent comprehensive setup guide.This documentation provides thorough coverage of EmailJS setup, including environment variables, templates, deployment, and troubleshooting. The step-by-step approach makes it accessible for developers at different skill levels.
src/hooks/useMobileVideoTexture.js (4)
5-23
: Excellent mobile-first approach for video texture handling.The conditional logic properly handles device capabilities and provides appropriate fallbacks. The immediate loading state resolution for mobile devices prevents unnecessary loading states.
48-56
: Comprehensive iOS Safari video handling.The specific handling for iOS Safari with
webkit-playsinline
and forced muted attributes addresses known compatibility issues. This is a thoughtful implementation.
75-78
: Proper cleanup of event listeners.The cleanup function correctly removes event listeners to prevent memory leaks. Good practice for React hooks.
26-31
: Verify resource allocation when src is nullDouble-check that passing
null
intouseVideoTexture
(from@react-three/drei
) truly skips creating a<video>
element or GPU texture under the hood. If it still allocates resources, gate the hook call instead of passingnull
:const videoTexture = shouldUseVideo ? useVideoTexture(src, { muted: true, loop: true, playsInline: true, autoPlay: true, }) : null;Points to verify:
- No hidden
<video>
element is instantiated whensrc
isnull
- No WebGL texture or internal buffer is allocated in that case
- How the library handles a
null
argument in its source or docssrc/components/CanvasErrorBoundary.jsx (2)
4-25
: Solid error boundary implementation.The component follows React error boundary patterns correctly with proper error state management and logging. The optional fallback prop provides flexibility.
27-56
: Excellent device-aware error fallback UI.The fallback component provides contextual messaging based on device type and includes a clear retry mechanism. The styling is consistent with the application's design system.
src/content/blogPosts.js (3)
1-1616
: Comprehensive blog post data structure.The blog posts contain high-quality technical content with consistent metadata structure. The detailed coverage of AI/ML topics provides valuable educational content.
1619-1641
: Well-implemented utility functions.The utility functions for categories, filtering, and searching are clean and functional. The case-insensitive search across multiple fields provides good user experience.
11-19
: Assess placeholder content strategy in blogPosts.jsOnly one “Coming Soon” placeholder was found in your blog posts data. Confirm this aligns with the intended UX and consider flagging unpublished entries instead of embedding placeholder text directly.
• File: src/content/blogPosts.js (lines 11–19)
content: `## Coming Soon This detailed case study about building AutoApply is currently being prepared and will be available soon. … *Check back soon for the full story of how AutoApply was built from concept to 10000+ active users.*`Suggestions:
- Introduce a
status: 'draft' | 'published'
field on each post and only rendercontent
whenstatus === 'published'
.- For draft posts, render a generic “Coming Soon” banner in the UI instead of hard-coding placeholder markdown.
- Confirm with the product/UX team that this placeholder approach meets user expectations.
CLAUDE.md (1)
1-88
: Well-structured documentation with comprehensive coverage!The documentation provides excellent guidance for developers working with the codebase. The use of VITE_ prefix for environment variables is correct, and the security reminder about not committing
.env.local
is crucial.VIDEO_REPLACEMENT_GUIDE.md (1)
178-188
: Excellent code examples for advanced customization!The JSX examples effectively demonstrate how to use video textures dynamically. The examples follow React best practices and are clear for developers to understand.
src/constants/index.js (4)
1-26
: Navigation links properly updated with Blog section.The addition of the Blog navigation link is well-integrated, maintaining consistent structure and proper anchor references.
433-487
: Excellent work experience updates with quantifiable achievements!The work experiences effectively highlight ML/AI expertise with specific metrics and technical details. The responsive positioning in
calculateSizes
is well-implemented.
45-186
: All referenced project assets verifiedAll texture videos and logo images exist in the specified paths under
public/textures/project/
andpublic/assets/
. No further changes are needed—ready to merge.
28-43
: Publication image path verifiedThe file
public/assets/publication1.png
exists, so the/assets/publication1.png
reference is valid. No changes needed.src/content/blog/cuda-basics-blog-post.md (1)
1-456
: Outstanding CUDA tutorial with comprehensive coverage!This blog post provides an excellent introduction to CUDA programming with:
- Clear explanations of core concepts
- Well-commented code examples
- Proper error handling demonstrations
- Performance optimization techniques
- Real-world application examples
The code examples are syntactically correct and follow CUDA best practices.
src/content/blog/building-ai-powered-saas.md (1)
32-35
: Parameter type mismatch:job_url
vs.screenshot
.
process_application()
forwardsjob_url
toself.form_detector.detect_forms(job_url)
, yetFormDetector.detect_forms()
expects an image (variablescreenshot
). This conceptual mismatch makes the example misleading.- # 1. Detect form elements using computer vision - form_elements = await self.form_detector.detect_forms(job_url) + # 1. Detect form elements using computer vision + screenshot = await take_screenshot(job_url) # illustrative helper + form_elements = await self.form_detector.detect_forms(screenshot)Either show a helper that captures a screenshot or rename the parameter to clarify the expected input.
import { Float, useTexture } from '@react-three/drei'; | ||
|
||
const PythonLogo = (props) => { | ||
const texture = useTexture('/assets/python.png'); | ||
|
||
return ( | ||
<Float floatIntensity={1}> | ||
<group position={[8, 8, 0]} scale={0.8} {...props} dispose={null}> | ||
<mesh rotation={[0, 0, 0]}> | ||
<planeGeometry args={[2, 2]} /> | ||
<meshStandardMaterial map={texture} transparent /> | ||
</mesh> | ||
</group> | ||
</Float> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
DRY: factor repeated logo-plane logic into a reusable component
Five new logo files share 100 % identical structure except for:
• texture path
• floatIntensity
• scale
• plane size
Create a generic FloatingLogoPlane
component (or hook) and pass these values as props.
This slashes duplicate code, eases future tweaks (e.g., adding a border or hover effect), and keeps render trees consistent.
🤖 Prompt for AI Agents
In src/components/PythonLogo.jsx lines 1 to 16, the logo rendering logic is
duplicated across multiple files with only texture path, floatIntensity, scale,
and plane size differing. Refactor by creating a reusable FloatingLogoPlane
component that accepts these values as props. Replace the current PythonLogo
component with this generic component, passing the specific values for the
Python logo. This will reduce code duplication and simplify future updates.
<group position={[8, 8, 0]} scale={0.8} {...props} dispose={null}> | ||
<mesh rotation={[0, 0, 0]}> | ||
<planeGeometry args={[2, 2]} /> | ||
<meshStandardMaterial map={texture} transparent /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove dispose={null}
– it is ineffective on <group>
and masks real disposal control
The dispose
prop is only respected by <primitive>
or material / geometry elements.
Adding it to <group>
creates a user-defined property that will never be read, potentially hiding real memory-management bugs. Simply omit the prop or place it on the resources that actually support disposal.
- <group position={[8, 8, 0]} scale={0.8} {...props} dispose={null}>
+ <group position={[8, 8, 0]} scale={0.8} {...props}>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<group position={[8, 8, 0]} scale={0.8} {...props} dispose={null}> | |
<mesh rotation={[0, 0, 0]}> | |
<planeGeometry args={[2, 2]} /> | |
<meshStandardMaterial map={texture} transparent /> | |
<group position={[8, 8, 0]} scale={0.8} {...props}> | |
<mesh rotation={[0, 0, 0]}> | |
<planeGeometry args={[2, 2]} /> | |
<meshStandardMaterial map={texture} transparent /> |
🤖 Prompt for AI Agents
In src/components/PythonLogo.jsx around lines 8 to 11, remove the dispose={null}
prop from the <group> element because it has no effect there and can mask real
disposal issues. Instead, omit this prop entirely from the <group> and only use
dispose on elements like <primitive>, materials, or geometries that support
disposal.
{publication.workshop && ( | ||
<p className="publication-workshop-subtitle"> | ||
NeurIPS: {publication.workshop} → {publication.workshopFull} | ||
</p> | ||
)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove hardcoded conference assumption.
The hardcoded "NeurIPS: " text assumes all publications are NeurIPS workshops, which limits the component's flexibility for future publications from other conferences.
- {publication.workshop && (
- <p className="publication-workshop-subtitle">
- NeurIPS: {publication.workshop} → {publication.workshopFull}
- </p>
- )}
+ {publication.workshop && (
+ <p className="publication-workshop-subtitle">
+ {publication.conference}: {publication.workshop} → {publication.workshopFull}
+ </p>
+ )}
This makes the component more flexible for publications from different conferences.
🤖 Prompt for AI Agents
In src/sections/Publications.jsx around lines 29 to 33, remove the hardcoded
"NeurIPS: " prefix before the workshop name to avoid assuming all publications
are from NeurIPS. Instead, display only the workshop and workshopFull values
dynamically to make the component flexible for publications from any conference.
const isMobile = isMobileQuery || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); | ||
const isTablet = isTabletQuery && !isMobile; | ||
const isDesktop = !isMobile && !isTablet; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix tablet detection logic.
The current logic for tablet detection is inconsistent. Line 24 includes tablet devices in the mobile detection, but line 25 excludes mobile devices from tablet detection, which creates a logical contradiction.
- const isMobile = isMobileQuery || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
- const isTablet = isTabletQuery && !isMobile;
+ const isMobileDevice = /Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
+ const isTabletDevice = /iPad/i.test(userAgent);
+
+ const isMobile = isMobileQuery || (isMobileDevice && !isTabletDevice);
+ const isTablet = isTabletQuery || isTabletDevice;
This separates the device detection logic from the screen size logic more clearly.
🤖 Prompt for AI Agents
In src/hooks/useMobileDetection.js around lines 24 to 26, the tablet detection
logic is inconsistent because tablet devices are included in the mobile
detection check, but then excluded from tablet detection, causing a
contradiction. To fix this, adjust the isMobile definition to exclude tablets by
removing tablet devices from the mobile regex or condition, and then define
isTablet independently based on tablet-specific criteria without excluding
mobile devices. This will clearly separate device type detection from screen
size logic.
useEffect(() => { | ||
const timer = setTimeout(() => { | ||
if (progress < 100) { | ||
setIsTimedOut(true); | ||
onTimeout?.(); | ||
} | ||
}, timeout); | ||
|
||
return () => clearTimeout(timer); | ||
}, [progress, timeout, onTimeout]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential issue with useEffect dependency array.
Including onTimeout
in the dependency array could cause the timeout to reset on every render if onTimeout
is an inline function. Consider using useCallback
for the onTimeout
prop or removing it from dependencies if it's not expected to change.
useEffect(() => {
const timer = setTimeout(() => {
if (progress < 100) {
setIsTimedOut(true);
onTimeout?.();
}
}, timeout);
return () => clearTimeout(timer);
- }, [progress, timeout, onTimeout]);
+ }, [progress, timeout]); // Remove onTimeout if it's not expected to change
Alternatively, if onTimeout
needs to be in dependencies, ensure it's wrapped with useCallback
in the parent component.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
useEffect(() => { | |
const timer = setTimeout(() => { | |
if (progress < 100) { | |
setIsTimedOut(true); | |
onTimeout?.(); | |
} | |
}, timeout); | |
return () => clearTimeout(timer); | |
}, [progress, timeout, onTimeout]); | |
useEffect(() => { | |
const timer = setTimeout(() => { | |
if (progress < 100) { | |
setIsTimedOut(true); | |
onTimeout?.(); | |
} | |
}, timeout); | |
return () => clearTimeout(timer); | |
}, [progress, timeout]); // Remove onTimeout if it's not expected to change |
🤖 Prompt for AI Agents
In src/components/EnhancedCanvasLoader.jsx around lines 10 to 19, the useEffect
hook includes onTimeout in its dependency array, which may cause the timeout to
reset on every render if onTimeout is an inline function. To fix this, either
remove onTimeout from the dependency array if it does not change, or ensure that
the onTimeout prop passed from the parent component is memoized using
useCallback to prevent unnecessary resets.
category: frontmatter.category, | ||
content: markdownContent, | ||
// Additional metadata | ||
lastModified: new Date().toISOString(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
lastModified should reflect actual file modification time.
Setting lastModified to the current time defeats its purpose. This field should represent when the content was actually last modified.
Since Vite's import.meta.glob doesn't provide file stats, consider removing this field or documenting that it represents the build time:
-lastModified: new Date().toISOString(),
+// Remove lastModified or rename to clarify its meaning
+buildTime: new Date().toISOString(),
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
lastModified: new Date().toISOString(), | |
// Remove lastModified or rename to clarify its meaning | |
buildTime: new Date().toISOString(), |
🤖 Prompt for AI Agents
In src/utils/contentLoader.js at line 59, the lastModified field is set to the
current time, which does not reflect the actual file modification time. Since
import.meta.glob does not provide file stats, either remove the lastModified
field entirely or update the code and documentation to clarify that lastModified
represents the build time, not the file's true modification time.
categories: getBlogCategories().length - 1, // Exclude 'All' | ||
tags: getBlogTags().length, | ||
totalWords: posts.reduce((acc, post) => acc + post.wordCount, 0), | ||
averageReadTime: Math.ceil(posts.reduce((acc, post) => acc + post.estimatedReadTime, 0) / posts.length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential division by zero error.
If there are no blog posts, posts.length
will be 0, causing averageReadTime
to be NaN
.
Add a check for empty posts array:
-averageReadTime: Math.ceil(posts.reduce((acc, post) => acc + post.estimatedReadTime, 0) / posts.length)
+averageReadTime: posts.length > 0 ? Math.ceil(posts.reduce((acc, post) => acc + post.estimatedReadTime, 0) / posts.length) : 0
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
averageReadTime: Math.ceil(posts.reduce((acc, post) => acc + post.estimatedReadTime, 0) / posts.length) | |
averageReadTime: posts.length > 0 | |
? Math.ceil(posts.reduce((acc, post) => acc + post.estimatedReadTime, 0) / posts.length) | |
: 0 |
🤖 Prompt for AI Agents
In src/utils/contentLoader.js at line 134, the calculation of averageReadTime
divides by posts.length without checking if posts is empty, which can cause a
division by zero and result in NaN. Fix this by adding a condition to check if
posts.length is greater than zero before performing the division; if posts is
empty, set averageReadTime to 0 or an appropriate default value.
const slug = filename.toLowerCase().replace(/[^a-z0-9]+/g, '-'); | ||
|
||
// Generate ID from filename hash (simple approach) | ||
const id = filename.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weak ID generation method prone to collisions.
Using the sum of character codes to generate IDs can easily result in collisions. For example, "abc" and "bac" would generate the same ID.
Consider using a more robust ID generation method:
-const id = filename.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
+const id = filename; // Use filename as ID since it's unique
+// Or use a hash function:
+// const id = crypto.createHash('md5').update(filename).digest('hex').substring(0, 8);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const id = filename.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); | |
// Replace weak character-sum ID with the filename (which is already unique), | |
// or switch to a hash if you need a shorter fixed-length ID: | |
- const id = filename.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); | |
+ const id = filename; // Use filename as ID since it's unique | |
+ // Or use a hash function: | |
+ // const id = crypto.createHash('md5').update(filename).digest('hex').substring(0, 8); |
🤖 Prompt for AI Agents
In src/utils/contentLoader.js at line 31, the current ID generation uses the sum
of character codes, which can cause collisions for different strings with the
same characters in different orders. Replace this with a more robust method such
as using a hash function (e.g., SHA-256 or a simple hash algorithm) on the
filename string to generate a unique and consistent ID that minimizes
collisions.
const posts = processMarkdownFiles(); | ||
|
||
// Sort posts by date (newest first) | ||
posts.sort((a, b) => new Date(b.date) - new Date(a.date)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add date validation to prevent runtime errors.
Date parsing without validation could throw errors if the date format is invalid or malformed.
Add validation:
-posts.sort((a, b) => new Date(b.date) - new Date(a.date));
+posts.sort((a, b) => {
+ const dateA = new Date(a.date);
+ const dateB = new Date(b.date);
+ if (isNaN(dateA) || isNaN(dateB)) {
+ console.error('Invalid date found in blog posts');
+ return 0;
+ }
+ return dateB - dateA;
+});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
posts.sort((a, b) => new Date(b.date) - new Date(a.date)); | |
posts.sort((a, b) => { | |
const dateA = new Date(a.date); | |
const dateB = new Date(b.date); | |
if (isNaN(dateA) || isNaN(dateB)) { | |
console.error('Invalid date found in blog posts'); | |
return 0; | |
} | |
return dateB - dateA; | |
}); |
🤖 Prompt for AI Agents
In src/utils/contentLoader.js at line 76, the current sorting of posts by date
directly parses dates without validation, which can cause runtime errors if the
date format is invalid. Add validation to check if both dates are valid before
comparing; if either date is invalid, handle it gracefully by placing invalid
dates at the end or skipping them to prevent errors during sorting.
# 4. Quality assurance | ||
validated_responses = await self.quality_checker.validate(responses) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent API: .validate
is undefined on QualityAssuranceAgent
.
The call quality_checker.validate(responses)
does not match the later class definition, which exposes validate_response(...)
.
- validated_responses = await self.quality_checker.validate(responses)
+ validated_responses = await self.quality_checker.validate_response(
+ responses,
+ job_data["requirements"] # or whatever object holds requirements
+ )
Readers copy-pasting the snippet will hit an AttributeError.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
# 4. Quality assurance | |
validated_responses = await self.quality_checker.validate(responses) | |
# 4. Quality assurance | |
- validated_responses = await self.quality_checker.validate(responses) | |
+ validated_responses = await self.quality_checker.validate_response( | |
+ responses, | |
+ job_data["requirements"] # or whatever object holds requirements | |
+ ) |
🤖 Prompt for AI Agents
In src/content/blog/building-ai-powered-saas.md around lines 44 to 46, the
method call to quality_checker.validate(responses) is incorrect because the
QualityAssuranceAgent class defines the method as validate_response, not
validate. Update the code to call quality_checker.validate_response(responses)
to match the class definition and avoid AttributeError.
Summary by CodeRabbit
New Features
Content Updates
Bug Fixes
Documentation
Refactor
Chores