From 806c04e47a71402025ccaac7e951ebfad085e841 Mon Sep 17 00:00:00 2001 From: Julian Lechner Date: Thu, 14 May 2026 13:34:56 +0200 Subject: [PATCH] improve: performance --- scripts/generate-optimized-assets.cjs | 2 +- src/app/home/home.component.spec.ts | 2 +- src/app/home/home.component.ts | 13 +++++++------ src/languages/de.ts | 24 ++++++++++++------------ src/languages/en.ts | 24 ++++++++++++------------ 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/scripts/generate-optimized-assets.cjs b/scripts/generate-optimized-assets.cjs index e16e2b3..58965d3 100644 --- a/scripts/generate-optimized-assets.cjs +++ b/scripts/generate-optimized-assets.cjs @@ -57,7 +57,7 @@ function getProfile(relativePath) { } if (normalizedRelativePath.startsWith('portrait/')) { - return { maxWidth: 640, quality: 82, alphaQuality: 90, variants: [128, 320, 480] }; + return { maxWidth: 640, quality: 82, alphaQuality: 90, variants: [128, 320, 384, 480] }; } return { maxWidth: 1600, quality: 82, alphaQuality: 92 }; diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts index 1098fb1..aa20c0f 100644 --- a/src/app/home/home.component.spec.ts +++ b/src/app/home/home.component.spec.ts @@ -434,7 +434,7 @@ describe('HomeComponent', (): void => { spyOn(window, 'matchMedia').and.callFake( (query: string): MediaQueryList => ({ - matches: query === '(prefers-reduced-motion: reduce)' ? false : true, + matches: query !== '(prefers-reduced-motion: reduce)', }) as MediaQueryList, ); diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 0607a33..e610cdb 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -137,7 +137,9 @@ export class HomeComponent implements OnInit, AfterViewInit, OnDestroy { } ngOnInit(): void { - this.initNameGradientScrollAnimation(); + this.zone.runOutsideAngular((): void => { + this.initNameGradientScrollAnimation(); + }); this.zone.runOutsideAngular((): void => { interval(1000) .pipe(takeUntilDestroyed(this.destroyRef)) @@ -151,8 +153,10 @@ export class HomeComponent implements OnInit, AfterViewInit, OnDestroy { } ngAfterViewInit(): void { - this.initProjectEntryRevealObserver(); - this.initAboutSectionScrollAnimation(); + this.zone.runOutsideAngular((): void => { + this.initProjectEntryRevealObserver(); + this.initAboutSectionScrollAnimation(); + }); } ngOnDestroy(): void { if (this.bioHideTimeoutId !== null) { @@ -231,13 +235,11 @@ export class HomeComponent implements OnInit, AfterViewInit, OnDestroy { if (!this.shouldEnableScrollEffects()) return; window.addEventListener('scroll', this.scheduleNameGradientUpdate, { passive: true }); window.addEventListener('resize', this.scheduleNameGradientUpdate, { passive: true }); - this.scheduleNameGradientUpdate(); } private initProjectEntryRevealObserver(): void { if (!this.shouldEnableScrollEffects()) return; window.addEventListener('scroll', this.scheduleProjectEntryRevealUpdate, { passive: true }); window.addEventListener('resize', this.scheduleProjectEntryRevealUpdate, { passive: true }); - this.scheduleProjectEntryRevealUpdate(); } private destroyProjectEntryRevealObserver(): void { if (typeof window === 'undefined' || typeof document === 'undefined') return; @@ -259,7 +261,6 @@ export class HomeComponent implements OnInit, AfterViewInit, OnDestroy { window.addEventListener('resize', this.scheduleAboutSectionScrollAnimationUpdate, { passive: true, }); - this.scheduleAboutSectionScrollAnimationUpdate(); } private destroyAboutSectionScrollAnimation(): void { if (typeof window === 'undefined' || typeof document === 'undefined') return; diff --git a/src/languages/de.ts b/src/languages/de.ts index 8cdddfe..dda5426 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -119,9 +119,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/me.webp', imageSrcset: - 'assets/optimized/portrait/me-320.webp 320w, assets/optimized/portrait/me-480.webp 480w, assets/optimized/portrait/me.webp 640w', + 'assets/optimized/portrait/me-320.webp 320w, assets/optimized/portrait/me-384.webp 384w, assets/optimized/portrait/me-480.webp 480w, assets/optimized/portrait/me.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 769, text: 'Ich', @@ -129,9 +129,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/love.webp', imageSrcset: - 'assets/optimized/portrait/love-320.webp 320w, assets/optimized/portrait/love-480.webp 480w, assets/optimized/portrait/love.webp 640w', + 'assets/optimized/portrait/love-320.webp 320w, assets/optimized/portrait/love-384.webp 384w, assets/optimized/portrait/love-480.webp 480w, assets/optimized/portrait/love.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 710, text: 'Meine Liebe', @@ -139,9 +139,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/scuba.webp', imageSrcset: - 'assets/optimized/portrait/scuba-320.webp 320w, assets/optimized/portrait/scuba-480.webp 480w, assets/optimized/portrait/scuba.webp 640w', + 'assets/optimized/portrait/scuba-320.webp 320w, assets/optimized/portrait/scuba-384.webp 384w, assets/optimized/portrait/scuba-480.webp 480w, assets/optimized/portrait/scuba.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 480, text: 'Tauchen', @@ -149,9 +149,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/trains.webp', imageSrcset: - 'assets/optimized/portrait/trains-320.webp 320w, assets/optimized/portrait/trains-480.webp 480w, assets/optimized/portrait/trains.webp 640w', + 'assets/optimized/portrait/trains-320.webp 320w, assets/optimized/portrait/trains-384.webp 384w, assets/optimized/portrait/trains-480.webp 480w, assets/optimized/portrait/trains.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 850, text: 'Züge', @@ -159,9 +159,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/traveling.webp', imageSrcset: - 'assets/optimized/portrait/traveling-320.webp 320w, assets/optimized/portrait/traveling-480.webp 480w, assets/optimized/portrait/traveling.webp 640w', + 'assets/optimized/portrait/traveling-320.webp 320w, assets/optimized/portrait/traveling-384.webp 384w, assets/optimized/portrait/traveling-480.webp 480w, assets/optimized/portrait/traveling.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 480, text: 'Reisen', @@ -169,9 +169,9 @@ export const deLanguage: LanguagePack = { { image: 'assets/optimized/portrait/culture.webp', imageSrcset: - 'assets/optimized/portrait/culture-320.webp 320w, assets/optimized/portrait/culture-480.webp 480w, assets/optimized/portrait/culture.webp 640w', + 'assets/optimized/portrait/culture-320.webp 320w, assets/optimized/portrait/culture-384.webp 384w, assets/optimized/portrait/culture-480.webp 480w, assets/optimized/portrait/culture.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 482, text: 'Kultur', diff --git a/src/languages/en.ts b/src/languages/en.ts index 7f78426..d6a6259 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -119,9 +119,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/me.webp', imageSrcset: - 'assets/optimized/portrait/me-320.webp 320w, assets/optimized/portrait/me-480.webp 480w, assets/optimized/portrait/me.webp 640w', + 'assets/optimized/portrait/me-320.webp 320w, assets/optimized/portrait/me-384.webp 384w, assets/optimized/portrait/me-480.webp 480w, assets/optimized/portrait/me.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 769, text: 'ME', @@ -129,9 +129,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/love.webp', imageSrcset: - 'assets/optimized/portrait/love-320.webp 320w, assets/optimized/portrait/love-480.webp 480w, assets/optimized/portrait/love.webp 640w', + 'assets/optimized/portrait/love-320.webp 320w, assets/optimized/portrait/love-384.webp 384w, assets/optimized/portrait/love-480.webp 480w, assets/optimized/portrait/love.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 710, text: 'My Love', @@ -139,9 +139,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/scuba.webp', imageSrcset: - 'assets/optimized/portrait/scuba-320.webp 320w, assets/optimized/portrait/scuba-480.webp 480w, assets/optimized/portrait/scuba.webp 640w', + 'assets/optimized/portrait/scuba-320.webp 320w, assets/optimized/portrait/scuba-384.webp 384w, assets/optimized/portrait/scuba-480.webp 480w, assets/optimized/portrait/scuba.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 480, text: 'Scuba Diving', @@ -149,9 +149,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/trains.webp', imageSrcset: - 'assets/optimized/portrait/trains-320.webp 320w, assets/optimized/portrait/trains-480.webp 480w, assets/optimized/portrait/trains.webp 640w', + 'assets/optimized/portrait/trains-320.webp 320w, assets/optimized/portrait/trains-384.webp 384w, assets/optimized/portrait/trains-480.webp 480w, assets/optimized/portrait/trains.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 850, text: 'Trains', @@ -159,9 +159,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/traveling.webp', imageSrcset: - 'assets/optimized/portrait/traveling-320.webp 320w, assets/optimized/portrait/traveling-480.webp 480w, assets/optimized/portrait/traveling.webp 640w', + 'assets/optimized/portrait/traveling-320.webp 320w, assets/optimized/portrait/traveling-384.webp 384w, assets/optimized/portrait/traveling-480.webp 480w, assets/optimized/portrait/traveling.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 480, text: 'Traveling', @@ -169,9 +169,9 @@ export const enLanguage: LanguagePack = { { image: 'assets/optimized/portrait/culture.webp', imageSrcset: - 'assets/optimized/portrait/culture-320.webp 320w, assets/optimized/portrait/culture-480.webp 480w, assets/optimized/portrait/culture.webp 640w', + 'assets/optimized/portrait/culture-320.webp 320w, assets/optimized/portrait/culture-384.webp 384w, assets/optimized/portrait/culture-480.webp 480w, assets/optimized/portrait/culture.webp 640w', imageSizes: - '(max-width: 700px) calc(100vw - 2rem), (max-width: 900px) min(100vw - 6rem, 560px), 560px', + '(max-width: 700px) calc(100vw - 4rem), (max-width: 900px) min(calc(100vw - 9rem), 560px), 320px', imageWidth: 640, imageHeight: 482, text: 'Culture',