Website config Update

This commit is contained in:
2025-11-28 06:17:25 +00:00
parent 88b068a2b5
commit 8cdb39afbe
11 changed files with 949 additions and 813 deletions

View File

@@ -25,28 +25,45 @@ An Arch Linux terminal-themed portfolio website with Hyprland-style TUI componen
## Configuration ## Configuration
Everything in the site is configurable from `src/lib/config.ts`. This file is the single source of truth for UI, layout, TUI behavior, colors, and per-page settings. Edit it to personalize the website to your needs. The site configuration is now **modular** — split into focused files in `src/lib/config/` for easier maintenance. You can still import everything from `$lib/config` for backward compatibility.
### Main Config Sections ### Config File Structure
- `user`: Profile info (name, username, bio, social links)
- `skills`, `projects`, `models`, `hackathons`: Content arrays shown in pages ```
- `layout`: Sizes and page margins (navbar height, container width) src/lib/config/
- `breakpoints`: Responsive breakpoints (mobile/tablet/desktop) ├── index.ts # Barrel export (re-exports all modules)
- `fonts`: Font stacks and weights ├── user.ts # User profile, socials, skills
- `colorPalette`: Terminal and UI colors (semantic and base colors) ├── layout.ts # Layout dimensions, breakpoints, fonts, navbar, scrollbar
- `terminalButtons`: Terminal header buttons colors (close/minimize/maximize) ├── theme.ts # Colors, animations, effects, loading screen
- `terminalSettings`: Typing presets, delays, cursor visibility, prompt style ├── content.ts # Projects, 3D models, hackathon cards
- `tuiStyle`: Styling options for border, spacing, font sizes, buttons, etc. ├── terminal.ts # Terminal settings, TUI styling, speed presets, shortcuts
- `tuiText`: Labels, hints, prefixes, and text labels for interactive elements └── navigation.ts # Navigation links, site metadata, page meta
- `animations`: Animation durations and easing for UI interactions ```
- `scrollbar`: Scrollbar appearance settings
- `navbar`: Navbar sizes and theme button settings ### Import Examples
- `modelViewer`: 3D viewer camera, lighting, and text strings
- `particles`: 3D background particles (count, opacity, motion) ```typescript
- `loadingScreen`: Loading text and colors // Barrel import (backward compatible)
- `keyboardShortcuts`: Map keyboard actions to keys import { user, colorPalette, projects } from '$lib/config';
- `effects`: Misc effects like selection background and backdrop blur
- `pageMeta`: Per-route metadata (title, description, icon, keywords) // Direct imports (smaller bundles, faster builds)
import { user, skills } from '$lib/config/user';
import { colorPalette, animations } from '$lib/config/theme';
import { projects, models, cards } from '$lib/config/content';
import { terminalSettings, keyboardShortcuts } from '$lib/config/terminal';
import { navigation, site, pageMeta } from '$lib/config/navigation';
```
### Config Modules
| File | Contents |
|------|----------|
| `user.ts` | `user`, `skills` |
| `layout.ts` | `layout`, `breakpoints`, `fonts`, `navbar`, `scrollbar` |
| `theme.ts` | `colorPalette`, `terminalButtons`, `loadingScreen`, `effects`, `animations` |
| `content.ts` | `projects`, `models`, `cards`, `sortedCards` + types |
| `terminal.ts` | `terminalSettings`, `tuiStyle`, `tuiText`, `pageSpeedSettings`, `pageAutoscrollSettings`, `speedPresets`, `modelViewer`, `particles`, `keyboardShortcuts` |
| `navigation.ts` | `navigation`, `site`, `pageMeta` |
### Example: Key config snippets ### Example: Key config snippets
```typescript ```typescript
@@ -96,19 +113,24 @@ export const tuiStyle = {
}; };
``` ```
### How to customize ### How to Customize
- Change any color in `colorPalette` to affect both inline coloring and semantic tokens like `(&primary)`/`(&error)`.
- Update `terminalSettings` to control typing speed, delays, and the TUI icon.
- Modify `tuiStyle` to adjust spacing, rounded corners, and button sizes.
- Use `keyboardShortcuts` to remap keys (e.g., toggle theme, skip animation).
- Per-page speeds are controlled by `pageSpeedSettings` (preset or numeric multiplier).
### Where to look for types & utilities - Edit `config/user.ts` to update your profile, socials, and skills
- `src/lib/components/tui/types.ts` — main TerminalLine types - Edit `config/content.ts` to add projects, models, or hackathon entries
- `src/lib/components/tui/utils.ts` — parsing utilities and style helpers - Edit `config/theme.ts` to change colors, animations, or loading screen
- `src/lib/stores/theme.ts` — theme store & `toggleMode()` - Edit `config/terminal.ts` to adjust typing speed, TUI styling, or shortcuts
- Edit `config/layout.ts` to change dimensions, breakpoints, or navbar settings
- Edit `config/navigation.ts` to add/remove nav links or update page metadata
If you change a value in `config.ts`, the UI should pick it up on next reload. Some values (fonts, CSS variables) may also require adjusting CSS variables or Tailwind config. Changes take effect on next reload. Some values (fonts, CSS variables) may also require adjusting CSS or Tailwind config.
### Where to Look for Types & Utilities
- `src/lib/config/` — All configuration modules
- `src/lib/components/tui/types.ts` — TerminalLine types
- `src/lib/components/tui/utils.ts` — Parsing utilities and style helpers
- `src/lib/stores/theme.ts` — Theme store & `toggleMode()`
- `src/lib/index.ts` — Helper functions (barrel export)
## Speed Presets ## Speed Presets

View File

@@ -1,777 +1,20 @@
// ============================================================================ // ============================================================================
// USER PROFILE // CONFIGURATION - BARREL EXPORT
// ============================================================================ // ============================================================================
// This file re-exports all configuration from the modular config/ directory.
export const user = { // For backward compatibility, you can continue importing from '$lib/config'.
name: 'Gagan M',
displayname: 'Sir Blob',
username: 'sirblob',
hostname: 'engineering',
title: 'Engineering Student',
email: 'sirblob0@gmail.com',
location: 'Washington DC-Baltimore Area',
bio: `Hi, I am Sir Blob — a engineer who loves making things. ` +
`I build fun coding projects, participate in game jams and hackathons, and enjoy games like Minecraft and Pokémon TCG Live.`,
// Prefer an absolute avatar URL if you want to pull directly from GitHub
avatar: '/blob_nerd.png',
// Social links - array of { name, icon (Iconify), link }
socials: [
{ name: 'GitHub', icon: 'mdi:github', link: 'https://github.com/SirBlobby' },
{ name: 'LinkedIn', icon: 'mdi:linkedin', link: 'https://www.linkedin.com/in/gmanjunatha/' },
{ name: 'Devpost', icon: 'simple-icons:devpost', link: 'https://devpost.com/Sir_Blob_' },
{ name: 'Discord', icon: 'mdi:discord', link: 'https://discord.com/users/sir_blob_' }
]
};
// ============================================================================
// LAYOUT & DIMENSIONS
// ============================================================================
export const layout = {
// Navbar
navbarHeight: 60, // px
navbarMaxWidth: 1400, // px
navbarZIndex: 1000,
// Container
containerMaxWidth: 1200, // px
containerPadding: '1.5rem',
// Grid
gridGap: '1.5rem',
gridMinColumnWidth: 300, // px
// Page margins
pageBottomMargin: 80, // px (desktop)
pageMobileBottomMargin: 60, // px (mobile)
};
// ============================================================================
// RESPONSIVE BREAKPOINTS
// ============================================================================
export const breakpoints = {
mobile: 768, // px
tablet: 1024, // px
desktop: 1400, // px
};
// ============================================================================
// FONTS
// ============================================================================
export const fonts = {
mono: "'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace",
sans: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
monoWeight: 600,
};
// ============================================================================
// COLOR PALETTE
// ============================================================================
// These colors are used for terminal text formatting and UI elements
// Colors follow Catppuccin Mocha theme by default
export const colorPalette = {
// Basic colors
red: '#f38ba8',
green: '#a6e3a1',
yellow: '#f9e2af',
blue: '#89b4fa',
magenta: '#cba6f7',
cyan: '#94e2d5',
white: '#cdd6f4',
gray: '#6c7086',
orange: '#fab387',
pink: '#f5c2e7',
black: '#1e1e2e',
surface: '#313244',
// Semantic colors (map to basic colors by default)
error: '#f38ba8', // red
success: '#a6e3a1', // green
warning: '#f9e2af', // yellow
info: '#89b4fa', // blue
};
// ============================================================================
// TERMINAL WINDOW BUTTONS (traffic lights)
// ============================================================================
export const terminalButtons = {
close: '#ff5f56',
minimize: '#ffbd2e',
maximize: '#27ca40',
};
// ============================================================================
// SKILLS
// ============================================================================
export const skills = {
languages: ['Python', 'JavaScript', 'TypeScript', 'C', 'C++', 'Java', 'Node.js'],
frameworks: ['Arduino', 'Bootstrap', 'TailwindCSS', 'Discord.js', 'React', 'Electron', 'Svelte'],
applications: ['Windows', 'Linux', 'macOS', 'IntelliJ', 'VS Code', 'Git', 'Blender', 'Godot'],
platforms: ['Windows', 'Linux', 'macOS', 'Arduino', 'Raspberry Pi'],
tools: ['Git', 'Docker', 'Neovim', 'VS Code'],
databases: ['MongoDB', 'Redis', 'SQLite'],
interests: ['Open Source', '3D Graphics', 'CLI Tools', 'Game Dev']
};
// ============================================================================
// PROJECTS
// ============================================================================
export interface Project {
name: string;
description: string;
tech: string[];
github?: string;
live?: string;
image?: string;
featured?: boolean;
}
export const projects: Project[] = [
{
name: 'PokemonTCGAPI',
description: 'Official NPM package wrapper for the PokemonTCG API — utilities and helpers for working with Pokemon TCG data.',
tech: ['TypeScript', 'Node.js'],
live: 'https://www.npmjs.com/package/@bosstop/pokemontcgapi',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'MCSS TS API',
description: 'TypeScript API for MCServersSoft services, published to NPM.',
tech: ['TypeScript', 'Node.js'],
live: 'https://www.npmjs.com/package/@mcserversoft/mcss-api',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'MCP Selenium',
description: 'Selenium automation utilities for MCP workflows, packaged for reuse.',
tech: ['TypeScript', 'Selenium'],
live: 'https://www.npmjs.com/package/@sirblob/mcp-selenium',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'Pkit',
description: 'CLI toolkit and utilities (Rust project) — small developer-focused CLI.',
tech: ['Rust', 'CLI'],
github: 'https://github.com/dead-projects-inc/pkit-cli',
image: 'https://icons.veryicon.com/png/o/business/vscode-program-item-icon/rust-1.png',
featured: false
}
];
// ============================================================================
// 3D MODELS
// ============================================================================
export interface Model3D {
name: string;
description: string;
thumbnail: string;
modelUrl?: string; // URL to .glb/.gltf file for preview
downloadUrl?: string;
software: string[];
polyCount?: string;
featured?: boolean;
}
export const models: Model3D[] = [
{
name: 'Character Model',
description: 'A stylized character model with full rig',
thumbnail: '/models/character-thumb.png',
modelUrl: '/models/character.glb',
software: ['Blender', 'Substance Painter'],
polyCount: '15k tris',
featured: true
},
{
name: 'Environment Asset Pack',
description: 'Low-poly environment assets for game dev',
thumbnail: '/models/environment-thumb.png',
software: ['Blender'],
polyCount: '2k-5k tris',
featured: true
},
{
name: 'Weapon Collection',
description: 'Sci-fi weapon models with PBR textures',
thumbnail: '/models/weapons-thumb.png',
software: ['Blender', 'Substance Painter'],
downloadUrl: 'https://example.com/download'
}
];
// ============================================================================
// HACKATHONS
// ============================================================================
export type Card = {
title: string;
description: string;
image?: string;
link?: string;
repo?: string;
devpost?: string;
hackathonName?: string;
university?: string;
location?: string;
year?: string;
tags?: string[];
featured?: boolean;
awards?: { track: string; place: string }[];
liveWarning?: boolean;
};
export const cards: Card[] = [
{
image: "/hacks/fooddecisive.png",
title: "Food Decisive",
description:
"Ever felt the indecisiveness of choosing what to eat? Don't fret! Decide your next bite with Food Decisive",
link: "https://fooddecisive.sirblob.co/",
repo: "https://github.com/SirBlobby/VTHacks-12",
devpost: "https://devpost.com/software/food-decisive",
hackathonName: "VTHacks 12",
university: "Virginia Tech",
location: "Blacksburg, VA",
year: "2024",
tags: ["AI", "Llama3.1", "Svelte", "Node.js"],
featured: false,
liveWarning: true
},
{
image: "/hacks/carbin.png",
title: "Carbin",
description:
"Encourage student participation in responsible waste management with smart bins that guide proper disposal.",
repo: "https://github.com/SirBlobby/patriotHacks2024",
devpost: "https://devpost.com/software/carboniferous-akc4mj",
hackathonName: "PatriotHacks 2024",
university: "George Mason University",
location: "Fairfax, VA",
year: "2024",
tags: ["AI", "Azure", "CloudConvert", "Python", "React", "TypeScript", "API"],
featured: true,
awards: [
{ track: "Save the World", place: "2nd Place" },
{ track: "Microsoft X Cloudforce", place: "2nd Place" }
]
},
{
image: "/hacks/patsafe.png",
title: "PatSafe",
description:
"Bridging the gap between doctors and patients for seamless post-discharge care",
link: "https://hoya-hax2025.vercel.app/",
repo: "https://github.com/SirBlobby/HoyaHax2025",
devpost: "https://devpost.com/software/patsafe",
hackathonName: "HoyaHax 2025",
university: "Georgetown University",
location: "Washington, D.C.",
year: "2025",
tags: ["Javascript", "Next.js", "React", "TypeScript", "LangChain", "OpenAI"],
},
{
image:"https://placehold.co/800x400/334155/94a3b8?text=Fauxcall",
title: "Fauxcall",
description:
"This product is perfect for situations where you are walking at night and you feel unsafe from someone. Fauxcall lets users create a convincing fake phone call to deter potential attackers and provide a quick escape mechanism.",
link: "",
repo: "https://github.com/SirBlobby/HooHacks-12",
devpost: "https://devpost.com/software/fauxcall",
hackathonName: "HooHacks 2025",
university: "University of Virginia",
location: "Charlottesville, VA",
year: "2025",
tags: ["mongodb", "next.js", "python", "react", "sesame.com", "skeleton", "twilio"],
featured: false
},
{
image: "/hacks/drinkhappy.png",
title: "Drink Happy",
description:
"drinkhappy.tech is a gamified hydration wellness app that helps users track drinks, earn points for healthy choices, and compete with friends. It's powered by Gemini AI for smart drink recognition.",
link: "https://drinkhappy.tech",
repo: "https://github.com/SirBlobby/Bitcamp-2025",
devpost: "https://devpost.com/software/drink-happy",
hackathonName: "Bitcamp",
university: "University of Maryland",
location: "College Park, MD",
year: "2025",
tags: ["api", "auth0", "gemini", "github", "javascript", "mongodb", "nextjs", "react", "tailwind", "vercel"],
featured: false
},
{
image: "/hacks/roadcast.png",
title: "Roadcast",
description:
"Roadcast provides drivers with crash data and weather insights to choose safer routes home. The project combines historical crash data, weather feeds, and spatial analysis to surface hazardous areas and route-level safety recommendations.",
link: "https://roadcast.sirblob.co/",
repo: "https://github.com/SirBlobby/roadcast",
devpost: "https://devpost.com/software/roadcast",
hackathonName: "VTHacks 13",
university: "Virginia Tech",
location: "Blacksburg, VA",
year: "2025",
tags: ["react", "node.js", "python", "mongodb", "geospatial", "mapbox"],
featured: true,
liveWarning: true
}
];
// Sort cards to show featured first
export const sortedCards = [...cards].sort((a, b) => {
if (a.featured && !b.featured) return -1;
if (!a.featured && b.featured) return 1;
return 0;
});
// ============================================================================
// TERMINAL DISPLAY SETTINGS
// ============================================================================
export type SpeedPreset = 'instant' | 'fast' | 'normal' | 'slow' | 'typewriter';
export const terminalSettings = {
// Base typing speed in ms per character (will be adjusted by content length)
baseTypeSpeed: 20,
// Minimum typing speed (fastest)
minTypeSpeed: 5,
// Maximum typing speed (slowest)
maxTypeSpeed: 50,
// Delay before starting to type (ms)
startDelay: 300,
// Delay between lines (ms)
lineDelay: 100,
// Show cursor
showCursor: true,
// Prompt style
promptStyle: 'full' as 'full' | 'short' | 'minimal',
// Terminal icon (emoji or text)
icon: '🐧',
// Scroll margin when navigating buttons (px)
scrollMargin: 80,
};
// ============================================================================
// TUI (Terminal UI) STYLING
// ============================================================================
export const tuiStyle = {
// Border & container
borderRadius: 8, // px
borderWidth: 2, // px
width: '95%',
borderGlowOpacity: 0.5,
borderGlowBlur: 4, // px
// Header
headerPadding: '0.5rem 0.75rem',
headerFontSize: '0.8rem',
// Body
bodyPadding: '1rem 1.25rem 2rem 1.25rem',
bodyFontSize: '0.9rem',
lineHeight: 1.7,
lineMinHeight: '1.7em',
blankLineHeight: '0.5em',
// Divider
dividerMargin: '0.75rem 0',
// Images
imageBorderRadius: 6, // px
defaultImageWidth: 300, // px
// Cursor
cursorWidth: 8, // px
// Scrollbar
scrollbarWidth: 6, // px
// Footer/Statusbar
statusbarPadding: '0.4rem 0.75rem',
statusbarFontSize: '0.75rem',
hintFontSize: '0.7rem',
hintBorderRadius: 3, // px
// Buttons
buttonPadding: '0.5rem 0.75rem',
buttonMargin: '0.2rem 0',
buttonBorderRadius: 4, // px
buttonFontSize: '0.9rem',
buttonIndicatorFontSize: '0.8rem',
buttonIndicatorWidth: '1rem',
};
// ============================================================================
// TUI TEXT & INDICATORS
// ============================================================================
export const tuiText = {
// Status text
loading: 'Loading...',
ready: 'Ready',
skipButton: 'Skip (Y)',
tuiLabel: 'TUI',
// Keyboard hints
hints: {
navigate: '↑↓ navigate',
select: '⏎ select',
toggle: 'T theme',
},
// Line prefixes
prefixes: {
error: '✗ ',
success: '✓ ',
info: ' ',
warning: '⚠ ',
command: '$ ',
},
// Button indicators
buttonIndicator: {
selected: '▶',
unselected: ' ',
},
};
// ============================================================================
// COLOR FORMATTING
// ============================================================================
// Use (&color)text(&) syntax in terminal content for colored text
// Use (&icon, iconName) syntax for inline icons
// //
// Available colors: // The configuration is now split into smaller, focused files:
// red, green, yellow, blue, magenta, cyan, white, gray, orange, pink // - config/user.ts → User profile and skills
// primary, accent, muted, error, success, warning, info // - config/layout.ts → Layout, breakpoints, fonts, navbar, scrollbar
// - config/theme.ts → Colors, animations, effects, loading screen
// - config/content.ts → Projects, models, hackathon cards
// - config/terminal.ts → Terminal settings, TUI styling, shortcuts
// - config/navigation.ts → Navigation links, site metadata, page meta
// //
// Available styles: // You can import directly from individual files for smaller bundles:
// bold, dim, italic, underline // import { user } from '$lib/config/user';
// // import { colorPalette } from '$lib/config/theme';
// Examples:
// "Hello (&red)world(&)!" -> red "world"
// "(&bold,green)Success(&): Task done" -> bold green "Success"
// "(&italic,cyan)Note(&): See docs" -> italic cyan "Note"
// "Status: (&primary)Active(&)" -> theme primary color
// "(&dim)This is muted text(&)" -> dimmed text
// "(&bold,underline,yellow)Warning(&)" -> bold underlined yellow
// "(&error)Failed(&) - (&success)Passed(&)" -> multiple colors
// "(&icon, mdi:github) GitHub" -> inline GitHub icon
// "Check (&icon, mdi:check) Done" -> inline check icon
// Per-page speed settings (override global settings)
// Use preset names or custom multiplier (0.1 = 10x faster, 2 = 2x slower)
export const pageSpeedSettings: Record<string, SpeedPreset | number> = {
// Examples:
// 'home': 'fast', // Fast typing on home page
// 'portfolio': 'normal', // Normal speed
// 'models': 'instant', // No typing animation
// 'hackathons': 0.5, // Custom: 2x faster than normal
'home': 'fast',
'portfolio': 'fast',
'models': 'fast',
'projects': 'normal'
};
// Per-page autoscroll settings (whether to auto-scroll as content types)
// Set to false to disable autoscroll on specific pages
export const pageAutoscrollSettings: Record<string, boolean> = {
// Examples:
// 'home': true, // Enable autoscroll
// 'portfolio': false, // Disable autoscroll
'home': true,
'portfolio': false,
'models': false,
'projects': false,
'components': false
};
// Speed preset multipliers (lower = faster)
export const speedPresets: Record<SpeedPreset, number> = {
'instant': 0, // No delay, instant display
'fast': 0.1, // 3x faster
'normal': 0.5, // Default speed
'slow': 1.5, // 2x slower
'typewriter': 2 // 3x slower, classic typewriter feel
};
// ============================================================================
// ANIMATIONS
// ============================================================================ // ============================================================================
export const animations = { export * from './config/index';
// Terminal/TUI animations
terminalFadeIn: { duration: '0.4s', easing: 'ease-out' },
tuiFadeIn: { duration: '0.4s', easing: 'ease-out' },
lineSlideIn: { duration: '0.15s', easing: 'ease-out' },
cursorBlink: { duration: '1s' },
borderGlow: { duration: '8s', transition: '0.3s' },
// Button/interaction animations
buttonHover: { duration: '0.2s' },
buttonTransition: { duration: '0.15s' },
// Navigation animations
hamburgerTransition: { duration: '0.3s' },
navLinkTransition: { duration: '0.2s' },
linkUnderline: { duration: '0.3s' },
dropdown: { flyDuration: 200, fadeDuration: 150 }, // ms
// Model viewer
modelViewerTransition: { duration: '0.3s' },
spin: { duration: '1s' },
// General
pulse: { duration: '2s' },
float: { duration: '3s' },
};
// ============================================================================
// SCROLLBAR
// ============================================================================
export const scrollbar = {
width: 8, // px
borderRadius: 4, // px
trackColor: 'rgba(0, 0, 0, 0.1)',
thumbColor: 'rgba(128, 128, 128, 0.5)',
thumbHoverColor: 'rgba(128, 128, 128, 0.7)',
};
// ============================================================================
// NAVBAR
// ============================================================================
export const navbar = {
height: 60, // px - also update layout.navbarHeight if changing
maxWidth: 1400, // px
padding: '0.75rem 1.5rem',
gap: '2rem',
zIndex: 1000,
// Brand
brandFontSize: '0.9rem',
cursorWidth: 8, // px
// Hamburger menu
hamburgerWidth: 24, // px
hamburgerHeight: 2, // px
hamburgerSpacing: 7, // px
// Links
linksGap: '1.5rem',
linkFontSize: '0.85rem',
linkPadding: '0.5rem 0.75rem',
linkBorderRadius: 4, // px
linkUnderlineHeight: 2, // px
// Mode toggle
modeToggleSize: 40, // px
modeToggleBorderRadius: 8, // px
themeButtonBorderRadius: 6, // px
// Dropdown
dropdownMinWidth: 180, // px
dropdownBorderRadius: 8, // px
dropdownZIndex: 1001,
backdropZIndex: 999,
mobileExpandedHeight: 200, // px
};
// ============================================================================
// MODEL VIEWER (3D)
// ============================================================================
export const modelViewer = {
// Container
borderRadius: 8, // px
minHeight: 300, // px
headerPadding: '0.5rem 0.75rem',
nameFontSize: '0.85rem',
// Controls
controlButtonSize: 28, // px
controlButtonBorderRadius: 4, // px
fullscreenZIndex: 100,
fullscreenTopOffset: 60, // px (navbar height)
// Camera
cameraFov: 45,
cameraNear: 0.1,
cameraFar: 1000,
cameraZ: 2.5, // initial camera distance
// Controls behavior
controlsMinDistance: 1,
controlsMaxDistance: 10,
dampingFactor: 0.05,
autoRotateSpeed: 2,
// Model
modelScale: 1.5,
// Ground plane
groundColor: 0x222222,
groundOpacity: 0.3,
// Lighting
ambientIntensity: 0.6,
directionalIntensity: 0.8,
lightColor: 0xffffff,
rimLightColor: 0x88ccff,
// Text
loadingText: 'Loading model...',
errorText: 'Failed to load model',
hints: {
rotate: 'Drag to rotate',
zoom: 'Scroll to zoom',
},
// Timing
resizeTimeout: 100, // ms
};
// ============================================================================
// PARTICLES (3D Background)
// ============================================================================
export const particles = {
count: 600,
spreadArea: 20,
size: 0.05,
velocityRange: 0.01,
// Opacity
darkOpacity: 0.6,
lightOpacity: 0.4,
// Motion
waveAmplitude: 0.001,
waveFrequency: 0.1,
boundary: 10, // wrap boundary
rotationSpeedY: 0.05,
rotationSpeedX: 0.02,
};
// ============================================================================
// LOADING SCREEN
// ============================================================================
export const loadingScreen = {
background: '#0d1117',
textColor: '#c9d1d9',
cursorColor: '#1793d1',
text: "Blob's Portfolio",
};
// ============================================================================
// SITE METADATA
// ============================================================================
export const site = {
title: `${user.displayname} | Portfolio`,
description: `${user.title} - ${user.bio}`,
keywords: ['developer', 'portfolio', 'programming', ...skills.languages, ...skills.frameworks],
ogImage: '/og-image.png',
twitterHandle: '@yourusername'
};
// ============================================================================
// PAGE META (per-route)
// ============================================================================
export interface PageMeta {
title: string;
description?: string;
icon?: string; // Iconify id or path to an image (e.g. 'mdi:home' or '/icons/home.svg')
keywords?: string[];
ogImage?: string;
}
// Map route => meta. Use route paths as keys (e.g. '/', '/portfolio')
export const pageMeta: Record<string, PageMeta> = {
'/': {
title: `${user.displayname} — Home`,
description: `Home — ${user.title} portfolio and projects.`,
icon: 'mdi:home',
keywords: ['home', 'portfolio', 'about']
},
'/portfolio': {
title: `${user.displayname} — Portfolio`,
description: 'Selected projects, highlights and case studies.',
icon: 'mdi:folder-multiple',
keywords: ['projects', 'portfolio', 'showcase']
},
'/models': {
title: `${user.displayname} — 3D Models`,
description: 'A curated collection of 3D models and previews.',
icon: 'mdi:cube-outline',
keywords: ['3d', 'models', 'glb', 'gltf']
},
'/projects': {
title: `${user.displayname} — Projects`,
description: 'Hackathon projects, demos and awards.',
icon: 'mdi:trophy',
keywords: ['hackathon', 'projects', 'events']
},
'/components': {
title: `${user.displayname} — Components`,
description: 'Terminal UI components showcase and documentation.',
icon: 'mdi:puzzle',
keywords: ['components', 'ui', 'terminal', 'tui']
}
};
// ============================================================================
// KEYBOARD SHORTCUTS
// ============================================================================
export const keyboardShortcuts = {
skip: ['y', 'Y'], // Skip typing animation
toggleTheme: ['t', 'T'], // Toggle dark/light mode
navigateUp: ['ArrowUp', 'k'],
navigateDown: ['ArrowDown', 'j'],
select: ['Enter'],
};
// ============================================================================
// NAVIGATION
// ============================================================================
export const navigation = [
{ name: 'home', path: '/', icon: '~' },
{ name: 'portfolio', path: '/portfolio', icon: '📁' },
{ name: 'models', path: '/models', icon: '🎨' },
{ name: 'projects', path: '/projects', icon: '🏆' },
// { name: 'components', path: '/components', icon: '🧩' },
{ name: 'blog', path: 'https://blog.sirblob.co', icon: '📝', external: true }
];
// ============================================================================
// EFFECTS
// ============================================================================
export const effects = {
backdropBlur: 10, // px
selectionBackground: 'rgba(23, 147, 209, 0.3)',
};
// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
// NOTE: Helper functions were moved to `src/lib/index.ts` to provide a central
// barrel and avoid duplication. Import helpers from `$lib` instead of `$lib/config`.

209
src/lib/config/content.ts Normal file
View File

@@ -0,0 +1,209 @@
// ============================================================================
// PROJECTS
// ============================================================================
export interface Project {
name: string;
description: string;
tech: string[];
github?: string;
live?: string;
image?: string;
featured?: boolean;
}
export const projects: Project[] = [
{
name: 'PokemonTCGAPI',
description: 'Official NPM package wrapper for the PokemonTCG API — utilities and helpers for working with Pokemon TCG data.',
tech: ['TypeScript', 'Node.js'],
live: 'https://www.npmjs.com/package/@bosstop/pokemontcgapi',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'MCSS TS API',
description: 'TypeScript API for MCServersSoft services, published to NPM.',
tech: ['TypeScript', 'Node.js'],
live: 'https://www.npmjs.com/package/@mcserversoft/mcss-api',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'MCP Selenium',
description: 'Selenium automation utilities for MCP workflows, packaged for reuse.',
tech: ['TypeScript', 'Selenium'],
live: 'https://www.npmjs.com/package/@sirblob/mcp-selenium',
image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png',
featured: false
},
{
name: 'Pkit',
description: 'CLI toolkit and utilities (Rust project) — small developer-focused CLI.',
tech: ['Rust', 'CLI'],
github: 'https://github.com/dead-projects-inc/pkit-cli',
image: 'https://icons.veryicon.com/png/o/business/vscode-program-item-icon/rust-1.png',
featured: false
}
];
// ============================================================================
// 3D MODELS
// ============================================================================
export interface Model3D {
name: string;
description: string;
thumbnail: string;
modelUrl?: string; // URL to .glb/.gltf file for preview
downloadUrl?: string;
software: string[];
polyCount?: string;
featured?: boolean;
}
export const models: Model3D[] = [
{
name: 'Bake Potato',
description: 'A fun baked-potato 3D model for demos and testing.',
thumbnail: '/models/BakePotato-thumb.png',
modelUrl: '/models/BakePotato.glb',
software: ['Blender'],
polyCount: '1k tris',
featured: true
},
{
name: 'Soda Can',
description: 'A realistic soda can GLB used for materials/tests.',
thumbnail: '/models/Soda-thumb.png',
modelUrl: '/models/Soda.glb',
software: ['Blender'],
polyCount: '800 tris',
featured: false
}
];
// ============================================================================
// HACKATHONS
// ============================================================================
export type Card = {
title: string;
description: string;
image?: string;
link?: string;
repo?: string;
devpost?: string;
hackathonName?: string;
university?: string;
location?: string;
year?: string;
tags?: string[];
featured?: boolean;
awards?: { track: string; place: string }[];
liveWarning?: boolean;
};
export const cards: Card[] = [
{
image: "/hacks/fooddecisive.png",
title: "Food Decisive",
description:
"Ever felt the indecisiveness of choosing what to eat? Don't fret! Decide your next bite with Food Decisive",
link: "https://fooddecisive.sirblob.co/",
repo: "https://github.com/SirBlobby/VTHacks-12",
devpost: "https://devpost.com/software/food-decisive",
hackathonName: "VTHacks 12",
university: "Virginia Tech",
location: "Blacksburg, VA",
year: "2024",
tags: ["AI", "Llama3.1", "Svelte", "Node.js"],
featured: false,
liveWarning: true
},
{
image: "/hacks/carbin.png",
title: "Carbin",
description:
"Encourage student participation in responsible waste management with smart bins that guide proper disposal.",
repo: "https://github.com/SirBlobby/patriotHacks2024",
devpost: "https://devpost.com/software/carboniferous-akc4mj",
hackathonName: "PatriotHacks 2024",
university: "George Mason University",
location: "Fairfax, VA",
year: "2024",
tags: ["AI", "Azure", "CloudConvert", "Python", "React", "TypeScript", "API"],
featured: true,
awards: [
{ track: "Save the World", place: "2nd Place" },
{ track: "Microsoft X Cloudforce", place: "2nd Place" }
]
},
{
image: "/hacks/patsafe.png",
title: "PatSafe",
description:
"Bridging the gap between doctors and patients for seamless post-discharge care",
link: "https://hoya-hax2025.vercel.app/",
repo: "https://github.com/SirBlobby/HoyaHax2025",
devpost: "https://devpost.com/software/patsafe",
hackathonName: "HoyaHax 2025",
university: "Georgetown University",
location: "Washington, D.C.",
year: "2025",
tags: ["Javascript", "Next.js", "React", "TypeScript", "LangChain", "OpenAI"],
},
{
image: "https://placehold.co/800x400/334155/94a3b8?text=Fauxcall",
title: "Fauxcall",
description:
"This product is perfect for situations where you are walking at night and you feel unsafe from someone. Fauxcall lets users create a convincing fake phone call to deter potential attackers and provide a quick escape mechanism.",
link: "",
repo: "https://github.com/SirBlobby/HooHacks-12",
devpost: "https://devpost.com/software/fauxcall",
hackathonName: "HooHacks 2025",
university: "University of Virginia",
location: "Charlottesville, VA",
year: "2025",
tags: ["mongodb", "next.js", "python", "react", "sesame.com", "skeleton", "twilio"],
featured: false
},
{
image: "/hacks/drinkhappy.png",
title: "Drink Happy",
description:
"drinkhappy.tech is a gamified hydration wellness app that helps users track drinks, earn points for healthy choices, and compete with friends. It's powered by Gemini AI for smart drink recognition.",
link: "https://drinkhappy.tech",
repo: "https://github.com/SirBlobby/Bitcamp-2025",
devpost: "https://devpost.com/software/drink-happy",
hackathonName: "Bitcamp",
university: "University of Maryland",
location: "College Park, MD",
year: "2025",
tags: ["api", "auth0", "gemini", "github", "javascript", "mongodb", "nextjs", "react", "tailwind", "vercel"],
featured: false
},
{
image: "/hacks/roadcast.png",
title: "Roadcast",
description:
"Roadcast provides drivers with crash data and weather insights to choose safer routes home. The project combines historical crash data, weather feeds, and spatial analysis to surface hazardous areas and route-level safety recommendations.",
link: "https://roadcast.sirblob.co/",
repo: "https://github.com/SirBlobby/roadcast",
devpost: "https://devpost.com/software/roadcast",
hackathonName: "VTHacks 13",
university: "Virginia Tech",
location: "Blacksburg, VA",
year: "2025",
tags: ["react", "node.js", "python", "mongodb", "geospatial", "mapbox"],
featured: true,
liveWarning: true
}
];
// Sort cards to show featured first
export const sortedCards = [...cards].sort((a, b) => {
if (a.featured && !b.featured) return -1;
if (!a.featured && b.featured) return 1;
return 0;
});

78
src/lib/config/index.ts Normal file
View File

@@ -0,0 +1,78 @@
// ============================================================================
// CONFIGURATION INDEX
// ============================================================================
// This file re-exports all configuration modules for backward compatibility.
// You can import from here or directly from the individual config files.
//
// Import examples:
// import { user, skills } from '$lib/config'; // via barrel
// import { user } from '$lib/config/user'; // direct import
// import { colorPalette } from '$lib/config/theme'; // direct import
// ============================================================================
// User profile and skills
export { user, skills } from './user';
// Layout, breakpoints, fonts, navbar, scrollbar
export { layout, breakpoints, fonts, navbar, scrollbar } from './layout';
// Theme colors, buttons, animations, effects, loading screen
export {
colorPalette,
terminalButtons,
loadingScreen,
effects,
animations
} from './theme';
// Content: projects, models, hackathon cards
export type { Project, Model3D, Card } from './content';
export { projects, models, cards, sortedCards } from './content';
// Terminal settings, TUI styling, speed presets, model viewer, particles, shortcuts
export type { SpeedPreset } from './terminal';
export {
terminalSettings,
tuiStyle,
tuiText,
pageSpeedSettings,
pageAutoscrollSettings,
speedPresets,
modelViewer,
particles,
keyboardShortcuts
} from './terminal';
// Navigation, site metadata, page meta
export type { PageMeta } from './navigation';
export { navigation, site, pageMeta } from './navigation';
// ============================================================================
// COLOR FORMATTING REFERENCE
// ============================================================================
// Use (&color)text(&) syntax in terminal content for colored text
// Use (&icon, iconName) syntax for inline icons
//
// Available colors:
// red, green, yellow, blue, magenta, cyan, white, gray, orange, pink
// primary, accent, muted, error, success, warning, info
//
// Available styles:
// bold, dim, italic, underline
//
// Examples:
// "Hello (&red)world(&)!" -> red "world"
// "(&bold,green)Success(&): Task done" -> bold green "Success"
// "(&italic,cyan)Note(&): See docs" -> italic cyan "Note"
// "Status: (&primary)Active(&)" -> theme primary color
// "(&dim)This is muted text(&)" -> dimmed text
// "(&bold,underline,yellow)Warning(&)" -> bold underlined yellow
// "(&error)Failed(&) - (&success)Passed(&)" -> multiple colors
// "(&icon, mdi:github) GitHub" -> inline GitHub icon
// "Check (&icon, mdi:check) Done" -> inline check icon
// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
// NOTE: Helper functions are in `src/lib/index.ts` to provide a central
// barrel and avoid duplication. Import helpers from `$lib` instead of `$lib/config`.

94
src/lib/config/layout.ts Normal file
View File

@@ -0,0 +1,94 @@
// ============================================================================
// LAYOUT & DIMENSIONS
// ============================================================================
export const layout = {
// Navbar
navbarHeight: 60, // px
navbarMaxWidth: 1400, // px
navbarZIndex: 1000,
// Container
containerMaxWidth: 1200, // px
containerPadding: '1.5rem',
// Grid
gridGap: '1.5rem',
gridMinColumnWidth: 300, // px
// Page margins
pageBottomMargin: 80, // px (desktop)
pageMobileBottomMargin: 60, // px (mobile)
};
// ============================================================================
// RESPONSIVE BREAKPOINTS
// ============================================================================
export const breakpoints = {
mobile: 768, // px
tablet: 1024, // px
desktop: 1400, // px
};
// ============================================================================
// FONTS
// ============================================================================
export const fonts = {
mono: "'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace",
sans: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
monoWeight: 600,
};
// ============================================================================
// NAVBAR
// ============================================================================
export const navbar = {
height: 60, // px - also update layout.navbarHeight if changing
maxWidth: 1400, // px
padding: '0.75rem 1.5rem',
gap: '2rem',
zIndex: 1000,
// Brand
brandFontSize: '0.9rem',
cursorWidth: 8, // px
// Hamburger menu
hamburgerWidth: 24, // px
hamburgerHeight: 2, // px
hamburgerSpacing: 7, // px
// Links
linksGap: '1.5rem',
linkFontSize: '0.85rem',
linkPadding: '0.5rem 0.75rem',
linkBorderRadius: 4, // px
linkUnderlineHeight: 2, // px
// Mode toggle
modeToggleSize: 40, // px
modeToggleBorderRadius: 8, // px
themeButtonBorderRadius: 6, // px
// Dropdown
dropdownMinWidth: 180, // px
dropdownBorderRadius: 8, // px
dropdownZIndex: 1001,
backdropZIndex: 999,
mobileExpandedHeight: 200, // px
};
// ============================================================================
// SCROLLBAR
// ============================================================================
export const scrollbar = {
width: 8, // px
borderRadius: 4, // px
trackColor: 'rgba(0, 0, 0, 0.1)',
thumbColor: 'rgba(128, 128, 128, 0.5)',
thumbHoverColor: 'rgba(128, 128, 128, 0.7)',
};

View File

@@ -0,0 +1,72 @@
import { user, skills } from './user';
// ============================================================================
// NAVIGATION
// ============================================================================
export const navigation = [
{ name: 'home', path: '/', icon: '~' },
{ name: 'portfolio', path: '/portfolio', icon: '📁' },
{ name: 'models', path: '/models', icon: '🎨' },
{ name: 'projects', path: '/projects', icon: '🏆' },
// { name: 'components', path: '/components', icon: '🧩' },
{ name: 'blog', path: 'https://blog.sirblob.co', icon: '📝', external: true }
];
// ============================================================================
// SITE METADATA
// ============================================================================
export const site = {
title: `${user.displayname} | Portfolio`,
description: `${user.title} - ${user.bio}`,
keywords: ['developer', 'portfolio', 'programming', ...skills.languages, ...skills.frameworks],
ogImage: '/og-image.png',
twitterHandle: '@yourusername'
};
// ============================================================================
// PAGE META (per-route)
// ============================================================================
export interface PageMeta {
title: string;
description?: string;
icon?: string; // Iconify id or path to an image (e.g. 'mdi:home' or '/icons/home.svg')
keywords?: string[];
ogImage?: string;
}
// Map route => meta. Use route paths as keys (e.g. '/', '/portfolio')
export const pageMeta: Record<string, PageMeta> = {
'/': {
title: `${user.displayname} — Home`,
description: `Home — ${user.title} portfolio and projects.`,
icon: 'mdi:home',
keywords: ['home', 'portfolio', 'about']
},
'/portfolio': {
title: `${user.displayname} — Portfolio`,
description: 'Selected projects, highlights and case studies.',
icon: 'mdi:folder-multiple',
keywords: ['projects', 'portfolio', 'showcase']
},
'/models': {
title: `${user.displayname} — 3D Models`,
description: 'A curated collection of 3D models and previews.',
icon: 'mdi:cube-outline',
keywords: ['3d', 'models', 'glb', 'gltf']
},
'/projects': {
title: `${user.displayname} — Projects`,
description: 'Hackathon projects, demos and awards.',
icon: 'mdi:trophy',
keywords: ['hackathon', 'projects', 'events']
},
'/components': {
title: `${user.displayname} — Components`,
description: 'Terminal UI components showcase and documentation.',
icon: 'mdi:puzzle',
keywords: ['components', 'ui', 'terminal', 'tui']
}
};

238
src/lib/config/terminal.ts Normal file
View File

@@ -0,0 +1,238 @@
// ============================================================================
// TERMINAL DISPLAY SETTINGS
// ============================================================================
export type SpeedPreset = 'instant' | 'fast' | 'normal' | 'slow' | 'typewriter';
export const terminalSettings = {
// Base typing speed in ms per character (will be adjusted by content length)
baseTypeSpeed: 20,
// Minimum typing speed (fastest)
minTypeSpeed: 5,
// Maximum typing speed (slowest)
maxTypeSpeed: 50,
// Delay before starting to type (ms)
startDelay: 300,
// Delay between lines (ms)
lineDelay: 100,
// Show cursor
showCursor: true,
// Prompt style
promptStyle: 'full' as 'full' | 'short' | 'minimal',
// Terminal icon (emoji or text)
icon: '🐧',
// Scroll margin when navigating buttons (px)
scrollMargin: 80,
};
// ============================================================================
// TUI (Terminal UI) STYLING
// ============================================================================
export const tuiStyle = {
// Border & container
borderRadius: 8, // px
borderWidth: 2, // px
width: '95%',
borderGlowOpacity: 0.5,
borderGlowBlur: 4, // px
// Header
headerPadding: '0.5rem 0.75rem',
headerFontSize: '0.8rem',
// Body
bodyPadding: '1rem 1.25rem 2rem 1.25rem',
bodyFontSize: '0.9rem',
lineHeight: 1.7,
lineMinHeight: '1.7em',
blankLineHeight: '0.5em',
// Divider
dividerMargin: '0.75rem 0',
// Images
imageBorderRadius: 6, // px
defaultImageWidth: 300, // px
// Cursor
cursorWidth: 8, // px
// Scrollbar
scrollbarWidth: 6, // px
// Footer/Statusbar
statusbarPadding: '0.4rem 0.75rem',
statusbarFontSize: '0.75rem',
hintFontSize: '0.7rem',
hintBorderRadius: 3, // px
// Buttons
buttonPadding: '0.5rem 0.75rem',
buttonMargin: '0.2rem 0',
buttonBorderRadius: 4, // px
buttonFontSize: '0.9rem',
buttonIndicatorFontSize: '0.8rem',
buttonIndicatorWidth: '1rem',
};
// ============================================================================
// TUI TEXT & INDICATORS
// ============================================================================
export const tuiText = {
// Status text
loading: 'Loading...',
ready: 'Ready',
skipButton: 'Skip (Y)',
tuiLabel: 'TUI',
// Keyboard hints
hints: {
navigate: '↑↓ navigate',
select: '⏎ select',
toggle: 'T theme',
},
// Line prefixes
prefixes: {
error: '✗ ',
success: '✓ ',
info: ' ',
warning: '⚠ ',
command: '$ ',
},
// Button indicators
buttonIndicator: {
selected: '▶',
unselected: ' ',
},
};
// ============================================================================
// Per-page speed settings (override global settings)
// Use preset names or custom multiplier (0.1 = 10x faster, 2 = 2x slower)
// ============================================================================
export const pageSpeedSettings: Record<string, SpeedPreset | number> = {
// Examples:
// 'home': 'fast', // Fast typing on home page
// 'portfolio': 'normal', // Normal speed
// 'models': 'instant', // No typing animation
// 'hackathons': 0.5, // Custom: 2x faster than normal
'home': 'fast',
'portfolio': 'fast',
'models': 'fast',
'projects': 'fast'
};
// Per-page autoscroll settings (whether to auto-scroll as content types)
// Set to false to disable autoscroll on specific pages
export const pageAutoscrollSettings: Record<string, boolean> = {
// Examples:
// 'home': true, // Enable autoscroll
// 'portfolio': false, // Disable autoscroll
'home': true,
'portfolio': false,
'models': false,
'projects': false,
'components': false
};
// Speed preset multipliers (lower = faster)
export const speedPresets: Record<SpeedPreset, number> = {
'instant': 0, // No delay, instant display
'fast': 0.1, // 3x faster
'normal': 0.5, // Default speed
'slow': 1.5, // 2x slower
'typewriter': 2 // 3x slower, classic typewriter feel
};
// ============================================================================
// MODEL VIEWER (3D)
// ============================================================================
export const modelViewer = {
// Container
borderRadius: 8, // px
minHeight: 300, // px
headerPadding: '0.5rem 0.75rem',
nameFontSize: '0.85rem',
// Controls
controlButtonSize: 28, // px
controlButtonBorderRadius: 4, // px
fullscreenZIndex: 100,
fullscreenTopOffset: 60, // px (navbar height)
// Camera
cameraFov: 45,
cameraNear: 0.1,
cameraFar: 1000,
cameraZ: 2.5, // initial camera distance
// Controls behavior
controlsMinDistance: 1,
controlsMaxDistance: 10,
dampingFactor: 0.05,
autoRotateSpeed: 2,
// Model
modelScale: 1.5,
// Ground plane
groundColor: 0x222222,
groundOpacity: 0.3,
// Lighting
ambientIntensity: 0.6,
directionalIntensity: 0.8,
lightColor: 0xffffff,
rimLightColor: 0x88ccff,
// Text
loadingText: 'Loading model...',
errorText: 'Failed to load model',
hints: {
rotate: 'Drag to rotate',
zoom: 'Scroll to zoom',
},
// Timing
resizeTimeout: 100, // ms
};
// ============================================================================
// PARTICLES (3D Background)
// ============================================================================
export const particles = {
count: 600,
spreadArea: 20,
size: 0.05,
velocityRange: 0.01,
// Opacity
darkOpacity: 0.6,
lightOpacity: 0.4,
// Motion
waveAmplitude: 0.001,
waveFrequency: 0.1,
boundary: 10, // wrap boundary
rotationSpeedY: 0.05,
rotationSpeedX: 0.02,
};
// ============================================================================
// KEYBOARD SHORTCUTS
// ============================================================================
export const keyboardShortcuts = {
skip: ['y', 'Y'], // Skip typing animation
toggleTheme: ['t', 'T'], // Toggle dark/light mode
navigateUp: ['ArrowUp', 'k'],
navigateDown: ['ArrowDown', 'j'],
select: ['Enter'],
};

88
src/lib/config/theme.ts Normal file
View File

@@ -0,0 +1,88 @@
// ============================================================================
// COLOR PALETTE
// ============================================================================
// These colors are used for terminal text formatting and UI elements
// Colors follow Catppuccin Mocha theme by default
export const colorPalette = {
// Basic colors
red: '#f38ba8',
green: '#a6e3a1',
yellow: '#f9e2af',
blue: '#89b4fa',
magenta: '#cba6f7',
cyan: '#94e2d5',
white: '#cdd6f4',
gray: '#6c7086',
orange: '#fab387',
pink: '#f5c2e7',
black: '#1e1e2e',
surface: '#313244',
// Semantic colors (map to basic colors by default)
error: '#f38ba8', // red
success: '#a6e3a1', // green
warning: '#f9e2af', // yellow
info: '#89b4fa', // blue
};
// ============================================================================
// TERMINAL WINDOW BUTTONS (traffic lights)
// ============================================================================
export const terminalButtons = {
close: '#ff5f56',
minimize: '#ffbd2e',
maximize: '#27ca40',
};
// ============================================================================
// LOADING SCREEN
// ============================================================================
export const loadingScreen = {
background: '#0d1117',
textColor: '#c9d1d9',
cursorColor: '#1793d1',
text: "Blob's Portfolio",
};
// ============================================================================
// EFFECTS
// ============================================================================
export const effects = {
backdropBlur: 10, // px
selectionBackground: 'rgba(23, 147, 209, 0.3)',
};
// ============================================================================
// ANIMATIONS
// ============================================================================
export const animations = {
// Terminal/TUI animations
terminalFadeIn: { duration: '0.4s', easing: 'ease-out' },
tuiFadeIn: { duration: '0.4s', easing: 'ease-out' },
lineSlideIn: { duration: '0.15s', easing: 'ease-out' },
cursorBlink: { duration: '1s' },
borderGlow: { duration: '8s', transition: '0.3s' },
// Button/interaction animations
buttonHover: { duration: '0.2s' },
buttonTransition: { duration: '0.15s' },
// Navigation animations
hamburgerTransition: { duration: '0.3s' },
navLinkTransition: { duration: '0.2s' },
linkUnderline: { duration: '0.3s' },
dropdown: { flyDuration: 200, fadeDuration: 150 }, // ms
// Model viewer
modelViewerTransition: { duration: '0.3s' },
spin: { duration: '1s' },
// General
pulse: { duration: '2s' },
float: { duration: '3s' },
};

41
src/lib/config/user.ts Normal file
View File

@@ -0,0 +1,41 @@
// ============================================================================
// USER PROFILE
// ============================================================================
export const user = {
name: 'Gagan M',
displayname: 'Sir Blob',
username: 'sirblob',
hostname: 'engineering',
title: 'Engineering Student',
email: 'sirblob0@gmail.com',
location: 'Washington DC-Baltimore Area',
bio: `Hi, I am Sir Blob — a engineer who loves making things. ` +
`I build fun coding projects, participate in game jams and hackathons, and enjoy games like Minecraft and Pokémon TCG Live.`,
// Prefer an absolute avatar URL if you want to pull directly from GitHub
avatar: '/blob_nerd.png',
// Social links - array of { name, icon (Iconify), link }
socials: [
{ name: 'GitHub', icon: 'mdi:github', link: 'https://github.com/SirBlobby' },
{ name: 'Gitea', icon: 'simple-icons:gitea', link: 'https://git.sirblob.co/SirBlob' },
{ name: 'LinkedIn', icon: 'mdi:linkedin', link: 'https://www.linkedin.com/in/gmanjunatha/' },
{ name: 'Devpost', icon: 'simple-icons:devpost', link: 'https://devpost.com/Sir_Blob_' },
{ name: 'Discord', icon: 'ic:baseline-discord', link: 'https://discord.com/users/sir_blob_' }
]
};
// ============================================================================
// SKILLS
// ============================================================================
export const skills = {
languages: ['Python', 'JavaScript', 'TypeScript', 'C', 'C++', 'Java', 'Node.js'],
frameworks: ['Arduino', 'Bootstrap', 'TailwindCSS', 'Discord.js', 'React', 'Electron', 'Svelte'],
applications: ['Windows', 'Linux', 'macOS', 'IntelliJ', 'VS Code', 'Git', 'Blender', 'Godot'],
platforms: ['Windows', 'Linux', 'macOS', 'Arduino', 'Raspberry Pi'],
tools: ['Git', 'Docker', 'Neovim', 'VS Code'],
databases: ['MongoDB', 'Redis', 'SQLite'],
interests: ['Open Source', '3D Graphics', 'Game Development', 'Embedded Systems', 'AI/ML']
};

View File

@@ -2,7 +2,7 @@
import TerminalTUI from '$lib/components/TerminalTUI.svelte'; import TerminalTUI from '$lib/components/TerminalTUI.svelte';
import type { TerminalLine } from '$lib/components/tui/types'; import type { TerminalLine } from '$lib/components/tui/types';
import ModelViewer from '$lib/components/ModelViewer.svelte'; import ModelViewer from '$lib/components/ModelViewer.svelte';
import { user } from '$lib/config'; import { user, models as configModels } from '$lib/config';
import { getPageSpeedMultiplier, getPageAutoscroll } from '$lib'; import { getPageSpeedMultiplier, getPageAutoscroll } from '$lib';
import { themeColors } from '$lib/stores/theme'; import { themeColors } from '$lib/stores/theme';
import Icon from '@iconify/svelte'; import Icon from '@iconify/svelte';
@@ -10,13 +10,23 @@
const speed = getPageSpeedMultiplier('models'); const speed = getPageSpeedMultiplier('models');
const autoscroll = getPageAutoscroll('models'); const autoscroll = getPageAutoscroll('models');
// Available GLB files in static/models/ // Build GLB model list from config (`models`) while preserving metadata.
const glbModels = [ // Keep `name`, `path`, `thumbnail`, and `description` for richer UI use.
{ name: 'Bake Potato', path: '/models/BakePotato.glb' }, const glbModels = (configModels && configModels.length > 0)
{ name: 'Soda Can', path: '/models/Soda.glb' } ? configModels
]; .map(m => ({
name: m.name,
path: m.modelUrl ?? m.downloadUrl ?? m.thumbnail ?? '',
thumbnail: m.thumbnail ?? '',
description: m.description ?? ''
}))
.filter(m => m.path)
: [
{ name: 'Bake Potato', path: '/models/BakePotato.glb', thumbnail: '/models/BakePotato-thumb.png', description: 'A fun baked-potato 3D model.' },
{ name: 'Soda Can', path: '/models/Soda.glb', thumbnail: '/models/Soda-thumb.png', description: 'A realistic soda can model.' }
];
let selectedModel = $state(glbModels[0]); let selectedModel = $state(glbModels[0] ?? { name: '', path: '', thumbnail: '', description: '' });
let showViewer = $state(false); let showViewer = $state(false);
function selectModel(model: typeof glbModels[0]) { function selectModel(model: typeof glbModels[0]) {
@@ -26,7 +36,7 @@
// Build the terminal lines for the models page // Build the terminal lines for the models page
const lines: TerminalLine[] = [ const lines: TerminalLine[] = [
{ type: 'command', content: 'ls ~/3d-models/' }, { type: 'command', content: 'ls ~/models/' },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
{ type: 'header', content: '(&primary,bold)3D Models(&)' }, { type: 'header', content: '(&primary,bold)3D Models(&)' },
@@ -63,7 +73,7 @@
> >
<!-- Terminal Section --> <!-- Terminal Section -->
<div class="terminal-section"> <div class="terminal-section">
<TerminalTUI {lines} title="~/3d-models" interactive={true} {speed} {autoscroll} /> <TerminalTUI {lines} title="~/models" interactive={true} {speed} {autoscroll} />
</div> </div>
<!-- 3D Viewer Section --> <!-- 3D Viewer Section -->

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import TerminalTUI from '$lib/components/TerminalTUI.svelte'; import TerminalTUI from '$lib/components/TerminalTUI.svelte';
import type { TerminalLine } from '$lib/components/tui/types'; import type { TerminalLine } from '$lib/components/tui/types';
import { user, sortedCards } from '$lib/config'; import { user, sortedCards, projects } from '$lib/config';
import { getPageSpeedMultiplier, getPageAutoscroll } from '$lib'; import { getPageSpeedMultiplier, getPageAutoscroll } from '$lib';
const speed = getPageSpeedMultiplier('projects'); const speed = getPageSpeedMultiplier('projects');
@@ -17,6 +17,47 @@
{ type: 'divider', content: 'PROJECTS' }, { type: 'divider', content: 'PROJECTS' },
{ type: 'command', content: 'ls ~/projects --grid' }, { type: 'command', content: 'ls ~/projects --grid' },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
...projects.filter(p => p.featured).flatMap(project => [
{ type: 'header' as const, content: `(&primary,bold)${project.name}(&)` },
{ type: 'output' as const, content: `(&muted)${project.description}(&)` },
{ type: 'info' as const, content: `(&info)Tech: (&primary)${project.tech.join(', ')}(&)` },
...(project.github ? [{
type: 'button' as const,
content: 'View on GitHub',
icon: 'mdi:github',
style: 'accent' as const,
href: project.github
}] : []),
...(project.live ? [{
type: 'button' as const,
content: 'View Live Demo',
icon: 'mdi:open-in-new',
style: 'accent' as const,
href: project.live
}] : []),
{ type: 'blank' as const, content: '' }
]),
...projects.filter(p => !p.featured).flatMap(project => [
{ type: 'success' as const, content: `(&success)${project.name}(&)` },
{ type: 'output' as const, content: `(&muted)${project.description}(&)` },
{ type: 'info' as const, content: `(&info)Tech:(&) (&primary)${project.tech.join(', ')}(&)` },
...(project.github ? [{
type: 'button' as const,
content: 'View on GitHub',
icon: 'mdi:github',
style: 'accent' as const,
href: project.github
}] : []),
...(project.live ? [{
type: 'button' as const,
content: 'View Live',
icon: 'mdi:open-in-new',
style: 'accent' as const,
href: project.live
}] : []),
{ type: 'blank' as const, content: '' }
]),
{ type: 'blank', content: '' },
{ type: 'divider', content: 'HACKATHONS' }, { type: 'divider', content: 'HACKATHONS' },
{ type: 'command', content: 'ls ~/hackathons --grid' }, { type: 'command', content: 'ls ~/hackathons --grid' },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },