Make WebP the default image format

This commit is contained in:
Andras Schmelczer 2022-09-22 09:06:51 +02:00
parent 890133d10e
commit 94faabca34
No known key found for this signature in database
GPG key ID: 0EA1BC97D0AB076E
23 changed files with 65 additions and 72 deletions

View file

@ -1,12 +1,15 @@
# Timeline # Timeline
An easily configurable portfolio. > An easy-to-configure portfolio.
> [Click for live version](https://schmelczer.dev) [![Check, build and deploy to GitHub Pages](https://github.com/schmelczer/schmelczer.github.io/actions/workflows/lint-and-deploy.yaml/badge.svg)](https://github.com/schmelczer/schmelczer.github.io/actions/workflows/lint-and-deploy.yaml)
[Check out the live version.](https://schmelczer.dev)
## Configuration ## Configuration
- The actual content is in the [data](src/data) folder starting with [portfolio.ts](src/data/portfolio.ts) - The actual content is in the [data](src/data) folder, starting with [portfolio.ts](src/data/portfolio.ts)
- The assets referenced should be located in [data/media](src/data/media) - The assets referenced should be located in [data/media](src/data/media)
## Build ## Build
@ -14,3 +17,8 @@ An easily configurable portfolio.
1. `npm install` 1. `npm install`
2. `npm run build` 2. `npm run build`
3. You can find the results in the [dist](dist) folder 3. You can find the results in the [dist](dist) folder
## Info
- All images are converted to `WebP` after being imported into any file.
> Except for the og-image, and SVGs.

8
custom.d.ts vendored
View file

@ -3,7 +3,7 @@ declare module '*.svg' {
export default content; export default content;
} }
declare module '*.jpg?format=webp' { declare module '*.jpg' {
import { ResponsiveImage } from 'src/types/responsive-image'; import { ResponsiveImage } from 'src/types/responsive-image';
const content: ResponsiveImage; const content: ResponsiveImage;
export default content; export default content;
@ -15,12 +15,6 @@ declare module '*.png' {
export default content; export default content;
} }
declare module '*.png?format=webp' {
import { ResponsiveImage } from 'src/types/responsive-image';
const content: ResponsiveImage;
export default content;
}
declare module '*.mp4' { declare module '*.mp4' {
import { url } from 'src/types/url'; import { url } from 'src/types/url';
const content: url; const content: url;

View file

@ -6,7 +6,7 @@ import { Main } from '../page/main/main';
import { PageElement } from '../page/page-element'; import { PageElement } from '../page/page-element';
import { PageTimeline } from '../page/timeline/timeline'; import { PageTimeline } from '../page/timeline/timeline';
import cvEnglish from './media/cv-andras-schmelczer.pdf'; import cvEnglish from './media/cv-andras-schmelczer.pdf';
import meWebP from './media/me.jpg?format=webp'; import me from './media/me.jpg';
import { adAstraTimelineElement } from './projects/ad-astra'; import { adAstraTimelineElement } from './projects/ad-astra';
import { citySimulationTimelineElement } from './projects/city-simulation'; import { citySimulationTimelineElement } from './projects/city-simulation';
import { declaredTimelineElement } from './projects/declared'; import { declaredTimelineElement } from './projects/declared';
@ -26,7 +26,7 @@ export const create = (): Array<PageElement> => [
new PageBackground(1, 1), new PageBackground(1, 1),
new PageHeader({ new PageHeader({
name: `András Schmelczer`, name: `András Schmelczer`,
imageWebP: meWebP, image: me,
imageAltText: `a picture of me`, imageAltText: `a picture of me`,
about: [ about: [
` `

View file

@ -1,6 +1,6 @@
import { Video } from '../../page/basics/video/video'; import { Video } from '../../page/basics/video/video';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import adAstraWebP from '../media/ad_astra.jpg?format=webp'; import adAstra from '../media/ad_astra.jpg';
import adAstraMp4 from '../media/mp4/ad_astra.mp4'; import adAstraMp4 from '../media/mp4/ad_astra.mp4';
import adAstraWebM from '../media/webm/ad_astra.webm'; import adAstraWebM from '../media/webm/ad_astra.webm';
import { GitHub } from '../shared'; import { GitHub } from '../shared';
@ -9,7 +9,7 @@ export const adAstraTimelineElement: TimelineElementParameters = {
title: `Gaming on an ATtiny85`, title: `Gaming on an ATtiny85`,
date: `2020 spring`, date: `2020 spring`,
figure: new Video({ figure: new Video({
posterWebP: adAstraWebP, poster: adAstra,
mp4: adAstraMp4, mp4: adAstraMp4,
webm: adAstraWebM, webm: adAstraWebM,
}), }),

View file

@ -1,14 +1,14 @@
import { Video } from '../../page/basics/video/video'; import { Video } from '../../page/basics/video/video';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import citySimulationMp4 from '../media/mp4/simulation.mp4'; import citySimulationMp4 from '../media/mp4/simulation.mp4';
import citySimulationPosterWebP from '../media/simulation.jpg?format=webp'; import citySimulationPoster from '../media/simulation.jpg';
import citySimulationWebM from '../media/webm/simulation.webm'; import citySimulationWebM from '../media/webm/simulation.webm';
export const citySimulationTimelineElement: TimelineElementParameters = { export const citySimulationTimelineElement: TimelineElementParameters = {
title: `City simulation`, title: `City simulation`,
date: `2018 July - August`, date: `2018 July - August`,
figure: new Video({ figure: new Video({
posterWebP: citySimulationPosterWebP, poster: citySimulationPoster,
mp4: citySimulationMp4, mp4: citySimulationMp4,
webm: citySimulationWebM, webm: citySimulationWebM,
}), }),

View file

@ -1,12 +1,12 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import colourWebP from '../media/color.jpg?format=webp'; import colour from '../media/color.jpg';
export const colorsTimelineElement: TimelineElementParameters = { export const colorsTimelineElement: TimelineElementParameters = {
title: `Photo colour grader`, title: `Photo colour grader`,
date: `2018 June`, date: `2018 June`,
figure: Image({ figure: Image({
imageWebP: colourWebP, image: colour,
alt: `a picture of the app`, alt: `a picture of the app`,
container: true, container: true,
}), }),

View file

@ -1,13 +1,13 @@
import { Preview } from '../../page/basics/preview/preview'; import { Preview } from '../../page/basics/preview/preview';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import declaredWebP from '../media/decla-red.png?format=webp'; import declared from '../media/decla-red.png';
import bscThesis from '../media/sdf2d-andras-schmelczer.pdf'; import bscThesis from '../media/sdf2d-andras-schmelczer.pdf';
import { GitHub, Open, Thesis } from '../shared'; import { GitHub, Open, Thesis } from '../shared';
export const declaredTimelineElement: TimelineElementParameters = { export const declaredTimelineElement: TimelineElementParameters = {
title: `Multiplayer game`, title: `Multiplayer game`,
date: `2020 autumn`, date: `2020 autumn`,
figure: new Preview(declaredWebP, 'https://decla.red', 'The website of the video game'), figure: new Preview(declared, 'https://decla.red', 'The website of the video game'),
description: ` description: `
Using SDF-2D (my ray tracing graphics library), I created a conquest-style multiplayer browser game. Using SDF-2D (my ray tracing graphics library), I created a conquest-style multiplayer browser game.
It even runs on mobiles. It even runs on mobiles.

View file

@ -1,6 +1,6 @@
import { Video } from '../../page/basics/video/video'; import { Video } from '../../page/basics/video/video';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import forexPosterWebP from '../media/forex.jpg?format=webp'; import forexPoster from '../media/forex.jpg';
import forexMp4 from '../media/mp4/forex.mp4'; import forexMp4 from '../media/mp4/forex.mp4';
import forexWebM from '../media/webm/forex.webm'; import forexWebM from '../media/webm/forex.webm';
@ -8,7 +8,7 @@ export const forexTimelineElement: TimelineElementParameters = {
title: `Predicting foreign exchange rates`, title: `Predicting foreign exchange rates`,
date: `2019 autumn`, date: `2019 autumn`,
figure: new Video({ figure: new Video({
posterWebP: forexPosterWebP, poster: forexPoster,
mp4: forexMp4, mp4: forexMp4,
webm: forexWebM, webm: forexWebM,
invertButton: true, invertButton: true,

View file

@ -1,14 +1,14 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import mscThesis from '../media/great-ai-andras-schmelczer.pdf'; import mscThesis from '../media/great-ai-andras-schmelczer.pdf';
import greatAiWebP from '../media/great-ai.png?format=webp'; import greatAi from '../media/great-ai.png';
import { Open, PyPi, Thesis } from '../shared'; import { Open, PyPi, Thesis } from '../shared';
export const greatAiTimelineElement: TimelineElementParameters = { export const greatAiTimelineElement: TimelineElementParameters = {
title: `GreatAI`, title: `GreatAI`,
date: `2022`, date: `2022`,
figure: Image({ figure: Image({
imageWebP: greatAiWebP, image: greatAi,
alt: `some example code using GreatAI`, alt: `some example code using GreatAI`,
container: true, container: true,
}), }),

View file

@ -1,6 +1,6 @@
import { Video } from '../../page/basics/video/video'; import { Video } from '../../page/basics/video/video';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import ledPosterWebP from '../media/led.jpg?format=webp'; import ledPoster from '../media/led.jpg';
import ledMp4 from '../media/mp4/led.mp4'; import ledMp4 from '../media/mp4/led.mp4';
import ledWebM from '../media/webm/led.webm'; import ledWebM from '../media/webm/led.webm';
@ -8,7 +8,7 @@ export const ledsTimelineElement: TimelineElementParameters = {
title: `Lights synchronised to music`, title: `Lights synchronised to music`,
date: `2016 spring`, date: `2016 spring`,
figure: new Video({ figure: new Video({
posterWebP: ledPosterWebP, poster: ledPoster,
mp4: ledMp4, mp4: ledMp4,
webm: ledWebM, webm: ledWebM,
}), }),

View file

@ -1,13 +1,13 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import myNotesWebP from '../media/my-notes.png?format=webp'; import myNotes from '../media/my-notes.png';
import { GitHub } from '../shared'; import { GitHub } from '../shared';
export const myNotesTimelineElement: TimelineElementParameters = { export const myNotesTimelineElement: TimelineElementParameters = {
title: `My Notes`, title: `My Notes`,
date: `2019 November`, date: `2019 November`,
figure: Image({ figure: Image({
imageWebP: myNotesWebP, image: myNotes,
alt: `two screenshots of the application`, alt: `two screenshots of the application`,
container: true, container: true,
}), }),

View file

@ -1,12 +1,12 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import processSimulatorInputWebP from '../media/process-simulator-input.jpg?format=webp'; import processSimulatorInput from '../media/process-simulator-input.jpg';
export const nuclearEditorTimelineElement: TimelineElementParameters = { export const nuclearEditorTimelineElement: TimelineElementParameters = {
title: `Graph editing application`, title: `Graph editing application`,
date: `2018 October - November`, date: `2018 October - November`,
figure: Image({ figure: Image({
imageWebP: processSimulatorInputWebP, image: processSimulatorInput,
alt: `a picture of the simulator's UI`, alt: `a picture of the simulator's UI`,
container: true, container: true,
}), }),

View file

@ -1,12 +1,12 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import processSimulatorWebP from '../media/process-simulator.jpg?format=webp'; import processSimulator from '../media/process-simulator.jpg';
export const nuclearTimelineElement: TimelineElementParameters = { export const nuclearTimelineElement: TimelineElementParameters = {
title: `Simulating the cooling system of a nuclear facility`, title: `Simulating the cooling system of a nuclear facility`,
date: `2018 October - November`, date: `2018 October - November`,
figure: Image({ figure: Image({
imageWebP: processSimulatorWebP, image: processSimulator,
alt: `a screenshot of the simulator`, alt: `a screenshot of the simulator`,
container: true, container: true,
}), }),

View file

@ -1,13 +1,13 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import photosWebP from '../media/photos.jpg?format=webp'; import photos from '../media/photos.jpg';
import { Open } from '../shared'; import { Open } from '../shared';
export const photosTimelineElement: TimelineElementParameters = { export const photosTimelineElement: TimelineElementParameters = {
title: `Photos`, title: `Photos`,
date: `2016 summer`, date: `2016 summer`,
figure: Image({ figure: Image({
imageWebP: photosWebP, image: photos,
alt: `a picture of the website`, alt: `a picture of the website`,
container: true, container: true,
}), }),

View file

@ -1,14 +1,14 @@
import { Video } from '../../page/basics/video/video'; import { Video } from '../../page/basics/video/video';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import platformMp4 from '../media/mp4/platform.mp4'; import platformMp4 from '../media/mp4/platform.mp4';
import platformPosterWebP from '../media/platform.png?format=webp'; import platformPoster from '../media/platform.png';
import platformWebM from '../media/webm/platform.webm'; import platformWebM from '../media/webm/platform.webm';
export const platformGameTimelineElement: TimelineElementParameters = { export const platformGameTimelineElement: TimelineElementParameters = {
title: `Platform game`, title: `Platform game`,
date: `2017 autumn`, date: `2017 autumn`,
figure: new Video({ figure: new Video({
posterWebP: platformPosterWebP, poster: platformPoster,
mp4: platformMp4, mp4: platformMp4,
webm: platformWebM, webm: platformWebM,
}), }),

View file

@ -1,13 +1,13 @@
import { Preview } from '../../page/basics/preview/preview'; import { Preview } from '../../page/basics/preview/preview';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import sdf2dWebP from '../media/sdf2d.png?format=webp'; import sdf2d from '../media/sdf2d.png';
import { NPM, Open, Youtube } from '../shared'; import { NPM, Open, Youtube } from '../shared';
export const sdf2dTimelineElement: TimelineElementParameters = { export const sdf2dTimelineElement: TimelineElementParameters = {
title: `2D ray tracing`, title: `2D ray tracing`,
date: `2020 autumn`, date: `2020 autumn`,
figure: new Preview( figure: new Preview(
sdf2dWebP, sdf2d,
'https://sdf2d.schmelczer.dev', 'https://sdf2d.schmelczer.dev',
'A webpage showcasing the SDF-2D project.' 'A webpage showcasing the SDF-2D project.'
), ),

View file

@ -1,13 +1,13 @@
import { Image } from '../../page/basics/image/image.html'; import { Image } from '../../page/basics/image/image.html';
import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters'; import { TimelineElementParameters } from '../../page/timeline/timeline-element/timeline-element-parameters';
import towersWebP from '../media/towers.png?format=webp'; import towers from '../media/towers.png';
import { GitHub, Open } from '../shared'; import { GitHub, Open } from '../shared';
export const towersTimelineElement: TimelineElementParameters = { export const towersTimelineElement: TimelineElementParameters = {
title: `Towers tracking app`, title: `Towers tracking app`,
date: `2019 August - September`, date: `2019 August - September`,
figure: Image({ figure: Image({
imageWebP: towersWebP, image: towers,
alt: `a picture of the website`, alt: `a picture of the website`,
container: true, container: true,
}), }),

View file

@ -4,13 +4,13 @@ import { ResponsiveImage } from '../../../types/responsive-image';
import './image.scss'; import './image.scss';
export const Image = ({ export const Image = ({
imageWebP, image,
alt, alt,
container = false, container = false,
isIgnoredByImageViewer = false, isIgnoredByImageViewer = false,
imageScreenRatio = 0.8, imageScreenRatio = 0.8,
}: { }: {
imageWebP: ResponsiveImage; image: ResponsiveImage;
alt: string; alt: string;
container?: boolean; container?: boolean;
isIgnoredByImageViewer?: boolean; isIgnoredByImageViewer?: boolean;
@ -19,27 +19,27 @@ export const Image = ({
${ ${
container container
? `<div class="figure-container" style="padding-top:${ ? `<div class="figure-container" style="padding-top:${
(imageWebP.height / imageWebP.width) * 100 (image.height / image.width) * 100
}%">` }%">`
: '' : ''
} }
<div <div
class="image" class="image"
style="background-size: cover; background-image: url('${imageWebP.placeholder}')", style="background-size: cover; background-image: url('${image.placeholder}')",
}}> }}>
<picture loading="lazy"> <picture loading="lazy">
<source <source
srcset="${imageWebP.srcSet}" srcset="${image.srcSet}"
sizes="${getSizes(imageWebP, imageScreenRatio)}" sizes="${getSizes(image, imageScreenRatio)}"
type="image/webp" type="image/"
/> />
<img <img
${isIgnoredByImageViewer ? 'image-viewer-ignore' : ''} ${isIgnoredByImageViewer ? 'image-viewer-ignore' : ''}
tabindex="0" tabindex="0"
loading="lazy" loading="lazy"
width="${imageWebP.width}" width="${image.width}"
height="${imageWebP.height}" height="${image.height}"
src="${last(imageWebP.images)?.path}" src="${last(image.images)?.path}"
alt="${alt}" alt="${alt}"
/> />
</picture> </picture>

View file

@ -7,14 +7,14 @@ import './preview.scss';
export const generate = ({ export const generate = ({
alt, alt,
posterWebP, poster,
}: { }: {
alt: string; alt: string;
posterWebP: ResponsiveImage; poster: ResponsiveImage;
}): html => ` }): html => `
<div class="preview"> <div class="preview">
${Image({ ${Image({
imageWebP: posterWebP, image: poster,
alt, alt,
container: true, container: true,
isIgnoredByImageViewer: true, isIgnoredByImageViewer: true,

View file

@ -4,12 +4,8 @@ import { PageElement } from '../../page-element';
import { generate } from './preview.html'; import { generate } from './preview.html';
export class Preview extends PageElement { export class Preview extends PageElement {
public constructor( public constructor(poster: ResponsiveImage, private readonly url: string, alt: string) {
posterWebP: ResponsiveImage, super(createElement(generate({ poster, alt })));
private readonly url: string,
alt: string
) {
super(createElement(generate({ posterWebP, alt })));
this.url += '?portfolioView'; this.url += '?portfolioView';
this.query('.start-button').addEventListener('click', this.loadContent.bind(this)); this.query('.start-button').addEventListener('click', this.loadContent.bind(this));
} }

View file

@ -4,6 +4,6 @@ import { url } from '../../../types/url';
export interface VideoParameters { export interface VideoParameters {
mp4: url; mp4: url;
webm: url; webm: url;
posterWebP: ResponsiveImage; poster: ResponsiveImage;
invertButton?: boolean; invertButton?: boolean;
} }

View file

@ -5,17 +5,12 @@ import { Image } from '../../basics/image/image.html';
import { VideoParameters } from './video-parameters'; import { VideoParameters } from './video-parameters';
import './video.scss'; import './video.scss';
export const generate = ({ export const generate = ({ webm, mp4, poster, invertButton }: VideoParameters): html => `
webm,
mp4,
posterWebP,
invertButton,
}: VideoParameters): html => `
<div class="figure-container video-container" style="padding-top:${ <div class="figure-container video-container" style="padding-top:${
(posterWebP.height / posterWebP.width) * 100 (poster.height / poster.width) * 100
}%"> }%">
${Image({ ${Image({
imageWebP: posterWebP, image: poster,
alt: `thumbnail for the video`, alt: `thumbnail for the video`,
isIgnoredByImageViewer: true, isIgnoredByImageViewer: true,
})} })}

View file

@ -8,12 +8,12 @@ import { PageThemeSwitcher } from './theme-switcher/theme-switcher';
export class PageHeader extends PageElement { export class PageHeader extends PageElement {
public constructor({ public constructor({
name, name,
imageWebP, image,
imageAltText, imageAltText,
about, about,
}: { }: {
name: string; name: string;
imageWebP: ResponsiveImage; image: ResponsiveImage;
imageAltText: string; imageAltText: string;
about: Array<string>; about: Array<string>;
}) { }) {
@ -23,7 +23,7 @@ export class PageHeader extends PageElement {
name, name,
about, about,
photo: Image({ photo: Image({
imageWebP, image,
alt: imageAltText, alt: imageAltText,
imageScreenRatio: 0.2, imageScreenRatio: 0.2,
}), }),