add first draft for work examples
This commit is contained in:
parent
46d559784a
commit
5faecf4f25
18 changed files with 609 additions and 106 deletions
|
|
@ -7,37 +7,28 @@ import SplitText from 'gsap/dist/SplitText';
|
||||||
import { PixiPlugin } from "gsap/dist/PixiPlugin";
|
import { PixiPlugin } from "gsap/dist/PixiPlugin";
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import createCanvasText from '$lib/utils/creareCanvasText';
|
import createCanvasText from '$lib/utils/createCanvasText';
|
||||||
|
import createCanvasImg from '$lib/utils/createCanvasImg';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
export let textsToCanvas: NodeListOf<Element>;
|
export let textsToCanvas: Array<HTMLElement> = [];
|
||||||
|
export let imgsToCanvas: Array<HTMLElement> = [];
|
||||||
let app: PIXI.Application;
|
let app: PIXI.Application;
|
||||||
|
let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
onMount(()=>{
|
onMount(()=>{
|
||||||
|
|
||||||
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
|
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
|
||||||
|
|
||||||
if (document.querySelector('.homeCanvas')) {
|
|
||||||
app = new PIXI.Application({
|
app = new PIXI.Application({
|
||||||
resizeTo: window,
|
resizeTo: window,
|
||||||
antialias: true,
|
antialias: true,
|
||||||
autoDensity: true,
|
autoDensity: true,
|
||||||
resolution: 2,
|
resolution: 2,
|
||||||
backgroundAlpha: 0,
|
backgroundAlpha: 0,
|
||||||
view: document.querySelector('.homeCanvas') as HTMLCanvasElement,
|
view: canvas,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else {
|
|
||||||
app = new PIXI.Application({
|
|
||||||
resizeTo: window,
|
|
||||||
antialias: true,
|
|
||||||
autoDensity: true,
|
|
||||||
resolution: 2,
|
|
||||||
backgroundAlpha: 0,
|
|
||||||
});
|
|
||||||
let canvaselem = document.body.appendChild(app.view as HTMLCanvasElement);
|
|
||||||
canvaselem.classList.add('homeCanvas');
|
|
||||||
}
|
|
||||||
//for debugging but Typescript has an issue with this:
|
//for debugging but Typescript has an issue with this:
|
||||||
// globalThis.__PIXI_APP__ = app as any;
|
// globalThis.__PIXI_APP__ = app as any;
|
||||||
|
|
||||||
|
|
@ -86,12 +77,11 @@ onMount(()=>{
|
||||||
async function convertText(){
|
async function convertText(){
|
||||||
await tick();
|
await tick();
|
||||||
textsToCanvas.forEach((element) => {
|
textsToCanvas.forEach((element) => {
|
||||||
elems.push(element as HTMLElement);
|
elems.push(element);
|
||||||
let canvasText = createCanvasText(element as HTMLElement, app.stage);
|
let canvasText = createCanvasText(element, app.stage);
|
||||||
canvasTexts.push(canvasText as PIXI.Text);
|
canvasTexts.push(canvasText);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
convertText();
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------
|
/*----------------------------------
|
||||||
|
|
@ -106,11 +96,45 @@ onMount(()=>{
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Convert images to canvas
|
||||||
|
* createCanvacImgs function
|
||||||
|
----------------------------------*/
|
||||||
|
let canvasImgs: Array<PIXI.Sprite> = [];
|
||||||
|
let imgElems: Array<HTMLElement> = [];
|
||||||
|
|
||||||
|
function convertImgs(){
|
||||||
|
imgsToCanvas.forEach((element) => {
|
||||||
|
imgElems.push(element);
|
||||||
|
let canvasImg = createCanvasImg(element, app.stage);
|
||||||
|
canvasImgs.push(canvasImg);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
convertImgs();
|
||||||
|
convertText();
|
||||||
|
}, 100);
|
||||||
|
// convertImgs();
|
||||||
|
// convertText();
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Function to update text on canvas
|
||||||
|
* runs in the Ticker
|
||||||
|
----------------------------------*/
|
||||||
|
function updateImgs(){
|
||||||
|
canvasImgs.forEach((image, index) => {
|
||||||
|
let imagePosition = imgElems[index].getBoundingClientRect();
|
||||||
|
image.position.set(imagePosition.x, imagePosition.y);
|
||||||
|
image.width = imagePosition.width;
|
||||||
|
image.height = imagePosition.height;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------
|
/*----------------------------------
|
||||||
* Mousemove events
|
* Mousemove events
|
||||||
*----------------------------------*/
|
*----------------------------------*/
|
||||||
window.addEventListener('pointermove', (e) => {
|
window.addEventListener('mousemove', (e) => {
|
||||||
const pointerX = e.clientX / window.innerWidth;
|
const pointerX = e.clientX / window.innerWidth;
|
||||||
const pointerY = e.clientY / window.innerHeight;
|
const pointerY = e.clientY / window.innerHeight;
|
||||||
const pointerXfrac = pointerX - 0.5;
|
const pointerXfrac = pointerX - 0.5;
|
||||||
|
|
@ -128,9 +152,9 @@ onMount(()=>{
|
||||||
app.ticker.add((delta) => {
|
app.ticker.add((delta) => {
|
||||||
elapsed += delta;
|
elapsed += delta;
|
||||||
bulgefilter.center = [(center[0] + Math.sin(elapsed/200)/20 ),(center[1] + Math.cos(elapsed/200)/20 )];
|
bulgefilter.center = [(center[0] + Math.sin(elapsed/200)/20 ),(center[1] + Math.cos(elapsed/200)/20 )];
|
||||||
|
updateImgs();
|
||||||
updateText();
|
updateText();
|
||||||
})
|
})
|
||||||
console.log('HomeCanvas mounted', textsToCanvas);
|
|
||||||
}) // <- end onMount
|
}) // <- end onMount
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
|
|
@ -140,3 +164,14 @@ onDestroy(() => {
|
||||||
}) // <- end onDestroy
|
}) // <- end onDestroy
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<canvas bind:this={canvas}></canvas>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
205
src/lib/components/WorkCanvas.svelte
Normal file
205
src/lib/components/WorkCanvas.svelte
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as PIXI from 'pixi.js';
|
||||||
|
import { RGBSplitFilter, BulgePinchFilter } from 'pixi-filters';
|
||||||
|
import gsap from 'gsap';
|
||||||
|
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
|
||||||
|
import SplitText from 'gsap/dist/SplitText';
|
||||||
|
import { PixiPlugin } from "gsap/dist/PixiPlugin";
|
||||||
|
import { onMount, onDestroy } from 'svelte';
|
||||||
|
import { browser } from '$app/environment';
|
||||||
|
import createCanvasText from '$lib/utils/createCanvasText';
|
||||||
|
import createCanvasImg from '$lib/utils/createCanvasImg';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
export let textsToCanvas: Array<HTMLElement> = [];
|
||||||
|
export let imgsToCanvas: Array<HTMLElement> = [];
|
||||||
|
export let bulgeFactor: number = 0.15;
|
||||||
|
let app: PIXI.Application;
|
||||||
|
let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
|
onMount(()=>{
|
||||||
|
|
||||||
|
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
|
||||||
|
|
||||||
|
app = new PIXI.Application({
|
||||||
|
resizeTo: window,
|
||||||
|
antialias: true,
|
||||||
|
autoDensity: true,
|
||||||
|
resolution: 2,
|
||||||
|
backgroundAlpha: 0,
|
||||||
|
view: canvas,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
//for debugging but Typescript has an issue with this:
|
||||||
|
// globalThis.__PIXI_APP__ = app as any;
|
||||||
|
|
||||||
|
PixiPlugin.registerPIXI(PIXI);
|
||||||
|
|
||||||
|
function xFrac(x: number){
|
||||||
|
return window.innerWidth * x;
|
||||||
|
}
|
||||||
|
function yFrac(y: number){
|
||||||
|
return window.innerHeight * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
let group = new PIXI.Container();
|
||||||
|
group.pivot.set(window.innerWidth / 2, window.innerHeight / 2);
|
||||||
|
group.x = window.innerWidth / 2;
|
||||||
|
group.y = window.innerHeight / 2;
|
||||||
|
app.stage.addChild(group);
|
||||||
|
|
||||||
|
let recty = new PIXI.Graphics();
|
||||||
|
recty.beginFill('rgb(0, 0, 0)');
|
||||||
|
recty.drawRect(0, 0, xFrac(1), yFrac(1));
|
||||||
|
recty.endFill();
|
||||||
|
recty.alpha = 0;
|
||||||
|
recty.pivot.set(xFrac(.5), yFrac(.5));
|
||||||
|
recty.x = xFrac(0.5);
|
||||||
|
recty.y = yFrac(0.5);
|
||||||
|
group.addChild(recty);
|
||||||
|
|
||||||
|
let center = [0.5, 0.5];
|
||||||
|
let bulgefilter = new BulgePinchFilter();
|
||||||
|
bulgefilter.radius = xFrac(0.6);
|
||||||
|
bulgefilter.strength = bulgeFactor;
|
||||||
|
bulgefilter.center = center;
|
||||||
|
bulgefilter.resolution = 2;
|
||||||
|
// app.stage.filters = [bulgefilter];
|
||||||
|
let rgbFilter = new RGBSplitFilter();
|
||||||
|
rgbFilter.red = [0, 0];
|
||||||
|
rgbFilter.green = [0, 0];
|
||||||
|
rgbFilter.blue = [0, 0];
|
||||||
|
rgbFilter.resolution = 2;
|
||||||
|
app.stage.filters = [bulgefilter];
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Convert text to canvas using
|
||||||
|
* createCanvasText function
|
||||||
|
----------------------------------*/
|
||||||
|
let canvasTexts: Array<PIXI.Text> = [];
|
||||||
|
let elems: Array<HTMLElement> = [];
|
||||||
|
|
||||||
|
async function convertText(){
|
||||||
|
await tick();
|
||||||
|
textsToCanvas.forEach((element) => {
|
||||||
|
elems.push(element);
|
||||||
|
let canvasText = createCanvasText(element, app.stage);
|
||||||
|
canvasTexts.push(canvasText);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Function to update text on canvas
|
||||||
|
* runs in the Ticker
|
||||||
|
----------------------------------*/
|
||||||
|
function updateText(){
|
||||||
|
canvasTexts.forEach((text, index) => {
|
||||||
|
let headlinePosition = elems[index].getBoundingClientRect();
|
||||||
|
text.position.set(headlinePosition.x, headlinePosition.y);
|
||||||
|
text.alpha = elems[index].style.opacity as unknown as number;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Convert images to canvas
|
||||||
|
* createCanvacImgs function
|
||||||
|
----------------------------------*/
|
||||||
|
let canvasImgs: Array<PIXI.Sprite> = [];
|
||||||
|
let imgElems: Array<HTMLElement> = [];
|
||||||
|
|
||||||
|
function convertImgs(){
|
||||||
|
imgsToCanvas.forEach((element) => {
|
||||||
|
imgElems.push(element);
|
||||||
|
let canvasImg = createCanvasImg(element, app.stage);
|
||||||
|
// canvasImg.tint = 0xff9494;
|
||||||
|
canvasImgs.push(canvasImg);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Function to update text on canvas
|
||||||
|
* runs in the Ticker
|
||||||
|
----------------------------------*/
|
||||||
|
function updateImgs(){
|
||||||
|
canvasImgs.forEach((image, index) => {
|
||||||
|
let imagePosition = imgElems[index].getBoundingClientRect();
|
||||||
|
image.position.set(imagePosition.x, imagePosition.y);
|
||||||
|
image.width = imagePosition.width;
|
||||||
|
image.height = imagePosition.height;
|
||||||
|
// image.alpha = imgElems[index].style.opacity as unknown as number;
|
||||||
|
image.alpha = window.getComputedStyle(imgElems[index]).opacity as unknown as number;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
convertImgs();
|
||||||
|
convertText();
|
||||||
|
}, 100);
|
||||||
|
// convertImgs();
|
||||||
|
// convertText();
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* Mousemove events
|
||||||
|
*----------------------------------*/
|
||||||
|
let tween = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
};
|
||||||
|
window.addEventListener('mousemove', (e) => {
|
||||||
|
const pointerX = e.clientX / window.innerWidth;
|
||||||
|
const pointerY = e.clientY / window.innerHeight;
|
||||||
|
const pointerXfrac = pointerX - 0.5;
|
||||||
|
const pointerYfrac = pointerY - 0.5;
|
||||||
|
rgbFilter.red = [pointerXfrac * 10, pointerYfrac * 10];
|
||||||
|
rgbFilter.green = [pointerXfrac * -10, pointerYfrac * -10];
|
||||||
|
|
||||||
|
gsap.to(tween, {
|
||||||
|
duration: .5,
|
||||||
|
ease: 'power3.out',
|
||||||
|
overwrite: true,
|
||||||
|
x: pointerX,
|
||||||
|
y: pointerY,
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------------
|
||||||
|
* The Ticker
|
||||||
|
* ----------------------------------*/
|
||||||
|
let elapsed = 0.0;
|
||||||
|
|
||||||
|
app.ticker.add((delta) => {
|
||||||
|
elapsed += delta;
|
||||||
|
// bulgefilter.center = center;
|
||||||
|
// bulgefilter.center = [(center[0] + Math.sin(elapsed/200)/20 ),(center[1] + Math.cos(elapsed/200)/20 )];
|
||||||
|
bulgefilter.center = [tween.x, tween.y];
|
||||||
|
bulgefilter.strength = bulgeFactor;
|
||||||
|
updateImgs();
|
||||||
|
updateText();
|
||||||
|
})
|
||||||
|
}) // <- end onMount
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (browser){
|
||||||
|
app.destroy(true, true);
|
||||||
|
}
|
||||||
|
}) // <- end onDestroy
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<canvas bind:this={canvas}></canvas>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
canvas {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -4,6 +4,7 @@ type Post = {
|
||||||
date: string
|
date: string
|
||||||
description: string
|
description: string
|
||||||
tags: string[]
|
tags: string[]
|
||||||
|
header_bg_image: string
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
render: () => string
|
render: () => string
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,6 @@ body {
|
||||||
body * {
|
body * {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
canvas {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
h1, h2, h3, h4, h5 {
|
h1, h2, h3, h4, h5 {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
|
|
|
||||||
19
src/lib/utils/createCanvasImg.ts
Normal file
19
src/lib/utils/createCanvasImg.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import * as PIXI from 'pixi.js';
|
||||||
|
|
||||||
|
export default function createCanvasText( element: HTMLElement, stage: PIXI.Container ){
|
||||||
|
|
||||||
|
const elem = element;
|
||||||
|
// console.log(elem);
|
||||||
|
const elemSrc = elem.getAttribute('src') || '';
|
||||||
|
const elemPosition = elem.getBoundingClientRect();
|
||||||
|
|
||||||
|
const canvasImg = PIXI.Sprite.from(elemSrc);
|
||||||
|
canvasImg.position.set(elemPosition.x, elemPosition.y);
|
||||||
|
canvasImg.width = elemPosition.width;
|
||||||
|
canvasImg.height = elemPosition.height;
|
||||||
|
stage.addChild(canvasImg);
|
||||||
|
|
||||||
|
// elem.style.opacity = '0';
|
||||||
|
elem.style.visibility = 'hidden';
|
||||||
|
return canvasImg;
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,9 @@ export default function createCanvasText( element: HTMLElement, stage: PIXI.Con
|
||||||
const elem = element;
|
const elem = element;
|
||||||
const elemStyles = window.getComputedStyle(elem);
|
const elemStyles = window.getComputedStyle(elem);
|
||||||
const elemFontSize = elemStyles.getPropertyValue('font-size');
|
const elemFontSize = elemStyles.getPropertyValue('font-size');
|
||||||
|
const elemFontWeight = elemStyles.getPropertyValue('font-weight');
|
||||||
const elemFontFamily = elemStyles.getPropertyValue('font-family');
|
const elemFontFamily = elemStyles.getPropertyValue('font-family');
|
||||||
|
const elemFontStyle = elemStyles.getPropertyValue('font-style');
|
||||||
const elemLetterSpacing = parseInt(elemStyles.getPropertyValue('letter-spacing'));
|
const elemLetterSpacing = parseInt(elemStyles.getPropertyValue('letter-spacing'));
|
||||||
const elemColor = elemStyles.getPropertyValue('color');
|
const elemColor = elemStyles.getPropertyValue('color');
|
||||||
const elemAlignment = elemStyles.getPropertyValue('text-align');
|
const elemAlignment = elemStyles.getPropertyValue('text-align');
|
||||||
|
|
@ -15,11 +17,14 @@ export default function createCanvasText( element: HTMLElement, stage: PIXI.Con
|
||||||
const canvasText = new Text(elem?.textContent as string, {
|
const canvasText = new Text(elem?.textContent as string, {
|
||||||
fontFamily: elemFontFamily,
|
fontFamily: elemFontFamily,
|
||||||
fontSize: elemFontSize,
|
fontSize: elemFontSize,
|
||||||
|
fontWeight: elemFontWeight as PIXI.TextStyleFontWeight,
|
||||||
|
fontStyle: elemFontStyle as PIXI.TextStyleFontStyle,
|
||||||
letterSpacing: elemLetterSpacing,
|
letterSpacing: elemLetterSpacing,
|
||||||
fill: elemColor,
|
fill: elemColor,
|
||||||
align: elemAlignment as PIXI.TextStyleAlign,
|
align: elemAlignment as PIXI.TextStyleAlign,
|
||||||
});
|
});
|
||||||
canvasText.position.set(elemPosition.x, elemPosition.y);
|
canvasText.position.set(elemPosition.x, elemPosition.y);
|
||||||
|
// canvasText.zIndex = 100;
|
||||||
stage.addChild(canvasText);
|
stage.addChild(canvasText);
|
||||||
|
|
||||||
elem.style.opacity = '0';
|
elem.style.opacity = '0';
|
||||||
|
|
@ -6,30 +6,33 @@
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
let navlinks = document.querySelectorAll('nav a');
|
let navlinks = document.querySelectorAll('nav a');
|
||||||
|
|
||||||
navlinks.forEach((link, index) => {
|
navlinks.forEach((link, index) => {
|
||||||
link.addEventListener('click', (e)=> {
|
link.addEventListener('click', (e)=> {
|
||||||
const checkbox = document.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
const checkbox = document.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||||
checkbox ? checkbox.checked = false : null;
|
checkbox ? checkbox.checked = false : null;
|
||||||
gsap.to('.content', {duration: 0.5, y: '0%', autoAlpha: 1, ease: 'power4.out'});
|
gsap.to('.content > *', {duration: 0.5, y: '0%', autoAlpha: 1, ease: 'power4.out'});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let checkbox = document.getElementById('menustate') as HTMLInputElement;
|
let checkbox = document.getElementById('menustate') as HTMLInputElement;
|
||||||
|
|
||||||
checkbox.addEventListener('change', (e)=> {
|
checkbox.addEventListener('change', (e)=> {
|
||||||
if (checkbox.checked) {
|
if (checkbox.checked) {
|
||||||
gsap.to('.content', {duration: 0.75, y: -200, autoAlpha: 0.5, ease: 'power2.inOut'});
|
gsap.to('.content > *', {duration: 0.75, y: -200, autoAlpha: 0.5, ease: 'power2.inOut'});
|
||||||
gsap.from('#nav', {duration: 0.5, autoAlpha: 0, y: '100%', ease: 'power4.out', delay: 0.1});
|
gsap.from('#nav', {duration: 0.5, autoAlpha: 0, y: '100%', ease: 'power4.out', delay: 0.1});
|
||||||
gsap.from('nav a', {duration: 0.5, autoAlpha: 0, y: 20, stagger: 0.1, ease: 'power4.out' , delay: 0.2});
|
gsap.from('nav a', {duration: 0.5, autoAlpha: 0, y: 20, stagger: 0.1, ease: 'power4.out' , delay: 0.2});
|
||||||
} else {
|
} else {
|
||||||
gsap.to('.content', {duration: 0.5, y: '0%', autoAlpha: 1, ease: 'power4.out'});
|
gsap.to('.content > *', {duration: 0.5, y: '0%', autoAlpha: 1, ease: 'power4.out'});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<a href='/' class="logo">
|
<a href='/' class="logo">
|
||||||
<Logo />
|
<Logo />
|
||||||
</a>
|
</a>
|
||||||
<header>
|
<header>
|
||||||
<input aria-hidden="true" type="checkbox" id="menustate" />
|
<input aria-hidden="true" type="checkbox" id="menustate" />
|
||||||
<label for="menustate" aria-hidden="true">
|
<label for="menustate" aria-hidden="true">
|
||||||
<span class="open">≡</span>
|
<span class="open">≡</span>
|
||||||
|
|
@ -41,7 +44,7 @@
|
||||||
<a href="/work">About</a>
|
<a href="/work">About</a>
|
||||||
<a href="/work">Hire</a>
|
<a href="/work">Hire</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
<slot />
|
||||||
|
|
@ -52,13 +55,24 @@
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1;
|
z-index: 3;
|
||||||
padding: var(--spacing-outer);
|
padding: var(--spacing-outer);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: .75em;
|
gap: .75em;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
// width: 100%;
|
||||||
|
|
||||||
|
// &:before {
|
||||||
|
// content: '';
|
||||||
|
// position: absolute;
|
||||||
|
// bottom: 0;
|
||||||
|
// left: 0;
|
||||||
|
// width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
// background: linear-gradient(0deg, #00117fFF 0%, #00117fFF 30%, #00117f00 100%);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
height: 36px;
|
height: 36px;
|
||||||
|
|
@ -95,7 +109,7 @@
|
||||||
width: auto;
|
width: auto;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 2;
|
z-index: 4;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: var(--spacing-outer);
|
margin: var(--spacing-outer);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@
|
||||||
import SplitText from 'gsap/dist/SplitText';
|
import SplitText from 'gsap/dist/SplitText';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let canvasElems: NodeListOf<Element>;
|
let canvasElems: Array<HTMLElement>;
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
console.log('Home mounted');
|
|
||||||
|
|
||||||
gsap.registerPlugin( ScrollTrigger, SplitText );
|
gsap.registerPlugin( ScrollTrigger, SplitText );
|
||||||
|
|
||||||
|
|
@ -51,7 +50,7 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
canvasElems = document.querySelectorAll('.lineChildren') as NodeListOf<Element>;
|
canvasElems = Array.from(document.querySelectorAll('.lineChildren'));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -98,13 +97,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
{#await onMount}
|
|
||||||
waiting
|
|
||||||
{:then}
|
|
||||||
<HomeCanvas textsToCanvas={canvasElems}/>
|
<HomeCanvas textsToCanvas={canvasElems}/>
|
||||||
{:catch error}
|
|
||||||
<p>error</p>
|
|
||||||
{/await}
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
article {
|
article {
|
||||||
|
|
@ -142,11 +135,11 @@
|
||||||
h1 {
|
h1 {
|
||||||
letter-spacing: -0.05em;
|
letter-spacing: -0.05em;
|
||||||
line-height: .9;
|
line-height: .9;
|
||||||
font-size: 2.5em;
|
font-size: 17vw;
|
||||||
margin-top: -.5em;
|
margin-top: -.5em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
font-size: 2.7em;
|
font-size: 12vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,222 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import HomeCanvas from '$lib/components/HomeCanvas.svelte';
|
import WorkCanvas from '$lib/components/WorkCanvas.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import gsap from 'gsap';
|
import gsap from 'gsap';
|
||||||
|
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
|
||||||
|
import SplitText from 'gsap/dist/SplitText';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
let canvasElems: NodeListOf<Element>;
|
let canvasTextElems: Array<HTMLElement>;
|
||||||
onMount(() => {
|
let canvasImgElems: Array<HTMLElement>;
|
||||||
canvasElems = document.querySelectorAll('h1') as NodeListOf<Element>;
|
let bulge = { factor: 0.15 };
|
||||||
// console.log('Work mounted', canvasElems);
|
|
||||||
|
|
||||||
gsap.set(canvasElems, { autoAlpha: 0 });
|
onMount(() => {
|
||||||
gsap.to(canvasElems, {
|
|
||||||
|
gsap.registerPlugin( ScrollTrigger, SplitText );
|
||||||
|
|
||||||
|
let h1 = document.querySelector('h1') as HTMLElement;
|
||||||
|
let h1Text = h1?.innerHTML || '';
|
||||||
|
h1.innerHTML = h1Text + h1Text + h1Text + h1Text || '';
|
||||||
|
h1.style.overflow = 'hidden';
|
||||||
|
h1.style.whiteSpace = 'nowrap';
|
||||||
|
|
||||||
|
h1.querySelectorAll('span').forEach((span) => {
|
||||||
|
gsap.to(span, {xPercent: -100, duration: 4, ease: 'none', repeat: -1 })
|
||||||
|
});
|
||||||
|
|
||||||
|
const split = new SplitText('h1', { type: 'words', wordsClass: 'words' });
|
||||||
|
gsap.set(split.words, { opacity: 0 });
|
||||||
|
|
||||||
|
canvasTextElems = Array.from(document.querySelectorAll('.words'));
|
||||||
|
gsap.set(canvasTextElems, {
|
||||||
|
opacity: 0, yPercent: -10
|
||||||
|
})
|
||||||
|
gsap.to(canvasTextElems, {
|
||||||
duration: 1,
|
duration: 1,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
yPercent: 0,
|
||||||
stagger: 0.1,
|
stagger: 0.1,
|
||||||
ease: 'power4.out',
|
ease: 'power4.out',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvasImgElems = Array.from(document.querySelectorAll('.workhero'));
|
||||||
|
gsap.set(canvasImgElems, {
|
||||||
|
opacity: 0, yPercent: -10
|
||||||
|
})
|
||||||
|
gsap.to(canvasImgElems, {
|
||||||
|
duration: 1,
|
||||||
|
opacity: 1,
|
||||||
|
yPercent: 0,
|
||||||
|
stagger: 0.1,
|
||||||
|
ease: 'power4.out',
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
function workClickHandler(e:Event){
|
||||||
|
e.preventDefault();
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
const originalLink = target.getAttribute('href') as string;
|
||||||
|
const targetImg = target.querySelector('.workhero') as HTMLElement;
|
||||||
|
const targetImgRect = targetImg.getBoundingClientRect();
|
||||||
|
const targetImgAspectRatio = targetImgRect.width / targetImgRect.height;
|
||||||
|
target.classList.add('active');
|
||||||
|
targetImg.style.width = `${targetImgRect.width}px`;
|
||||||
|
targetImg.style.height = `${targetImgRect.height}px`;
|
||||||
|
targetImg.style.top = `${targetImgRect.top}px`;
|
||||||
|
targetImg.style.left = `${targetImgRect.left}px`;
|
||||||
|
targetImg.style.position = 'fixed';
|
||||||
|
|
||||||
|
gsap.to('.work:not(.active) .workhero', {
|
||||||
|
duration: .3,
|
||||||
|
opacity: 0,
|
||||||
|
yPercent: 10,
|
||||||
|
stagger: 0.1,
|
||||||
|
ease: 'power4.out',
|
||||||
|
})
|
||||||
|
gsap.set(targetImg, {
|
||||||
|
zIndex: 100,
|
||||||
|
})
|
||||||
|
gsap.to(targetImg, {
|
||||||
|
duration: .6,
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerWidth / targetImgAspectRatio,
|
||||||
|
ease: 'circ.inOut',
|
||||||
|
delay: .3,
|
||||||
|
})
|
||||||
|
gsap.to(bulge, {
|
||||||
|
duration: .3,
|
||||||
|
factor: 0,
|
||||||
|
ease: 'circ.inOut',
|
||||||
|
onUpdate: () => {
|
||||||
|
bulge.factor = bulge.factor;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
gsap.to('h1', {
|
||||||
|
duration: .3,
|
||||||
|
yPercent: -200,
|
||||||
|
ease: 'circ.inOut',
|
||||||
|
})
|
||||||
|
|
||||||
|
// after a timeout of 1000ms (1s), navigate to the original link
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = originalLink;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="work">
|
<h1><span>Casestudies</span></h1>
|
||||||
<h1>My work examples:</h1>
|
<div class="works">
|
||||||
|
|
||||||
{#each data.posts as work}
|
{#each data.posts as work}
|
||||||
|
<a href="{work.path}" class="work" on:click={ workClickHandler }>
|
||||||
|
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
|
||||||
<h2>{work.meta.title}</h2>
|
<h2>{work.meta.title}</h2>
|
||||||
<a href="{work.path}">Link to work</a>
|
</a>
|
||||||
|
|
||||||
|
{/each}
|
||||||
|
{#each data.posts as work}
|
||||||
|
<a href="{work.path}" class="work" on:click={ workClickHandler }>
|
||||||
|
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
|
||||||
|
<h2>{work.meta.title}</h2>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/each}
|
||||||
|
{#each data.posts as work}
|
||||||
|
<a href="{work.path}" class="work" on:click={ workClickHandler }>
|
||||||
|
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
|
||||||
|
<h2>{work.meta.title}</h2>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{/each}
|
||||||
|
{#each data.posts as work}
|
||||||
|
<a href="{work.path}" class="work" on:click={ workClickHandler }>
|
||||||
|
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
|
||||||
|
<h2>{work.meta.title}</h2>
|
||||||
|
</a>
|
||||||
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{#await onMount}
|
<WorkCanvas textsToCanvas={canvasTextElems} imgsToCanvas={canvasImgElems} bulgeFactor={bulge.factor} />
|
||||||
waiting
|
|
||||||
{:then}
|
|
||||||
<HomeCanvas textsToCanvas={canvasElems}/>
|
|
||||||
{:catch error}
|
|
||||||
<p>error</p>
|
|
||||||
{/await}
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
h1, h2 {
|
h1 {
|
||||||
|
font-size: 12vw;
|
||||||
|
font-style: italic;
|
||||||
|
margin: 0.5em 0 0.5em 0;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
text-align: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
visibility: hidden;
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
font-size: 7vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
& span {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
letter-spacing: -0.025em;
|
letter-spacing: -0.025em;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
font-size: 2vw;
|
||||||
|
// visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
position: absolute;
|
||||||
position: relative;
|
right: 0%;
|
||||||
|
top: 0%;
|
||||||
|
transform: scale(0.8);
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.1em 0.4em 0.2em 0.4em;
|
||||||
|
border-radius: .25em;
|
||||||
|
color: var(--color-bg);
|
||||||
|
text-align: center;
|
||||||
|
transform-origin: center center;
|
||||||
|
width: auto;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--color-text);
|
||||||
|
transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
|
||||||
|
.works .work:hover & {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
h1 {
|
}
|
||||||
letter-spacing: -0.05em;
|
.works {
|
||||||
line-height: .9;
|
padding: 24vw 0.5em 0.5em 0.5em;
|
||||||
font-size: 2.5em;
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
font-size: 5.7em;
|
padding: 14vw 0.5em 0.5em 0.5em;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25em;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 20svh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.work {
|
.work {
|
||||||
padding: var(--spacing-outer);
|
flex: 0 0 calc(33% - .125em);
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
text-decoration: none;
|
||||||
|
overflow: hidden;
|
||||||
|
// visibility: hidden;
|
||||||
|
}
|
||||||
|
.workhero {
|
||||||
|
width: 100%;
|
||||||
|
// aspect-ratio: 4/3;
|
||||||
|
object-fit: cover;
|
||||||
|
visibility: hidden;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
export async function load({ params }){
|
export async function load({ params }){
|
||||||
try {
|
try {
|
||||||
const post = await import(`../${params.slug}.md`)
|
const post = await import(`../${params.slug}.md`)
|
||||||
const { title, date } = post.metadata
|
const { title, date, header_bg_image } = post.metadata
|
||||||
const Content = post.default.render()
|
const Content = post.default.render()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
date,
|
date,
|
||||||
|
header_bg_image,
|
||||||
Content
|
Content
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,45 @@
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { onMount, onDestroy } from 'svelte';
|
||||||
|
import { fly } from 'svelte/transition';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
|
let visible = false;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
let workheros = document.querySelector('.hero');
|
||||||
|
console.log(workheros);
|
||||||
|
visible = true;
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<article>
|
<article>
|
||||||
<h1>{data.title}</h1>
|
<img class="hero" src="{data.header_bg_image}" alt="{data.title}" />
|
||||||
<p>{@html data.Content.html}</p>
|
{#if visible}
|
||||||
|
<h1 in:fly>{data.title}</h1>
|
||||||
|
<p in:fly>{@html data.Content.html}</p>
|
||||||
|
{/if}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
article {
|
article {
|
||||||
padding: var(--spacing-outer);
|
padding: var(--spacing-outer);
|
||||||
}
|
}
|
||||||
|
.hero {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left:0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
height: auto;
|
||||||
|
// object-fit: cover;
|
||||||
|
}
|
||||||
|
h1, p {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
@media (max-width: 767px){
|
||||||
|
h1 {
|
||||||
|
margin-top: calc(100vw / 1.333);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
---
|
---
|
||||||
title: Adidas
|
title: Adidas
|
||||||
category: Visual Design
|
header_bg_image: /work/adidas/adidas_hero.jpg
|
||||||
permalink: /work/adidas
|
|
||||||
header_bg_image: ./img/work_adidas/adidas_hero_bw.jpg
|
|
||||||
extra_classes: portfolio theme-adidas
|
|
||||||
order: 12
|
order: 12
|
||||||
|
description: Adidas, as you might have heard, is an international sports and lifestyle clothing brand. I worked on several digital campaigns as a graphic designer and illustrator.
|
||||||
svg: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 1440 900" viewBox="0 0 1440 900">
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 1440 900" viewBox="0 0 1440 900">
|
||||||
<path d="M1440 900v-.5l-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.2-8.3.4-11.9H707.9l-.1.6 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.2 8.3-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.5 14.2 14.2 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.3 14.1 8.2V900z" style="fill:#ffb7ab"/>
|
<path d="M1440 900v-.5l-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.2-8.3.4-11.9H707.9l-.1.6 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.2 8.3-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.5 14.2 14.2 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.3 14.1 8.2V900z" style="fill:#ffb7ab"/>
|
||||||
</svg>'
|
</svg>'
|
||||||
|
|
|
||||||
21
src/routes/work/formo.md
Normal file
21
src/routes/work/formo.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: Formo.bio
|
||||||
|
header_bg_image: /work/formo/formo_hero.png
|
||||||
|
order: 12
|
||||||
|
description: Formo, as you might have heard, is an international sports and lifestyle clothing brand. I worked on several digital campaigns as a graphic designer and illustrator.
|
||||||
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 1440 900" viewBox="0 0 1440 900">
|
||||||
|
<path d="M1440 900v-.5l-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.2-8.3.4-11.9H707.9l-.1.6 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.2 8.3-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.5 14.2 14.2 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.3 14.1 8.2V900z" style="fill:#ffb7ab"/>
|
||||||
|
</svg>'
|
||||||
|
---
|
||||||
|
<div class="infobox">
|
||||||
|
<p>Client: <a href="https://www.adidas-group.com/en/">Adidas E-commerce dept</a></p>
|
||||||
|
Tasks:
|
||||||
|
<ul>
|
||||||
|
<li>Visual Design</li>
|
||||||
|
<li>Campaign asset production</li>
|
||||||
|
<li>Illustration</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><span class="drop_cap">A</span>didas, as you might have heard, is an international sports and lifestyle clothing brand. I worked on several digital campaigns as a graphic designer and illustrator.</p>
|
||||||
|
</div>
|
||||||
21
src/routes/work/jpl.md
Normal file
21
src/routes/work/jpl.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: JustPeace Labs
|
||||||
|
header_bg_image: /work/jpl/jpl_hero.jpg
|
||||||
|
description: JustPeace Labs is a non-profit organization that works with local communities to build peace and prevent violence.
|
||||||
|
order: 11
|
||||||
|
svg: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 1440 900" viewBox="0 0 1440 900">
|
||||||
|
<path d="M1440 900v-.5l-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.2-8.3.4-11.9H707.9l-.1.6 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.2 8.3-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.5 14.2 14.2 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.3 14.1 8.2V900z" style="fill:#ffb7ab"/>
|
||||||
|
</svg>'
|
||||||
|
---
|
||||||
|
<div class="infobox">
|
||||||
|
<p>Client: <a href="https://www.adidas-group.com/en/">Adidas E-commerce dept</a></p>
|
||||||
|
Tasks:
|
||||||
|
<ul>
|
||||||
|
<li>Visual Design</li>
|
||||||
|
<li>Campaign asset production</li>
|
||||||
|
<li>Illustration</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p><span class="drop_cap">A</span>didas, as you might have heard, is an international sports and lifestyle clothing brand. I worked on several digital campaigns as a graphic designer and illustrator.</p>
|
||||||
|
</div>
|
||||||
BIN
static/work/adidas/adidas_hero.jpg
Normal file
BIN
static/work/adidas/adidas_hero.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
BIN
static/work/formo/formo_hero.png
Normal file
BIN
static/work/formo/formo_hero.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 MiB |
BIN
static/work/jpl/jpl_hero.jpg
Normal file
BIN
static/work/jpl/jpl_hero.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
|
|
@ -1,6 +1,7 @@
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit()]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue