Particles Update

This commit is contained in:
2025-11-29 06:58:20 +00:00
parent 82d896a38e
commit c32505cfca
8 changed files with 62 additions and 23 deletions

View File

@@ -7,10 +7,10 @@
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 95%; width: 100%;
margin: 0 auto; margin: 0 auto;
height: calc(100vh - var(--navbar-height) - 80px); height: calc(100vh - var(--navbar-height) - 65px);
max-height: calc(100vh - var(--navbar-height) - 80px); max-height: calc(100vh - var(--navbar-height) - 65px);
animation: tuiFadeIn 0.4s ease-out; animation: tuiFadeIn 0.4s ease-out;
} }

View File

@@ -12,11 +12,23 @@
.tui-inline-group { .tui-inline-group {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-start;
gap: 0.5rem; gap: 0.5rem;
margin-bottom: 0.2rem; margin-bottom: 0.2rem;
animation: lineSlideIn 0.15s ease-out; animation: lineSlideIn 0.15s ease-out;
} }
/* When inline group contains an image, allow text to wrap beside it */
.tui-inline-group:has(.inline-image) {
flex-wrap: nowrap;
align-items: flex-start;
}
.tui-inline-group:has(.inline-image) .inline-content {
flex: 1;
min-width: 0;
}
.inline-content { .inline-content {
display: inline; display: inline;
white-space: pre-wrap; white-space: pre-wrap;
@@ -179,6 +191,14 @@
padding: 0.5rem 0; padding: 0.5rem 0;
} }
/* Inline images */
.tui-image.inline-image {
display: inline-flex;
padding: 0;
vertical-align: middle;
flex-shrink: 0;
}
.tui-image img { .tui-image img {
border-radius: 6px; border-radius: 6px;
border: 1px solid var(--terminal-border); border: 1px solid var(--terminal-border);

View File

@@ -3,10 +3,11 @@
import { T } from '@threlte/core'; import { T } from '@threlte/core';
import ParticleField from './ParticleField.svelte'; import ParticleField from './ParticleField.svelte';
import { themeColors, mode } from '$lib/stores/theme'; import { themeColors, mode } from '$lib/stores/theme';
import * as THREE from 'three';
import '$lib/assets/css/background-3d.css'; import '$lib/assets/css/background-3d.css';
let bgColor = $derived($mode === 'dark' ? $themeColors.background : $themeColors.background); // Reactive theme colors
const bgColor = $derived($themeColors.background);
const primaryColor = $derived($themeColors.primary);
</script> </script>
<div class="scene-container"> <div class="scene-container">
@@ -26,7 +27,7 @@
<T.DirectionalLight <T.DirectionalLight
position={[5, 5, 5]} position={[5, 5, 5]}
intensity={0.5} intensity={0.5}
color={$themeColors.primary} color={primaryColor}
/> />
<!-- Particle system --> <!-- Particle system -->

View File

@@ -17,6 +17,14 @@
let velocities: Float32Array; let velocities: Float32Array;
let time = 0; let time = 0;
// Reactive theme values - use accent or a darker color for light mode visibility
const currentMode = $derived($mode);
const particleColor = $derived(
currentMode === 'dark'
? $themeColors.primary
: $themeColors.accent || $themeColors.primary
);
// Create particles // Create particles
function createParticles() { function createParticles() {
positions = new Float32Array(particleCount * 3); positions = new Float32Array(particleCount * 3);
@@ -40,10 +48,11 @@
particlesMaterial = new THREE.PointsMaterial({ particlesMaterial = new THREE.PointsMaterial({
size: 0.05, size: 0.05,
color: new THREE.Color(particleColor),
sizeAttenuation: true, sizeAttenuation: true,
transparent: true, transparent: true,
opacity: 0.6, opacity: currentMode === 'dark' ? 0.6 : 0.8,
blending: THREE.AdditiveBlending, blending: currentMode === 'dark' ? THREE.AdditiveBlending : THREE.NormalBlending,
depthWrite: false depthWrite: false
}); });
@@ -54,12 +63,13 @@
createParticles(); createParticles();
}); });
// Update particle color based on theme // Update particle color and opacity based on theme
$effect(() => { $effect(() => {
if (particlesMaterial) { if (particlesMaterial) {
const color = new THREE.Color($themeColors.primary); particlesMaterial.color.set(particleColor);
particlesMaterial.color = color; particlesMaterial.opacity = currentMode === 'dark' ? 0.6 : 0.8;
particlesMaterial.opacity = $mode === 'dark' ? 0.6 : 0.4; particlesMaterial.blending = currentMode === 'dark' ? THREE.AdditiveBlending : THREE.NormalBlending;
particlesMaterial.needsUpdate = true;
} }
}); });

View File

@@ -70,6 +70,7 @@
{@const line = displayed.parsed.line} {@const line = displayed.parsed.line}
{@const idx = group.indices[j]} {@const idx = group.indices[j]}
{@const visibleSegments = getSegmentsUpToChar(displayed.parsed.segments, displayed.charIndex)} {@const visibleSegments = getSegmentsUpToChar(displayed.parsed.segments, displayed.charIndex)}
{@const showImage = displayed.showImage}
{#if line.type === 'button'} {#if line.type === 'button'}
<TuiButton {line} index={idx} selected={selectedIndex === idx} onClick={onButtonClick} onHover={onHoverButton} inline={true} /> <TuiButton {line} index={idx} selected={selectedIndex === idx} onClick={onButtonClick} onHover={onHoverButton} inline={true} />
{:else if line.type === 'link'} {:else if line.type === 'link'}
@@ -84,7 +85,14 @@
<TuiCheckbox {line} inline={true} /> <TuiCheckbox {line} inline={true} />
{:else if line.type === 'toggle'} {:else if line.type === 'toggle'}
<TuiToggle {line} inline={true} /> <TuiToggle {line} inline={true} />
{:else} {:else if line.type === 'image' && showImage}
<div class="tui-image inline-image">
<img src={line.image} alt={line.imageAlt || 'Image'} style="max-width: {line.imageWidth || 300}px" />
{#if line.content}
<span class="image-caption">{line.content}</span>
{/if}
</div>
{:else if line.type !== 'image'}
<span class="inline-content {line.type}"> <span class="inline-content {line.type}">
{getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}<Icon icon={segment.icon} width="14" class="inline-icon" />{:else if getSegmentStyle(segment)}<span style={getSegmentStyle(segment)}>{segment.text}</span>{:else}{segment.text}{/if}{/each} {getLinePrefix(line.type)}{#each visibleSegments as segment}{#if segment.icon}<Icon icon={segment.icon} width="14" class="inline-icon" />{:else if getSegmentStyle(segment)}<span style={getSegmentStyle(segment)}>{segment.text}</span>{:else}{segment.text}{/if}{/each}
</span> </span>

View File

@@ -18,7 +18,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
// alt/option + t: toggle mode (hold+digit to pick theme) // alt/option + t: toggle mode (hold+digit to pick theme)
// keydown: start hold // keydown: start hold
hotkeys('alt+t', (e) => { hotkeys('alt+b', (e) => {
if (e.repeat) return; if (e.repeat) return;
tHeld = true; tHeld = true;
tDigitUsed = false; tDigitUsed = false;
@@ -26,7 +26,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
}); });
// macOS alias: option // macOS alias: option
hotkeys('option+t', (e) => { hotkeys('option+b', (e) => {
if (e.repeat) return; if (e.repeat) return;
tHeld = true; tHeld = true;
tDigitUsed = false; tDigitUsed = false;
@@ -34,7 +34,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
}); });
// keyup: toggle if no digit used // keyup: toggle if no digit used
hotkeys('alt+t', { keyup: true }, (e) => { hotkeys('alt+b', { keyup: true }, (e) => {
if (!tDigitUsed && tHeld) { if (!tDigitUsed && tHeld) {
const now = Date.now(); const now = Date.now();
if (now - lastToggleAt > 400) { if (now - lastToggleAt > 400) {
@@ -47,7 +47,7 @@ export function registerKeybinds(opts: KeybindsOptions) {
e.preventDefault(); e.preventDefault();
}); });
hotkeys('option+t', { keyup: true }, (e) => { hotkeys('option+b', { keyup: true }, (e) => {
if (!tDigitUsed && tHeld) { if (!tDigitUsed && tHeld) {
const now = Date.now(); const now = Date.now();
if (now - lastToggleAt > 400) { if (now - lastToggleAt > 400) {
@@ -99,8 +99,8 @@ export function registerKeybinds(opts: KeybindsOptions) {
export function unregisterKeybinds() { export function unregisterKeybinds() {
// Unbind all key patterns we registered // Unbind all key patterns we registered
hotkeys.unbind('alt+t'); hotkeys.unbind('alt+b');
hotkeys.unbind('option+t'); hotkeys.unbind('option+b');
const tThemeKeys = Array.from({ length: 9 }, (_, i) => `alt+t+${i + 1}`).join(','); const tThemeKeys = Array.from({ length: 9 }, (_, i) => `alt+t+${i + 1}`).join(',');
const tThemeKeysOption = Array.from({ length: 9 }, (_, i) => `option+t+${i + 1}`).join(','); const tThemeKeysOption = Array.from({ length: 9 }, (_, i) => `option+t+${i + 1}`).join(',');
hotkeys.unbind(`${tThemeKeys},${tThemeKeysOption}`); hotkeys.unbind(`${tThemeKeys},${tThemeKeysOption}`);

View File

@@ -15,7 +15,7 @@ export const lines: TerminalLine[] = [
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
{ type: 'header', content: `Welcome to ${user.displayname}'s Portfolio` }, { type: 'header', content: `Welcome to ${user.displayname}'s Portfolio` },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
// { type: 'image', content: '', image: user.avatar, imageAlt: user.name, imageWidth: 120, inline: false }, { type: 'image', content: '', image: user.avatar, imageAlt: user.name, imageWidth: 120, inline: true },
{ type: 'output', content: `(&muted)${user.bio}(&)`, inline: true }, { type: 'output', content: `(&muted)${user.bio}(&)`, inline: true },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
@@ -34,9 +34,9 @@ export const lines: TerminalLine[] = [
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
{ type: 'divider', content: 'Website Keybinds' }, { type: 'divider', content: 'Website Keybinds' },
{ type: 'blank', content: '' }, { type: 'blank', content: '' },
{ type: 'output', content: '(&orange)Toggle Light/Dark Mode(&) (&text, bold)(Alt/Option+T)(&)' , inline: true }, { type: 'output', content: '(&orange)Toggle Light/Dark Mode(&) (&text, bold)(Alt/Option+B)(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true }, { type: 'output', content: '(&muted)•(&)' , inline: true },
{ type: 'output', content: '(&orange)Select Theme(&) (&text, bold)Use Alt/Option+T + [#](&)' , inline: true }, { type: 'output', content: '(&orange)Select Theme(&) (&text, bold)(Alt/Option+T + [#])(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true }, { type: 'output', content: '(&muted)•(&)' , inline: true },
{ type: 'output', content: '(&orange)Skip typing animation(&) (&text, bold)(Y)(&)' , inline: true }, { type: 'output', content: '(&orange)Skip typing animation(&) (&text, bold)(Y)(&)' , inline: true },
{ type: 'output', content: '(&muted)•(&)' , inline: true }, { type: 'output', content: '(&muted)•(&)' , inline: true },

View File

@@ -73,10 +73,10 @@
color: {$themeColors.text}; color: {$themeColors.text};
" "
> >
<Background3D />
<NavbarWaybar /> <NavbarWaybar />
<!-- <Navbar /> --> <!-- <Navbar /> -->
<main class="main-content"> <main class="main-content">
<Background3D />
{@render children()} {@render children()}
</main> </main>
</div> </div>