diff --git a/src/assets/foxrenderfarm-arch-linux.png b/src/assets/foxrenderfarm-arch-linux.png new file mode 100644 index 0000000..f3e9280 Binary files /dev/null and b/src/assets/foxrenderfarm-arch-linux.png differ diff --git a/src/content/blog/coder-to-orchestrator.mdx b/src/content/blog/coder-to-orchestrator.mdx index 7dbd623..33978cf 100644 --- a/src/content/blog/coder-to-orchestrator.mdx +++ b/src/content/blog/coder-to-orchestrator.mdx @@ -3,7 +3,7 @@ title: 'Building Your Own Tools: From VFX Artist to Developer' description: 'Self-Hosting and AI Development in 2024: Why I build custom software instead of using cloud solutions, and how you can too without being a hardcore developer.' pubDate: 'Dec 8 2024' heroImage: '../../assets/claude-nuke.png' -featured: true +featured: false category: 'Development' tags: ['AI/ML', 'Self-Hosting', 'Open Source', 'Development', 'Automation'] --- @@ -74,4 +74,4 @@ Two years ago, saying "I'm building a Notion replacement" would've sounded delus That's the shift. We've gone from "this is impossible" to "this is just a weekend project if I plan it right." -And honestly? I'm excited to see where this goes. The next few years are going to be wild. \ No newline at end of file +And honestly? I'm excited to see where this goes. The next few years are going to be wild. diff --git a/src/content/blog/installing-raysync-and-foxrenderfarm-on-arch-linux.mdx b/src/content/blog/installing-raysync-and-foxrenderfarm-on-arch-linux.mdx new file mode 100644 index 0000000..002da2b --- /dev/null +++ b/src/content/blog/installing-raysync-and-foxrenderfarm-on-arch-linux.mdx @@ -0,0 +1,342 @@ +--- +title: 'How to use Fox Renderfarm on Arch Linux' +description: 'A practical guide to getting Raysync and FoxRenderfarm working on Arch Linux.' +pubDate: 'Dec 14 2025' +heroImage: '../../assets/foxrenderfarm-arch-linux.png' +featured: true +category: 'Pipeline' +tags: ['Linux', 'Pipeline', 'Rendering', 'DevOps', 'Tutorial'] +--- + +## Introduction + +If you're a VFX or 3D artist who's made the leap to Arch (or any rolling release distro), you've probably hit this wall before. Proprietary software packaged as `.deb` files, legacy library dependencies, and that sinking feeling when you find that you are the first person on the internet to have ever tried to install a specific software on Arch. + +This guide walks through my process of installing **Raysync** (file transfer acceleration) and the desktop client for **[FoxRenderfarm](https://www.foxrenderfarm.com/download.html)** on Arch Linux. Both only ship `.deb` packages and `.run` installers designed for Rocky Linux and CentOS7. + +I don't suspect this guide will work forever, but my hope in posting this is that others can reference this and have somewhere to start from. + +## System Information + +This guide was tested on: +- **OS:** Arch Linux (kernel 6.17.4-arch2-1) +- **Desktop Environment:** Hyprland (should work on Gnome and KDE also) +- **Display Server:** Wayland/X11 +- **Graphics:** NVIDIA (proprietary drivers 560.35.03) / AMD (mesa) +- **Architecture:** x86_64 + +**Software versions:** +- Raysync: 6.2.8.24 (.deb package) +- FoxRenderfarm Desktop: 5.0 (CentOS7 installer - `QFoxRenderfarmDesktop5.0.run`) +- libjpeg6-turbo: 2.0.6-1 (AUR) +- System libstdc++: 14.2.1 (gcc-libs package) + +Your mileage may vary depending on your system state and library versions, but the general approach should work on any rolling release distro. + +## Part 1: Raysync - The Simple One + +The installation of Raysync turned out to be surprisingly straightforward and took minimal troubleshooting. Raysync is a high-speed file transfer tool used by FoxRenderfarm, and to get the Desktop client working, you'll need to install this first. + +### Succumbing to hubris + +My first instinct was to use `debtap`, a tool specifically designed to convert Debian packages to Arch packages: + +```bash +debtap Raysync_6.2.8.24.deb +``` + +This created a shiny new `raysync-3.3.8.1-1-x86_64.pkg.tar.zst` file that (in my hubris and overwhelmed by my own sense of unique genius) led me to believe I was done. Silly me for assuming the tool *designed specifically for converting Debian packages to Arch packages* would convert my debian package to an Arch package. Rookie mistake. + +``` +error: package raysync-3.3.8.1-1-x86_64 does not have a valid architecture +``` + +It turns out `debtap` didn't properly set the architecture metadata when I skipped the prompts (because why the fuck would it). Could I have fixed it? Sure. But no, I was annoyed and wanted the path of least resistance. + +### The Manual Extraction Method + +Here's what actually works: + +```bash +# Extract the .deb archive (it's just an AR archive) +ar x Raysync_6.2.8.24.deb + +# Extract the actual files +tar -xzf data.tar.gz + +# Copy to system directories +sudo cp -r usr / +sudo cp -r opt / 2>/dev/null # If opt/ exists in the package +``` + +**What's happening here:** A `.deb` file is just an archive containing `control.tar.gz` (metadata) and `data.tar.gz` (the actual files). We're skipping all the package manager validation and just putting the files where they belong. + +**The tradeoff:** This works perfectly, but you lose package manager tracking. That means: +- No `pacman -R raysync` to uninstall +- No automatic dependency resolution +- You'll need to track updates manually + +For a proprietary tool that rarely updates? (Since I'm writing this down) I'm cool with it. + +Once installed, Raysync lives at: +- Binary: `/usr/local/bin/raysync` +- Resources: `/usr/local/share/raysync/` +- Desktop entries: `/usr/share/applications/raysync-*.desktop` + +Just run `raysync` from the terminal or launch it from your application menu. You'll see some Qt platform warnings in the console, but they're harmless - probably. + +## Part 2: FoxRenderfarm - The Dependency Nightmare + +FoxRenderfarm is where things get more complex. Duh. + +### The Installation + +Fox provides two self-extracting installers: +- `foxrenderfarm5.0.run` (140MB) Rocky Linux +- `QFoxRenderfarmDesktop5.0.run` (188MB) CentOS7 + +I went with the CentOS7 installer: + +```bash +./QFoxRenderfarmDesktop5.0.run +``` + +The installer extracts everything to: +``` +/home/myhomedirectory/Rayvision/FoxRenderfarm5.0/ +``` + +Launch it with: +```bash +cd ~/Rayvision/FoxRenderfarm5.0 +./foxrenderfarm.sh +``` + +And... it crashes immediately. Welcome to dependency hell. + +### Debugging Strategy: Know Your Tools + +Before we start fixing things randomly, let's understand what we're dealing with. The most important tool in your arsenal is `ldd`: + +```bash +ldd foxrenderfarm | grep "not found" +``` + +This shows every shared library the binary expects but can't find. Think of it as a checklist of problems to solve. + +### The Library Dependency Journey + +#### Issue #1: Image Format Libraries + +```bash +ldd foxrenderfarm | grep "not found" +# Output: +# libjpeg.so.62 => not found +# libmng.so.1 => not found +# libtiff.so.5 => not found +``` + +First attempt - install the system versions: +```bash +sudo pacman -S libjpeg-turbo libmng libtiff +``` + +But here's the problem: +- Arch ships `libjpeg.so.8`, app needs `libjpeg.so.62` +- Arch ships `libmng.so.2`, app needs `libmng.so.1` +- Arch ships `libtiff.so.6`, app needs `libtiff.so.5` + +**Why symlinks don't work:** You might think "just symlink the new version to the old name," but that fails because of symbol versioning. The application was compiled with specific function signatures that exist in version 6.2 but not in 8.x. The library knows this and refuses to load. + +#### Issue #2: Finding Legacy JPEG Support + +This is where the AUR (Arch User Repository) saves your life: + +```bash +cd /tmp +git clone https://aur.archlinux.org/libjpeg6-turbo.git +cd libjpeg6-turbo +makepkg -si --skippgpcheck +``` + +**Why AUR?** The community maintains packages for legacy software. `libjpeg6-turbo` provides the exact `LIBJPEG_6.2` symbols our application needs, compiled specifically for compatibility with old binaries. + +**About `--skippgpcheck`:** Normally you want to verify PGP signatures, but the key wasn't in my keyring. For a well-known AUR package, this is acceptable. If you want to be thorough: `gpg --recv-keys 85C7044E033FDE16`. + +#### Issue #3: The JBIG Dependency + +``` +error while loading shared libraries: libjbig.so.2.0: cannot open shared object file +``` + +Install the system package: +```bash +sudo pacman -S jbigkit +``` + +But Arch ships version 2.1, and the app wants 2.0. Fortunately, libjbig is backward compatible, so a symlink works: + +```bash +cd ~/Rayvision/FoxRenderfarm5.0 +sudo ln -sf /usr/lib/libjbig.so libjbig.so.2.0 +``` + +**Key decision:** I put this symlink in the application directory rather than `/usr/lib` to avoid breaking other softwares that expects the newer version. + +#### Issue #4: The Bundled Library Problem + +``` +version `GLIBCXX_3.4.22' not found (required by foxrenderfarm) +``` + +Here's where it gets counterintuitive. FoxRenderfarm bundles its own `libstdc++.so.6` in two locations: +- Main directory: `libstdc++.so.6` +- Transmit engine: `transmit_engine/libstdc++.so.6` + +The startup script sets `LD_LIBRARY_PATH` to prioritize these bundled libraries. The problem? They're *older* than what the application actually needs. Someone compiled this against a newer GCC but shipped it with old libraries. + +**The fix:** Get rid of them and let it use the system library: + +```bash +cd ~/Rayvision/FoxRenderfarm5.0 +mv libstdc++.so libstdc++.so.old +mv libstdc++.so.6 libstdc++.so.6.old +mv transmit_engine/libstdc++.so.6 transmit_engine/libstdc++.so.6.old +``` + +Now the linker falls through to Arch's current libstdc++, which has all the symbols we need. + +### Understanding LD_LIBRARY_PATH + +The `foxrenderfarm.sh` startup script sets: +```bash +LD_LIBRARY_PATH=$dirname:$dirname/libs:$dirname/transmit_engine +``` + +This creates a search order: +1. Application directory (for bundled OpenSSL, our libjbig symlink) +2. `libs/` subdirectory (Qt libraries) +3. `transmit_engine/` subdirectory +4. System libraries in `/usr/lib` + +We're using a hybrid approach: +- **Keep bundled** OpenSSL 1.1 (system has 3.x) +- **Keep bundled** Qt libraries (version-specific) +- **Use system** libstdc++ (newer and better) +- **Use system** libjpeg62 (from AUR) +- **Symlink locally** libjbig (backward compatible) + +This gives us the best of both worlds. + +## Final Configuration + +### What We Installed + +**System packages:** +```bash +sudo pacman -S libmng libtiff jbigkit +``` + +**AUR packages:** +```bash +# libjpeg6-turbo (for legacy JPEG support) +``` + +**Custom symlinks created:** +```bash +# In ~/Rayvision/FoxRenderfarm5.0/ +libjbig.so.2.0 → /usr/lib/libjbig.so +``` + +**Bundled libraries removed:** +```bash +# Renamed to .old (not deleted, just in case) +libstdc++.so +libstdc++.so.6 +transmit_engine/libstdc++.so.6 +``` + +## Lessons from the Trenches + +### 1. Package Conversion Isn't Always the Answer + +Tools like `debtap` are great for simple packages, but when metadata gets mangled or you just want to get something working quickly, manual extraction is often faster and more reliable. + +The tradeoff is you lose package manager integration. Ride like lightning I say. + +### 2. Library Compatibility Is Nuanced + +- **Backward compatible:** Newer versions work fine (libstdc++, libjbig) +- **Symbol versioned:** Strict version requirements (libjpeg) +- **ABI breaks:** Major version bumps often won't work + +The debugging process: +1. Try system library (newest version) +2. Try symlink if backward compatible +3. Search AUR for older version if symbols required +4. Use bundled library as last resort + +### 3. Bundled Libraries Can Lie + +Just because software bundles a library doesn't mean you should use it. Sometimes the bundled version is *older* than what the binary actually needs, and you're better off removing it and using the system version. + +Always check `ldd` and read the actual error messages. Don't assume bundled = correct. + +### 4. LD_LIBRARY_PATH Is Your Friend + +Understanding the dynamic linker's search order is crucial for debugging these issues: +1. `LD_LIBRARY_PATH` directories +2. `/lib` and `/usr/lib` +3. Paths in `/etc/ld.so.conf` + +By controlling `LD_LIBRARY_PATH` in the startup script, you can create a hybrid environment that uses bundled libraries where needed and system libraries where better. + +## Uninstallation + +If you need to remove these later: + +### Raysync +```bash +sudo rm /usr/local/bin/raysync +sudo rm -rf /usr/local/share/raysync/ +sudo rm /usr/share/applications/raysync-*.desktop +``` + +### FoxRenderfarm +```bash +# Use the built-in uninstaller +~/Rayvision/FoxRenderfarm5.0/uninst + +# Or manual removal +rm -rf ~/Rayvision/FoxRenderfarm5.0/ +rm ~/.local/share/applications/foxrenderfarm.desktop +rm -rf ~/.config/FoxRenderfarm/ +``` + +### Cleanup Dependencies +```bash +# Only remove if nothing else needs them +sudo pacman -R libjpeg6-turbo + +# System packages (libmng, libtiff, jbigkit) can usually stay +# Other software might depend on them +``` + +## Final Thoughts + +Running proprietary VFX software on Arch isn't always smooth, but it's rarely impossible. The key is methodical debugging: + +1. Use `ldd` to identify missing dependencies +2. Understand *why* each dependency is needed +3. Choose the right solution: system package, AUR, symlink, or bundled library +4. Test thoroughly before moving on to the next issue + +Is it more work than running CentOS or Rocky Linux? Absolutely. But if you're reading this, ~~you've already decided that having full control over your system is worth the occasional dependency hunt.~~ You're a sadist. + +And honestly? After doing this a few times, you start to get pretty fast at it. These days, getting proprietary software working on Arch is less "will this work?" and more "how long will it take?" + +Usually not that long. + +--- + +*Have questions or run into issues following this guide? Feel free to reach out. And if you're working on similar pipeline challenges, I'd love to hear about your solutions.* diff --git a/src/styles/global.css b/src/styles/global.css index d4a5365..3fd9b0f 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -2,628 +2,667 @@ @plugin "@tailwindcss/typography"; @theme { - --color-brand-dark: #0B0D11; - --color-brand-panel: #151921; - --color-brand-accent: #ff4d00; - --color-brand-cyan: #22D3EE; - --color-brand-red: #E11D48; + --color-brand-dark: #0B0D11; + --color-brand-panel: #151921; + --color-brand-accent: #dd4132; + --color-brand-cyan: #22D3EE; + --color-brand-red: #E11D48; - --font-sans: "Inter", sans-serif; - --font-mono: "Space Mono", monospace; + --font-sans: "Inter", sans-serif; + --font-mono: "Space Mono", monospace; - /* Animation keyframes */ - --animate-reveal: reveal 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; - --animate-fade-in: fade-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; - --animate-slide-up: slide-up 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; - --animate-slide-left: slide-left 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; - --animate-slide-right: slide-right 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; - --animate-scale-in: scale-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; + /* Animation keyframes */ + --animate-reveal: reveal 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; + --animate-fade-in: fade-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; + --animate-slide-up: slide-up 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; + --animate-slide-left: slide-left 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; + --animate-slide-right: slide-right 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; + --animate-scale-in: scale-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; - @keyframes reveal { - from { - opacity: 0; - transform: translateY(30px); - } - to { - opacity: 1; - transform: translateY(0); - } - } + @keyframes reveal { + from { + opacity: 0; + transform: translateY(30px); + } - @keyframes fade-in { - from { - opacity: 0; + to { + opacity: 1; + transform: translateY(0); + } } - to { - opacity: 1; - } - } - @keyframes slide-up { - from { - opacity: 0; - transform: translateY(40px); - } - to { - opacity: 1; - transform: translateY(0); - } - } + @keyframes fade-in { + from { + opacity: 0; + } - @keyframes slide-left { - from { - opacity: 0; - transform: translateX(40px); + to { + opacity: 1; + } } - to { - opacity: 1; - transform: translateX(0); - } - } - @keyframes slide-right { - from { - opacity: 0; - transform: translateX(-40px); - } - to { - opacity: 1; - transform: translateX(0); - } - } + @keyframes slide-up { + from { + opacity: 0; + transform: translateY(40px); + } - @keyframes scale-in { - from { - opacity: 0; - transform: scale(0.95); + to { + opacity: 1; + transform: translateY(0); + } } - to { - opacity: 1; - transform: scale(1); + + @keyframes slide-left { + from { + opacity: 0; + transform: translateX(40px); + } + + to { + opacity: 1; + transform: translateX(0); + } + } + + @keyframes slide-right { + from { + opacity: 0; + transform: translateX(-40px); + } + + to { + opacity: 1; + transform: translateX(0); + } + } + + @keyframes scale-in { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } } - } } @utility text-massive { - line-height: 0.9; - letter-spacing: -0.04em; + line-height: 0.9; + letter-spacing: -0.04em; } @utility text-stroke { - -webkit-text-stroke: 1px rgba(255, 255, 255, 0.15); - color: transparent; + -webkit-text-stroke: 1px rgba(255, 255, 255, 0.15); + color: transparent; } @utility skill-tag { - @apply text-[10px] font-mono font-bold uppercase tracking-wider px-3 py-2 border border-slate-700 text-slate-400 hover:border-brand-accent hover:text-white transition-all duration-300 cursor-default select-none; + @apply text-[10px] font-mono font-bold uppercase tracking-wider px-3 py-2 border border-slate-700 text-slate-400 hover:border-brand-accent hover:text-white transition-all duration-300 cursor-default select-none; } @utility btn-primary { - @apply bg-brand-accent text-brand-dark px-8 py-4 text-xs font-bold uppercase tracking-widest hover:bg-white transition-all duration-300 inline-block; + @apply bg-brand-accent text-brand-dark px-8 py-4 text-xs font-bold uppercase tracking-widest hover:bg-white transition-all duration-300 inline-block; } @utility btn-ghost { - @apply border border-slate-600 text-white px-8 py-4 text-xs font-bold uppercase tracking-widest hover:border-brand-accent hover:bg-brand-accent/5 transition-all duration-300 inline-block; + @apply border border-slate-600 text-white px-8 py-4 text-xs font-bold uppercase tracking-widest hover:border-brand-accent hover:bg-brand-accent/5 transition-all duration-300 inline-block; } @utility grid-overlay { - background-size: 100px 100px; - background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px); - pointer-events: none; - z-index: 0; + background-size: 100px 100px; + background-image: linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px); + pointer-events: none; + z-index: 0; } /* Base Styles */ body { - background-color: var(--color-brand-dark); - color: #ffffff; - overflow-x: hidden; + background-color: var(--color-brand-dark); + color: #ffffff; + overflow-x: hidden; } /* Smooth scroll behavior - disabled on mobile for better performance */ html { - scroll-behavior: smooth; + scroll-behavior: smooth; } @media (max-width: 768px) { - html { - scroll-behavior: auto; - } + html { + scroll-behavior: auto; + } } /* Mobile viewport height fix - uses dvh with vh fallback */ :root { - --vh-full: 100vh; - --vh-full: 100dvh; + --vh-full: 100vh; + --vh-full: 100dvh; } /* Custom Scrollbar */ ::-webkit-scrollbar { - width: 8px; + width: 8px; } ::-webkit-scrollbar-track { - background: var(--color-brand-dark); + background: var(--color-brand-dark); } ::-webkit-scrollbar-thumb { - background: #334155; - transition: background 0.3s ease; + background: #334155; + transition: background 0.3s ease; } ::-webkit-scrollbar-thumb:hover { - background: var(--color-brand-accent); + background: var(--color-brand-accent); } /* ===== SCROLL ANIMATION SYSTEM ===== */ /* Base animation classes - elements start hidden */ .animate-on-scroll { - opacity: 0; - transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), - transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); + opacity: 0; + transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), + transform 0.7s cubic-bezier(0.16, 1, 0.3, 1); } /* Slide up variant */ .animate-on-scroll.slide-up { - transform: translateY(40px); + transform: translateY(40px); } /* Slide left variant (comes from right) */ .animate-on-scroll.slide-left { - transform: translateX(40px); + transform: translateX(40px); } /* Slide right variant (comes from left) */ .animate-on-scroll.slide-right { - transform: translateX(-40px); + transform: translateX(-40px); } /* Scale in variant */ .animate-on-scroll.scale-in { - transform: scale(0.95); + transform: scale(0.95); } /* Fade only */ .animate-on-scroll.fade-in { - transform: none; + transform: none; } /* Active state - when element is in view */ .animate-on-scroll.is-visible { - opacity: 1; - transform: translateY(0) translateX(0) scale(1); + opacity: 1; + transform: translateY(0) translateX(0) scale(1); } /* Stagger delay classes for sequential animations */ -.stagger-1 { transition-delay: 0.1s; } -.stagger-2 { transition-delay: 0.2s; } -.stagger-3 { transition-delay: 0.3s; } -.stagger-4 { transition-delay: 0.4s; } -.stagger-5 { transition-delay: 0.5s; } -.stagger-6 { transition-delay: 0.6s; } -.stagger-7 { transition-delay: 0.7s; } -.stagger-8 { transition-delay: 0.8s; } +.stagger-1 { + transition-delay: 0.1s; +} + +.stagger-2 { + transition-delay: 0.2s; +} + +.stagger-3 { + transition-delay: 0.3s; +} + +.stagger-4 { + transition-delay: 0.4s; +} + +.stagger-5 { + transition-delay: 0.5s; +} + +.stagger-6 { + transition-delay: 0.6s; +} + +.stagger-7 { + transition-delay: 0.7s; +} + +.stagger-8 { + transition-delay: 0.8s; +} /* Legacy reveal-text support */ .reveal-text { - opacity: 0; - transform: translateY(30px); - transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); + opacity: 0; + transform: translateY(30px); + transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); } .reveal-text.active { - opacity: 1; - transform: translateY(0); + opacity: 1; + transform: translateY(0); } /* Delay variants for reveal-text */ -.reveal-text.delay-100 { transition-delay: 0.1s; } -.reveal-text.delay-200 { transition-delay: 0.2s; } -.reveal-text.delay-300 { transition-delay: 0.3s; } -.reveal-text.delay-400 { transition-delay: 0.4s; } -.reveal-text.delay-500 { transition-delay: 0.5s; } +.reveal-text.delay-100 { + transition-delay: 0.1s; +} + +.reveal-text.delay-200 { + transition-delay: 0.2s; +} + +.reveal-text.delay-300 { + transition-delay: 0.3s; +} + +.reveal-text.delay-400 { + transition-delay: 0.4s; +} + +.reveal-text.delay-500 { + transition-delay: 0.5s; +} /* ===== CURSOR STYLES ===== */ .cursor-dot, .cursor-outline { - position: fixed; - top: 0; - left: 0; - transform: translate(-50%, -50%); - border-radius: 50%; - z-index: 9999; - pointer-events: none; - will-change: transform; + position: fixed; + top: 0; + left: 0; + transform: translate(-50%, -50%); + border-radius: 50%; + z-index: 9999; + pointer-events: none; + will-change: transform; } .cursor-dot { - width: 8px; - height: 8px; - background-color: var(--color-brand-accent); + width: 8px; + height: 8px; + background-color: var(--color-brand-accent); } .cursor-outline { - width: 40px; - height: 40px; - border: 1px solid rgba(255, 77, 0, 0.5); - transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1), - height 0.3s cubic-bezier(0.16, 1, 0.3, 1), - background-color 0.3s ease; + width: 40px; + height: 40px; + border: 1px solid rgba(255, 77, 0, 0.5); + transition: width 0.3s cubic-bezier(0.16, 1, 0.3, 1), + height 0.3s cubic-bezier(0.16, 1, 0.3, 1), + background-color 0.3s ease; } /* Interactive Elements Cursor Hover Effect */ -.hover-trigger:hover ~ .cursor-outline, -a:hover ~ .cursor-outline, -button:hover ~ .cursor-outline { - width: 60px; - height: 60px; - background-color: rgba(255, 77, 0, 0.05); - border-color: var(--color-brand-accent); +.hover-trigger:hover~.cursor-outline, +a:hover~.cursor-outline, +button:hover~.cursor-outline { + width: 60px; + height: 60px; + background-color: rgba(255, 77, 0, 0.05); + border-color: var(--color-brand-accent); } /* ===== ENHANCED TRANSITIONS ===== */ /* Smooth link transitions */ a { - transition: color 0.3s ease, border-color 0.3s ease; + transition: color 0.3s ease, border-color 0.3s ease; } /* Image hover zoom - smoother */ .hover-zoom { - transition: transform 1s cubic-bezier(0.16, 1, 0.3, 1); + transition: transform 1s cubic-bezier(0.16, 1, 0.3, 1); } .hover-zoom:hover, .group:hover .hover-zoom { - transform: scale(1.05); + transform: scale(1.05); } /* Line expand animation */ .line-expand { - transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1); + transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1); } /* Border glow on hover - subtle */ .hover-border-glow { - transition: border-color 0.3s ease, box-shadow 0.3s ease; + transition: border-color 0.3s ease, box-shadow 0.3s ease; } .hover-border-glow:hover { - border-color: var(--color-brand-accent); - box-shadow: 0 0 20px rgba(255, 77, 0, 0.1); + border-color: var(--color-brand-accent); + box-shadow: 0 0 20px rgba(255, 77, 0, 0.1); } /* Gradient divider */ .divider-gradient { - background: linear-gradient( - to right, - transparent, - rgba(255, 255, 255, 0.1) 20%, - rgba(255, 255, 255, 0.1) 80%, - transparent - ); + background: linear-gradient(to right, + transparent, + rgba(255, 255, 255, 0.1) 20%, + rgba(255, 255, 255, 0.1) 80%, + transparent); } /* Divider with accent hint */ .divider-accent { - background: linear-gradient( - to right, - transparent, - rgba(255, 77, 0, 0.2) 50%, - transparent - ); + background: linear-gradient(to right, + transparent, + rgba(255, 77, 0, 0.2) 50%, + transparent); } /* ===== PROSE / MARKDOWN STYLES ===== */ .prose-custom { - color: #94A3B8; - line-height: 1.8; - font-size: 1.0625rem; + color: #94A3B8; + line-height: 1.8; + font-size: 1.0625rem; } .prose-custom h2 { - color: #ffffff; - font-size: 1.75rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: -0.025em; - margin-top: 3.5rem; - margin-bottom: 1.25rem; - padding-bottom: 0.75rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - position: relative; - scroll-margin-top: 6rem; + color: #ffffff; + font-size: 1.75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: -0.025em; + margin-top: 3.5rem; + margin-bottom: 1.25rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + position: relative; + scroll-margin-top: 6rem; } .prose-custom h2::before { - content: "//"; - color: var(--color-brand-accent); - margin-right: 0.5rem; - font-family: var(--font-mono); - font-size: 0.9em; + content: "//"; + color: var(--color-brand-accent); + margin-right: 0.5rem; + font-family: var(--font-mono); + font-size: 0.9em; } .prose-custom h3 { - color: #ffffff; - font-size: 1.25rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: -0.015em; - margin-top: 2.5rem; - margin-bottom: 1rem; - scroll-margin-top: 6rem; + color: #ffffff; + font-size: 1.25rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: -0.015em; + margin-top: 2.5rem; + margin-bottom: 1rem; + scroll-margin-top: 6rem; } .prose-custom h4 { - color: #ffffff; - font-size: 1.1rem; - font-weight: 600; - margin-top: 1.5rem; - margin-bottom: 0.75rem; - scroll-margin-top: 6rem; + color: #ffffff; + font-size: 1.1rem; + font-weight: 600; + margin-top: 1.5rem; + margin-bottom: 0.75rem; + scroll-margin-top: 6rem; } .prose-custom p { - margin-bottom: 1.5rem; + margin-bottom: 1.5rem; } .prose-custom a { - color: var(--color-brand-accent); - text-decoration: none; - transition: color 0.3s ease; - border-bottom: 1px solid transparent; + color: var(--color-brand-accent); + text-decoration: none; + transition: color 0.3s ease; + border-bottom: 1px solid transparent; } .prose-custom a:hover { - color: #ffffff; - border-bottom-color: var(--color-brand-accent); + color: #ffffff; + border-bottom-color: var(--color-brand-accent); } .prose-custom strong { - color: #ffffff; - font-weight: 600; + color: #ffffff; + font-weight: 600; } .prose-custom em { - color: #CBD5E1; - font-style: italic; + color: #CBD5E1; + font-style: italic; } .prose-custom ul { - list-style: none; - padding-left: 0; - margin-bottom: 1.5rem; + list-style: none; + padding-left: 0; + margin-bottom: 1.5rem; } .prose-custom ul li { - position: relative; - padding-left: 1.75rem; - margin-bottom: 0.75rem; + position: relative; + padding-left: 1.75rem; + margin-bottom: 0.75rem; } .prose-custom ul li::before { - content: "▹"; - position: absolute; - left: 0; - color: var(--color-brand-accent); - font-size: 0.85em; + content: "▹"; + position: absolute; + left: 0; + color: var(--color-brand-accent); + font-size: 0.85em; } .prose-custom ol { - list-style: none; - padding-left: 0; - margin-bottom: 1.5rem; - counter-reset: ol-counter; + list-style: none; + padding-left: 0; + margin-bottom: 1.5rem; + counter-reset: ol-counter; } .prose-custom ol li { - margin-bottom: 0.75rem; - padding-left: 2.5rem; - position: relative; - counter-increment: ol-counter; + margin-bottom: 0.75rem; + padding-left: 2.5rem; + position: relative; + counter-increment: ol-counter; } .prose-custom ol li::before { - content: counter(ol-counter, decimal-leading-zero); - position: absolute; - left: 0; - color: var(--color-brand-accent); - font-family: var(--font-mono); - font-size: 0.75rem; - font-weight: 700; - width: 1.75rem; + content: counter(ol-counter, decimal-leading-zero); + position: absolute; + left: 0; + color: var(--color-brand-accent); + font-family: var(--font-mono); + font-size: 0.75rem; + font-weight: 700; + width: 1.75rem; } /* Enhanced Blockquotes - Terminal/Industrial Style */ .prose-custom blockquote { - position: relative; - border-left: 3px solid var(--color-brand-accent); - background: linear-gradient(135deg, rgba(255, 77, 0, 0.05), rgba(21, 25, 33, 0.8)); - padding: 1.5rem 1.5rem 1.5rem 2rem; - margin: 2.5rem 0; - font-style: italic; - color: #CBD5E1; - border-right: 1px solid rgba(255, 255, 255, 0.05); - border-top: 1px solid rgba(255, 255, 255, 0.05); - border-bottom: 1px solid rgba(255, 255, 255, 0.05); + position: relative; + border-left: 3px solid var(--color-brand-accent); + background: linear-gradient(135deg, rgba(255, 77, 0, 0.05), rgba(21, 25, 33, 0.8)); + padding: 1.5rem 1.5rem 1.5rem 2rem; + margin: 2.5rem 0; + font-style: italic; + color: #CBD5E1; + border-right: 1px solid rgba(255, 255, 255, 0.05); + border-top: 1px solid rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .prose-custom blockquote::before { - content: "///"; - position: absolute; - top: -0.75rem; - left: 1rem; - background: var(--color-brand-dark); - padding: 0 0.5rem; - font-family: var(--font-mono); - font-size: 0.625rem; - font-weight: 700; - letter-spacing: 0.1em; - color: var(--color-brand-accent); - font-style: normal; + content: "///"; + position: absolute; + top: -0.75rem; + left: 1rem; + background: var(--color-brand-dark); + padding: 0 0.5rem; + font-family: var(--font-mono); + font-size: 0.625rem; + font-weight: 700; + letter-spacing: 0.1em; + color: var(--color-brand-accent); + font-style: normal; } .prose-custom blockquote p { - margin-bottom: 0; + margin-bottom: 0; } .prose-custom blockquote p:last-child { - margin-bottom: 0; + margin-bottom: 0; } /* Enhanced Code - Inline */ .prose-custom code { - color: var(--color-brand-accent); - background-color: rgba(255, 77, 0, 0.1); - padding: 0.2rem 0.5rem; - border-radius: 0; - font-family: var(--font-mono); - font-size: 0.85em; - border: 1px solid rgba(255, 77, 0, 0.2); + color: var(--color-brand-accent); + background-color: rgba(255, 77, 0, 0.1); + padding: 0.2rem 0.5rem; + border-radius: 0; + font-family: var(--font-mono); + font-size: 0.85em; + border: 1px solid rgba(255, 77, 0, 0.2); } /* Enhanced Code Blocks - Terminal Style */ .prose-custom pre { - position: relative; - background-color: var(--color-brand-panel); - border: 1px solid rgba(255, 255, 255, 0.1); - padding: 0; - margin: 2.5rem 0; - overflow: hidden; + position: relative; + background-color: var(--color-brand-panel); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 0; + margin: 2.5rem 0; + overflow: hidden; } .prose-custom pre::before { - content: "TERMINAL"; - display: block; - background: rgba(255, 255, 255, 0.03); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); - padding: 0.75rem 1rem; - font-family: var(--font-mono); - font-size: 0.625rem; - font-weight: 700; - letter-spacing: 0.15em; - color: #64748B; - text-transform: uppercase; + content: "TERMINAL"; + display: block; + background: rgba(255, 255, 255, 0.03); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + padding: 0.75rem 1rem; + font-family: var(--font-mono); + font-size: 0.625rem; + font-weight: 700; + letter-spacing: 0.15em; + color: #64748B; + text-transform: uppercase; } .prose-custom pre code { - display: block; - background: none; - padding: 1.5rem; - color: #CBD5E1; - border: none; - overflow-x: auto; + display: block; + background: none; + padding: 1.5rem; + color: #CBD5E1; + border: none; + overflow-x: auto; } /* Enhanced Horizontal Rules - Section Dividers */ .prose-custom hr { - border: none; - height: auto; - margin: 4rem 0; - position: relative; - display: flex; - align-items: center; - justify-content: center; - gap: 1rem; + border: none; + height: auto; + margin: 4rem 0; + position: relative; + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; } .prose-custom hr::before { - content: ""; - flex: 1; - height: 1px; - background: linear-gradient(to right, transparent, rgba(255, 77, 0, 0.3)); + content: ""; + flex: 1; + height: 1px; + background: linear-gradient(to right, transparent, rgba(255, 77, 0, 0.3)); } .prose-custom hr::after { - content: ""; - flex: 1; - height: 1px; - background: linear-gradient(to left, transparent, rgba(255, 77, 0, 0.3)); + content: ""; + flex: 1; + height: 1px; + background: linear-gradient(to left, transparent, rgba(255, 77, 0, 0.3)); } /* Enhanced Images */ .prose-custom img { - border: 1px solid rgba(255, 255, 255, 0.1); - margin: 2.5rem 0; - transition: border-color 0.3s ease; + border: 1px solid rgba(255, 255, 255, 0.1); + margin: 2.5rem 0; + transition: border-color 0.3s ease; } .prose-custom img:hover { - border-color: rgba(255, 77, 0, 0.3); + border-color: rgba(255, 77, 0, 0.3); } /* Image Captions (for figures) */ .prose-custom figure { - margin: 2.5rem 0; + margin: 2.5rem 0; } .prose-custom figure img { - margin: 0; + margin: 0; } .prose-custom figcaption { - font-family: var(--font-mono); - font-size: 0.6875rem; - text-transform: uppercase; - letter-spacing: 0.1em; - color: #64748B; - margin-top: 0.75rem; - padding-left: 0.5rem; - border-left: 2px solid var(--color-brand-accent); + font-family: var(--font-mono); + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #64748B; + margin-top: 0.75rem; + padding-left: 0.5rem; + border-left: 2px solid var(--color-brand-accent); } /* Video containers */ .prose-custom .video-container { - margin: 2.5rem 0; - position: relative; + margin: 2.5rem 0; + position: relative; } .prose-custom .video-container video { - width: 100%; - border: 1px solid rgba(255, 255, 255, 0.1); + width: 100%; + border: 1px solid rgba(255, 255, 255, 0.1); } .prose-custom .video-container p { - font-family: var(--font-mono); - font-size: 0.6875rem; - text-transform: uppercase; - letter-spacing: 0.1em; - color: #64748B; - margin-top: 0.75rem; - margin-bottom: 0; + font-family: var(--font-mono); + font-size: 0.6875rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #64748B; + margin-top: 0.75rem; + margin-bottom: 0; } /* Tables */ .prose-custom table { - width: 100%; - margin: 2.5rem 0; - border-collapse: collapse; - font-size: 0.9375rem; + width: 100%; + margin: 2.5rem 0; + border-collapse: collapse; + font-size: 0.9375rem; } .prose-custom thead { - background: rgba(255, 255, 255, 0.03); - border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.03); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .prose-custom th { - font-family: var(--font-mono); - font-size: 0.625rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.1em; - color: #64748B; - padding: 1rem; - text-align: left; + font-family: var(--font-mono); + font-size: 0.625rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #64748B; + padding: 1rem; + text-align: left; } .prose-custom td { - padding: 1rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); - color: #94A3B8; + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + color: #94A3B8; } .prose-custom tr:hover td { - background: rgba(255, 255, 255, 0.02); + background: rgba(255, 255, 255, 0.02); }