it's blue now

This commit is contained in:
saiminh 2023-10-01 12:31:51 +02:00
parent c559947292
commit dd0d6c25a2
43 changed files with 3615 additions and 356 deletions

View file

@ -26,5 +26,9 @@ module.exports = {
parser: '@typescript-eslint/parser' parser: '@typescript-eslint/parser'
} }
} }
] ],
rules: {
"no-await-in-loop": "error",
"no-promise-executor-return": "error",
}
}; };

View file

@ -0,0 +1,132 @@
<script lang="ts">
import { onMount } from "svelte";
import gsap from "gsap";
export let summary: string;
let details: HTMLElement;
let contentHeight: number;
let summaryHeight: number;
onMount( () => {
contentHeight = (details?.querySelector('.faq-content') as HTMLElement).offsetHeight;
summaryHeight = (details?.querySelector('summary') as HTMLElement).offsetHeight;
details.style.setProperty('--height', `${summaryHeight}px`);
details.style.height = `var(--height)`;
function resizeHandler() {
contentHeight = (details?.querySelector('.faq-content') as HTMLElement).offsetHeight;
summaryHeight = (details?.querySelector('summary') as HTMLElement).offsetHeight;
if ( details?.hasAttribute('open') ) {
details.style.setProperty('--height', `${contentHeight + summaryHeight}px`);
details.style.height = `var(--height)`;
} else {
details.style.setProperty('--height', `${summaryHeight}px`);
details.style.height = `var(--height)`;
}
}
window.addEventListener('resize', resizeHandler );
return () => {
window.removeEventListener('resize', resizeHandler );
}
})
function summaryClickHandler(e: Event){
e.preventDefault();
if ( details.hasAttribute('open') ) {
gsap.to( details, {
'--height': summaryHeight, duration: .4, ease: 'power4.out', overwrite: true,
onComplete: () => {
details.toggleAttribute('open')
}
})
} else {
details.toggleAttribute('open');
contentHeight = (details?.querySelector('.faq-content') as HTMLElement).offsetHeight;
let fullHeight = contentHeight + summaryHeight;
gsap.to( details, {
'--height': fullHeight, duration: .5, ease: 'back.out(1)', overwrite: true
})
gsap.fromTo( details.querySelector('.faq-content'), {
opacity: 0, x: -60
}, {
opacity: 1, x: 0, duration: .5, ease: 'power3.out', overwrite: true
})
}
}
</script>
<details bind:this={details}>
<!-- svelte-ignore a11y-no-static-element-interactions -->
<summary on:click={summaryClickHandler} on:keyup={summaryClickHandler}>{summary}</summary>
<div class="faq-content">
<slot />
</div>
</details>
<style lang="scss">
details {
--height: 0;
overflow: hidden;
padding: 0;
margin-bottom: 0;
transition: margin-bottom .3s ease-out;
}
details[open] {
margin-bottom: 1em;
}
summary {
display: block;
cursor: url('/pointer.svg'), auto;
position: relative;
z-index: 2;
line-height: 1.2;
font-size: 1em;
padding: 0.5em 0 0.5em 1.5em;
&:before, &:after {
content: '';
position: absolute;
left: 0;
top: 1em;
width: 17px;
height: 2px;
background-color: var(--color-text);
transform-origin: center;
transition: transform .2s ease-in-out;
}
&:before {
transform: rotate(90deg);
}
}
details[open] summary {
&::before {
transform: rotate(0deg);
}
}
.faq-content {
border-left: 1px solid;
margin-left: 8px;
padding: 1em 0 0 calc(1.5em - 8px);
position: relative;
z-index: 1;
font-size: 1em;
box-sizing: border-box;
}
:global(.faq-content p, .faq-content li){
font-size: 1em!important;
}
:global(.faq-content li){
margin-left: 2em;
}
:global(.faq-content > :first-child){
margin-top: 0;
}
:global(.faq-content > :last-child){
margin-bottom: 0;
}
</style>

View file

@ -20,17 +20,6 @@
display: block; display: block;
margin: var(--spacing-nav); margin: var(--spacing-nav);
cursor: url('/pointer.svg'), auto; cursor: url('/pointer.svg'), auto;
} text-decoration: none;
.header-nav {
@media screen and (max-width: 767px) {
background-color: var(--color-bg);
width: 100%;
height: calc(36px + 2 * var(--spacing-nav));
position: fixed;
bottom: 0;
left: 0;
z-index: 3;
// border-top: 1px solid var(--color-text);
}
} }
</style> </style>

View file

@ -16,16 +16,24 @@ export let imgsToCanvas: Array<HTMLElement> = [];
let app: PIXI.Application; let app: PIXI.Application;
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
onMount(()=>{ onMount(()=>{
function xFrac(x: number){
return window.innerWidth * x;
}
function yFrac(y: number){
return window.innerHeight * y;
}
let is_fine = window.matchMedia('(pointer:fine)').matches let is_fine = window.matchMedia('(pointer:fine)').matches
let is_coarse = window.matchMedia('(pointer:coarse)').matches let is_coarse = window.matchMedia('(pointer:coarse)').matches
let is_landscape = window.matchMedia('(orientation:landscape)').matches
let is_portrait = window.matchMedia('(orientation:portrait)').matches
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText); gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
app = new PIXI.Application({ app = new PIXI.Application({
resizeTo: window, resizeTo: document.querySelector('.canvasResizeToThis') as HTMLElement,
antialias: true, antialias: true,
autoDensity: true, autoDensity: true,
resolution: 2, resolution: 2,
@ -34,69 +42,49 @@ onMount(()=>{
}); });
//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 as any).__PIXI_APP__ = app;
PixiPlugin.registerPIXI(PIXI); PixiPlugin.registerPIXI(PIXI);
function xFrac(x: number){
return window.innerWidth * x;
}
function yFrac(y: number){
return window.innerHeight * y;
}
let group = new PIXI.Container(); let bulgegroup = new PIXI.Container();
group.pivot.set(window.innerWidth / 2, window.innerHeight / 2); bulgegroup.pivot.set(xFrac(0.5), yFrac(0.5));
group.x = window.innerWidth / 2; bulgegroup.x = xFrac(0.5);
group.y = window.innerHeight / 2; bulgegroup.y = yFrac(0.5);
app.stage.addChild(group); app.stage.addChild(bulgegroup);
let recty = new PIXI.Graphics(); let bulgebg = new PIXI.Graphics();
recty.beginFill('rgb(0, 0, 0)'); bulgebg.beginFill('rgb(0, 0, 0)');
recty.drawRect(0, 0, xFrac(1), yFrac(1)); bulgebg.drawRect(0, 0, xFrac(1.2), yFrac(1.2));
recty.endFill(); bulgebg.endFill();
recty.alpha = 0; bulgebg.alpha = 0;
recty.pivot.set(xFrac(.5), yFrac(.5)); bulgebg.pivot.set(xFrac(.5), yFrac(.5));
recty.x = xFrac(0.5); bulgebg.x = xFrac(0.5);
recty.y = yFrac(0.5); bulgebg.y = yFrac(0.5);
group.addChild(recty); bulgegroup.addChild(bulgebg);
let center = [0.5, 0.5]; let center = [0.5, 0.5];
let bulgefilter = new BulgePinchFilter(); let bulgefilter = new BulgePinchFilter();
bulgefilter.radius = xFrac(0.45); bulgefilter.radius = xFrac(0.5);
bulgefilter.strength = 0; bulgefilter.strength = is_fine ? 0.5 : 0.4;
bulgefilter.center = center; bulgefilter.center = center;
bulgefilter.resolution = 2; bulgefilter.resolution = 2;
app.stage.filters = [bulgefilter];
bulgegroup.filters = [bulgefilter];
let opening_animation_running = false;
gsap.to(bulgefilter, { let introTl = gsap.timeline();
introTl.to(bulgefilter, {
strength: 0.75,
duration: .75,
ease: 'power4.out',
}, 1.5)
introTl.to(bulgefilter, {
strength: is_fine ? 0.5 : 0.4, strength: is_fine ? 0.5 : 0.4,
duration: 1.5, duration: 1.25,
delay: 1, ease: 'elastic.out(1.5, .2)',
ease: 'elastic.out(1.75, 0.3)',
});
window.addEventListener( is_fine ? 'mousedown' : 'touchstart', (e)=>{
let target = e.target as HTMLElement;
if (target.tagName === 'H1' || target.tagName === 'H2' || target.tagName === 'P'){
gsap.to(bulgefilter, {
strength: 0,
duration: 1,
ease: 'elastic.out',
});
}
}) })
window.addEventListener( is_fine ? 'mouseup' : 'touchend', (e)=>{
let target = e.target as HTMLElement;
if (target.tagName === 'H1' || target.tagName === 'H2' || target.tagName === 'P'){
gsap.to(bulgefilter, {
strength: 0.5,
duration: 2,
ease: 'elastic.out',
});
}
})
/*---------------------------------- /*----------------------------------
* Convert text to canvas using * Convert text to canvas using
* createCanvasText function * createCanvasText function
@ -108,12 +96,11 @@ onMount(()=>{
await tick(); await tick();
textsToCanvas.forEach((element) => { textsToCanvas.forEach((element) => {
elems.push(element); elems.push(element);
let canvasText = createCanvasText(element, app.stage); let canvasText = createCanvasText(element, bulgegroup);
canvasTexts.push(canvasText); canvasTexts.push(canvasText);
}) })
} }
/*---------------------------------- /*----------------------------------
* Function to update text on canvas * Function to update text on canvas
* runs in the Ticker * runs in the Ticker
@ -121,8 +108,11 @@ onMount(()=>{
function updateText(){ function updateText(){
canvasTexts.forEach((text, index) => { canvasTexts.forEach((text, index) => {
let headlinePosition = elems[index].getBoundingClientRect(); let headlinePosition = elems[index].getBoundingClientRect();
headlinePosition.x = headlinePosition.x + xFrac(0.1);
headlinePosition.y = headlinePosition.y + yFrac(0.1);
text.position.set(headlinePosition.x, headlinePosition.y); text.position.set(headlinePosition.x, headlinePosition.y);
text.alpha = elems[index].style.opacity as unknown as number; text.alpha = elems[index].style.opacity as unknown as number;
text.style.fill = window.getComputedStyle(elems[index]).color;
}) })
} }
@ -145,8 +135,6 @@ onMount(()=>{
convertImgs(); convertImgs();
convertText(); convertText();
}, 100); }, 100);
// convertImgs();
// convertText();
/*---------------------------------- /*----------------------------------
* Function to update text on canvas * Function to update text on canvas
@ -155,6 +143,8 @@ onMount(()=>{
function updateImgs(){ function updateImgs(){
canvasImgs.forEach((image, index) => { canvasImgs.forEach((image, index) => {
let imagePosition = imgElems[index].getBoundingClientRect(); let imagePosition = imgElems[index].getBoundingClientRect();
imagePosition.x = imagePosition.x + xFrac(0.1);
imagePosition.y = imagePosition.y + yFrac(0.1);
image.position.set(imagePosition.x, imagePosition.y); image.position.set(imagePosition.x, imagePosition.y);
image.width = imagePosition.width; image.width = imagePosition.width;
image.height = imagePosition.height; image.height = imagePosition.height;
@ -164,26 +154,37 @@ onMount(()=>{
/*---------------------------------- /*----------------------------------
* Mousemove events * Mousemove events
*----------------------------------*/ *----------------------------------*/
let tween = { let tween = {
x: 0.5, x: 0.5,
y: is_fine ? 0.5 : 250/window.innerHeight, y: is_fine ? 0.5 : 250/window.innerHeight,
}; };
const mouse = {
x: xFrac(0.5),
y: yFrac(0.5),
}
if (is_fine) { if (is_fine) {
window.addEventListener('mousemove', (e) => { window.addEventListener('mousemove', (e) => {
if (opening_animation_running) return;
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;
const pointerYfrac = pointerY - 0.5; const pointerYfrac = pointerY - 0.5;
// center = [(0.5 + pointerXfrac/10),(0.5 + pointerYfrac/10)]; gsap.to(mouse, {
duration: 0.5,
ease: 'power3.out',
overwrite: true,
x: e.clientX,
y: e.clientY,
})
gsap.to(tween, { gsap.to(tween, {
duration: .5, duration: .5,
ease: 'power3.out', ease: 'power3.out',
overwrite: true, overwrite: true,
x: 0.5 + pointerXfrac/10, x: 0.5 + pointerXfrac/2,
y: 0.5 + pointerYfrac/10, y: 0.5 + pointerYfrac/2,
}) })
}) })
@ -197,7 +198,11 @@ onMount(()=>{
app.ticker.add((delta) => { app.ticker.add((delta) => {
elapsed += delta; elapsed += delta;
bulgefilter.center = [(tween.x + Math.sin(elapsed/200)/20 ),(tween.y + Math.cos(elapsed/200)/20 )]; if (is_coarse) {
bulgefilter.center = [(tween.x + Math.sin(elapsed/200)/20 ),(tween.y + Math.cos(elapsed/200)/20 )];
} else {
bulgefilter.center = [tween.x, tween.y];
}
updateImgs(); updateImgs();
updateText(); updateText();
}) })
@ -205,6 +210,11 @@ onMount(()=>{
window.addEventListener('resize', (e) => { window.addEventListener('resize', (e) => {
tween.y = is_fine ? 0.5 : 250/window.innerHeight; tween.y = is_fine ? 0.5 : 250/window.innerHeight;
}) })
return () => {
gsap.killTweensOf(imgElems);
gsap.killTweensOf(elems);
ScrollTrigger.getAll().forEach( instance => instance.kill() );
}
}) // <- end onMount }) // <- end onMount
onDestroy(() => { onDestroy(() => {
@ -220,8 +230,10 @@ onDestroy(() => {
<style> <style>
canvas { canvas {
position: fixed; position: fixed;
top: 0; top: -10vh;
left: 0; left: -10vw;
width: 120vw;
height: 120vh;
z-index: -1; z-index: -1;
} }
</style> </style>

View file

@ -0,0 +1,254 @@
<script lang="ts">
import { onMount } from 'svelte';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';
onMount(() => {
gsap.registerPlugin(ScrollTrigger);
gsap.set('#fingers *', { transformOrigin: '100% 66%' });
let introIsPlaying = true;
const keyPress = (key: HTMLElement) => {
let tl = gsap.timeline({ delay: Math.random() * 3, repeat: 0, paused: true});
tl.to( key, { duration: .3, yPercent: 20, zIndex: -1, ease: 'power3.in'})
.to( key, { duration: .3, yPercent: 0, ease: 'power3.in', onComplete: () => {
keyPress(key);
tl.kill();
} })
tl.play();
}
const initKeys = () => {
document.querySelectorAll("#keys path").forEach( key => {
keyPress(key as HTMLElement);
})
}
const fingerMove = (finger: HTMLElement) => {
gsap.to( finger, { duration: .2, rotateZ: Math.random() * 10 + 5, ease: 'power3.in', delay: Math.random(), repeat: -1, yoyo: true })
}
const moveHandToRandom = () => {
if (introIsPlaying) {
return
} else {
gsap.to( '#hand', {
duration: .6,
xPercent: Math.random() * -80,
yPercent: Math.random() * -20,
rotateZ: Math.random() * 20 - 10,
ease: 'power3.in',
onComplete: () => moveHandToRandom()
})
}
}
const initHand = () => {
document.querySelectorAll("#fingers *").forEach( finger => {
fingerMove(finger as HTMLElement);
})
moveHandToRandom();
}
let introTl = gsap.timeline( {
scrollTrigger: { trigger: '#hank', start: 'top 50%', end: 'top top' }
});
introTl.set('#hand', {
yPercent: -100,
rotateZ: 40,
autoAlpha: 0,
})
introTl.set('#keys path', {
y: 1000,
autoAlpha: 0,
})
introTl.to('#keys path', {
duration: .66,
y: 0,
autoAlpha: 1,
stagger: {
each: .0025,
from: 'random'
},
ease: 'power3.out',
onComplete: () => initKeys()
}, 0);
introTl.to('#hand', {
yPercent: 0,
rotateZ: 0,
autoAlpha: 1,
duration: 1,
ease: 'power4.inOut',
onComplete: () => {
introIsPlaying = false;
initHand();
}
}, 0);
return () => {
gsap.killTweensOf("#hand, #keys path, #fingers *");
introTl.kill();
ScrollTrigger.getAll().forEach( instance => instance.kill() );
introIsPlaying = true;
}
})
</script>
<svg id="hank" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 2000 1000" width="2000" height="1000">
<g id="keyboard">
<polygon id="back" class="st0" points="1986.2,933.8 21.4,933.8 198,468.4 1768.8,468.4 "/>
<g id="keys">
<path class="st1" d="M278.5,534.6c-0.5,1.6-2.8,3-5.1,3h-50.2c-2.3,0-3.7-1.3-3.1-3l12.5-35.1c0.6-1.6,2.8-2.8,5.1-2.8h49.1 c2.2,0,3.6,1.3,3.1,2.8L278.5,534.6z"/>
<path class="st1" d="M257.4,599.7c-0.6,1.7-2.9,3.2-5.3,3.2h-51.9c-2.4,0-3.8-1.4-3.2-3.2l13.3-37.5c0.6-1.7,3-3,5.3-3h50.7 c2.3,0,3.7,1.4,3.2,3L257.4,599.7z"/>
<path class="st1" d="M327.8,599.7c-0.5,1.7-2.8,3.2-5.2,3.2h-51.9c-2.4,0-3.8-1.4-3.3-3.2l12-37.5c0.5-1.7,2.8-3,5.1-3h50.7 c2.3,0,3.8,1.4,3.3,3L327.8,599.7z"/>
<path class="st1" d="M398.2,599.7c-0.4,1.7-2.7,3.2-5.1,3.2h-51.9c-2.4,0-3.9-1.4-3.4-3.2l10.7-37.5c0.5-1.7,2.7-3,5-3h50.7 c2.3,0,3.8,1.4,3.4,3L398.2,599.7z"/>
<path class="st1" d="M468.7,599.7c-0.4,1.7-2.6,3.2-5,3.2h-51.9c-2.4,0-3.9-1.4-3.5-3.2l9.3-37.5c0.4-1.7,2.6-3,4.9-3h50.7 c2.3,0,3.9,1.4,3.5,3L468.7,599.7z"/>
<path class="st1" d="M539.1,599.7c-0.3,1.7-2.5,3.2-4.9,3.2h-51.9c-2.4,0-4-1.4-3.6-3.2l8-37.5c0.4-1.7,2.5-3,4.8-3h50.7 c2.3,0,3.9,1.4,3.6,3L539.1,599.7z"/>
<path class="st1" d="M609.5,599.7c-0.3,1.7-2.4,3.2-4.7,3.2h-51.9c-2.4,0-4-1.4-3.7-3.2l6.7-37.5c0.3-1.7,2.4-3,4.7-3h50.7 c2.3,0,4,1.4,3.7,3L609.5,599.7z"/>
<path class="st1" d="M680,599.7c-0.2,1.7-2.3,3.2-4.6,3.2h-51.9c-2.4,0-4.1-1.4-3.8-3.2l5.3-37.5c0.2-1.7,2.3-3,4.6-3h50.7 c2.3,0,4,1.4,3.8,3L680,599.7z"/>
<path class="st1" d="M750.4,599.7c-0.1,1.7-2.2,3.2-4.5,3.2H694c-2.4,0-4.1-1.4-3.9-3.2l4-37.5c0.2-1.7,2.2-3,4.5-3h50.7 c2.3,0,4.1,1.4,4,3L750.4,599.7z"/>
<path class="st1" d="M820.9,599.7c-0.1,1.7-2.1,3.2-4.4,3.2h-51.9c-2.4,0-4.2-1.4-4.1-3.2l2.7-37.5c0.1-1.7,2.1-3,4.4-3h50.7 c2.3,0,4.1,1.4,4.1,3L820.9,599.7z"/>
<path class="st1" d="M891.3,599.7c0,1.7-1.9,3.2-4.3,3.2h-51.9c-2.4,0-4.2-1.4-4.2-3.2l1.3-37.5c0.1-1.7,2-3,4.3-3h50.7 c2.3,0,4.2,1.4,4.2,3L891.3,599.7z"/>
<path class="st1" d="M961.7,599.7c0.1,1.7-1.8,3.2-4.2,3.2h-51.9c-2.4,0-4.3-1.4-4.3-3.2l0-37.5c0-1.7,1.9-3,4.2-3h50.7 c2.3,0,4.2,1.4,4.3,3L961.7,599.7z"/>
<path class="st1" d="M1032.2,599.7c0.1,1.7-1.7,3.2-4.1,3.2h-51.9c-2.4,0-4.3-1.4-4.4-3.2l-1.3-37.5c-0.1-1.7,1.8-3,4.1-3h50.7 c2.3,0,4.3,1.4,4.4,3L1032.2,599.7z"/>
<path class="st1" d="M1102.6,599.7c0.2,1.7-1.6,3.2-4,3.2h-51.9c-2.4,0-4.4-1.4-4.5-3.2l-2.7-37.5c-0.1-1.7,1.7-3,4-3h50.7 c2.3,0,4.3,1.4,4.5,3L1102.6,599.7z"/>
<path class="st1" d="M1234.8,599.7c0.3,1.7-1.4,3.2-3.7,3.2h-113.7c-2.4,0-4.4-1.4-4.6-3.2l-4-37.5c-0.2-1.7,1.6-3,3.9-3h111.2 c2.3,0,4.4,1.4,4.7,3L1234.8,599.7z"/>
<path class="st1" d="M268.3,655.1c-0.6,1.8-3,3.3-5.4,3.3h-82.3c-2.4,0-3.9-1.5-3.2-3.3l14.1-39.6c0.6-1.8,3.1-3.2,5.4-3.2h80.4 c2.4,0,3.8,1.4,3.3,3.2L268.3,655.1z"/>
<path class="st1" d="M269.4,713.4c-0.6,1.9-3.1,3.5-5.6,3.5H160c-2.5,0-4-1.6-3.3-3.5l14.9-41.9c0.7-1.9,3.2-3.4,5.6-3.4h101.4 c2.4,0,4,1.5,3.4,3.4L269.4,713.4z"/>
<path class="st1" d="M289.9,775.1c-0.6,2.1-3.2,3.7-5.7,3.7H138.1c-2.6,0-4.1-1.7-3.3-3.7l15.8-44.4c0.7-2,3.3-3.6,5.8-3.6H299 c2.5,0,4.1,1.6,3.5,3.6L289.9,775.1z"/>
<path class="st1" d="M214,839.5c-0.7,2.2-3.4,4-6,4h-92.7c-2.6,0-4.2-1.8-3.4-4l16.7-47c0.7-2.1,3.4-3.8,6-3.8h90.4 c2.6,0,4.1,1.7,3.5,3.8L214,839.5z"/>
<path class="st1" d="M342.8,655.1c-0.5,1.8-2.9,3.3-5.3,3.3h-53.3c-2.4,0-3.9-1.5-3.4-3.3l12.1-39.6c0.5-1.8,2.9-3.2,5.3-3.2h52.1 c2.4,0,3.9,1.4,3.4,3.2L342.8,655.1z"/>
<path class="st1" d="M345.2,713.4c-0.5,1.9-3,3.5-5.5,3.5h-54.8c-2.5,0-4.1-1.6-3.5-3.5l12.4-41.9c0.5-1.9,3-3.4,5.4-3.4h53.6 c2.4,0,4,1.5,3.5,3.4L345.2,713.4z"/>
<path class="st1" d="M422.1,713.4c-0.4,1.9-2.8,3.5-5.3,3.5H362c-2.5,0-4.1-1.6-3.6-3.5l10.8-41.9c0.5-1.9,2.9-3.4,5.3-3.4h53.6 c2.4,0,4.1,1.5,3.6,3.4L422.1,713.4z"/>
<path class="st1" d="M369.3,775.1c-0.5,2.1-3,3.7-5.6,3.7h-56.4c-2.6,0-4.2-1.7-3.6-3.7l12.3-44.4c0.5-2,3-3.6,5.5-3.6h55.1 c2.5,0,4.1,1.6,3.7,3.6L369.3,775.1z"/>
<path class="st1" d="M294.5,839.5c-0.6,2.2-3.2,4-5.9,4h-58.1c-2.6,0-4.3-1.8-3.6-4l14.3-47c0.6-2.1,3.3-3.8,5.8-3.8h56.7 c2.6,0,4.2,1.7,3.6,3.8L294.5,839.5z"/>
<path class="st1" d="M376.1,839.5c-0.5,2.2-3.1,4-5.7,4h-58.1c-2.6,0-4.3-1.8-3.7-4l12.5-47c0.6-2.1,3.1-3.8,5.7-3.8h56.7 c2.6,0,4.3,1.7,3.8,3.8L376.1,839.5z"/>
<path class="st1" d="M456.9,839.5c-0.4,2.2-3,4-5.6,4h-58.1c-2.6,0-4.4-1.8-3.9-4l10.8-47c0.5-2.1,3-3.8,5.5-3.8h56.7 c2.6,0,4.3,1.7,3.9,3.8L456.9,839.5z"/>
<path class="st1" d="M942.9,839.5c0,2.2-2.1,4-4.7,4H473.5c-2.6,0-4.4-1.8-4-4l9.1-47c0.4-2.1,2.8-3.8,5.4-3.8h453.2 c2.6,0,4.7,1.7,4.7,3.8L942.9,839.5z"/>
<path class="st1" d="M449.1,775.1c-0.4,2.1-2.9,3.7-5.4,3.7h-56.4c-2.6,0-4.2-1.7-3.8-3.7l10.6-44.4c0.5-2,2.9-3.6,5.4-3.6h55.1 c2.5,0,4.2,1.6,3.8,3.6L449.1,775.1z"/>
<path class="st1" d="M528.8,775.1c-0.4,2.1-2.7,3.7-5.3,3.7h-56.4c-2.6,0-4.3-1.7-3.9-3.7l9-44.4c0.4-2,2.8-3.6,5.3-3.6h55.1 c2.5,0,4.3,1.6,3.9,3.6L528.8,775.1z"/>
<path class="st1" d="M608.6,775.1c-0.3,2.1-2.6,3.7-5.2,3.7H547c-2.6,0-4.4-1.7-4-3.7l7.4-44.4c0.3-2,2.6-3.6,5.1-3.6h55.1 c2.5,0,4.3,1.6,4.1,3.6L608.6,775.1z"/>
<path class="st1" d="M688.3,775.1c-0.2,2.1-2.5,3.7-5,3.7h-56.4c-2.6,0-4.4-1.7-4.2-3.7l5.7-44.4c0.3-2,2.5-3.6,5-3.6h55.1 c2.5,0,4.4,1.6,4.2,3.6L688.3,775.1z"/>
<path class="st1" d="M768.1,775.1c-0.1,2.1-2.3,3.7-4.9,3.7h-56.4c-2.6,0-4.5-1.7-4.3-3.7l4.1-44.4c0.2-2,2.4-3.6,4.9-3.6h55.1 c2.5,0,4.4,1.6,4.3,3.6L768.1,775.1z"/>
<path class="st1" d="M847.8,775.1c-0.1,2.1-2.2,3.7-4.7,3.7h-56.4c-2.6,0-4.6-1.7-4.4-3.7l2.5-44.4c0.1-2,2.2-3.6,4.7-3.6h55.1 c2.5,0,4.5,1.6,4.5,3.6L847.8,775.1z"/>
<path class="st1" d="M927.6,775.1c0,2.1-2,3.7-4.6,3.7h-56.4c-2.6,0-4.6-1.7-4.6-3.7l0.8-44.4c0-2,2.1-3.6,4.6-3.6h55.1 c2.5,0,4.6,1.6,4.6,3.6L927.6,775.1z"/>
<path class="st1" d="M1007.3,775.1c0.1,2.1-1.9,3.7-4.5,3.7h-56.4c-2.6,0-4.7-1.7-4.7-3.7l-0.8-44.4c0-2,2-3.6,4.5-3.6h55.1 c2.5,0,4.6,1.6,4.7,3.6L1007.3,775.1z"/>
<path class="st1" d="M1028.2,839.5c0.1,2.2-1.9,4-4.6,4h-58.1c-2.6,0-4.8-1.8-4.9-4l-1.2-47c-0.1-2.1,2-3.8,4.6-3.8h56.7 c2.6,0,4.8,1.7,4.9,3.8L1028.2,839.5z"/>
<path class="st1" d="M1110.5,839.5c0.2,2.2-1.8,4-4.4,4h-58.1c-2.6,0-4.9-1.8-5-4l-3-47c-0.1-2.1,1.9-3.8,4.4-3.8h56.7 c2.6,0,4.8,1.7,5,3.8L1110.5,839.5z"/>
<path class="st1" d="M1192.7,839.5c0.3,2.2-1.6,4-4.3,4h-58.1c-2.6,0-5-1.8-5.2-4l-4.7-47c-0.2-2.1,1.7-3.8,4.3-3.8h56.7 c2.6,0,4.9,1.7,5.2,3.8L1192.7,839.5z"/>
<path class="st1" d="M1275,839.5c0.4,2.2-1.5,4-4.1,4h-58.1c-2.6,0-5-1.8-5.3-4l-6.5-47c-0.3-2.1,1.6-3.8,4.2-3.8h56.7 c2.6,0,5,1.7,5.3,3.8L1275,839.5z"/>
<path class="st1" d="M1087.1,775.1c0.2,2.1-1.8,3.7-4.3,3.7h-56.4c-2.6,0-4.7-1.7-4.9-3.7l-2.5-44.4c-0.1-2,1.8-3.6,4.3-3.6h55.1 c2.5,0,4.7,1.6,4.8,3.6L1087.1,775.1z"/>
<path class="st1" d="M1264.2,775.1c0.3,2.1-1.5,3.7-4,3.7h-154c-2.6,0-4.8-1.7-5-3.7l-4.1-44.4c-0.2-2,1.7-3.6,4.2-3.6h150.3 c2.5,0,4.8,1.6,5.1,3.6L1264.2,775.1z"/>
<path class="st1" d="M499.1,713.4c-0.4,1.9-2.7,3.5-5.2,3.5h-54.8c-2.5,0-4.2-1.6-3.7-3.5l9.3-41.9c0.4-1.9,2.7-3.4,5.2-3.4h53.6 c2.4,0,4.1,1.5,3.8,3.4L499.1,713.4z"/>
<path class="st1" d="M576.1,713.4c-0.3,1.9-2.6,3.5-5.1,3.5h-54.8c-2.5,0-4.2-1.6-3.9-3.5l7.8-41.9c0.3-1.9,2.6-3.4,5-3.4h53.6 c2.4,0,4.2,1.5,3.9,3.4L576.1,713.4z"/>
<path class="st1" d="M653,713.4c-0.2,1.9-2.5,3.5-4.9,3.5h-54.8c-2.5,0-4.3-1.6-4-3.5l6.2-41.9c0.3-1.9,2.5-3.4,4.9-3.4H654 c2.4,0,4.2,1.5,4,3.4L653,713.4z"/>
<path class="st1" d="M730,713.4c-0.2,1.9-2.3,3.5-4.8,3.5h-54.8c-2.5,0-4.3-1.6-4.1-3.5l4.7-41.9c0.2-1.9,2.4-3.4,4.8-3.4h53.6 c2.4,0,4.3,1.5,4.1,3.4L730,713.4z"/>
<path class="st1" d="M807,713.4c-0.1,1.9-2.2,3.5-4.7,3.5h-54.8c-2.5,0-4.4-1.6-4.3-3.5l3.2-41.9c0.1-1.9,2.2-3.4,4.7-3.4h53.6 c2.4,0,4.3,1.5,4.3,3.4L807,713.4z"/>
<path class="st1" d="M883.9,713.4c0,1.9-2.1,3.5-4.6,3.5h-54.8c-2.5,0-4.5-1.6-4.4-3.5l1.6-41.9c0.1-1.9,2.1-3.4,4.5-3.4h53.6 c2.4,0,4.4,1.5,4.4,3.4L883.9,713.4z"/>
<path class="st1" d="M960.9,713.4c0.1,1.9-1.9,3.5-4.4,3.5h-54.8c-2.5,0-4.5-1.6-4.5-3.5l0.1-41.9c0-1.9,2-3.4,4.4-3.4h53.6 c2.4,0,4.5,1.5,4.5,3.4L960.9,713.4z"/>
<path class="st1" d="M1037.8,713.4c0.1,1.9-1.8,3.5-4.3,3.5h-54.8c-2.5,0-4.6-1.6-4.6-3.5l-1.4-41.9c-0.1-1.9,1.9-3.4,4.3-3.4 h53.6c2.4,0,4.5,1.5,4.6,3.4L1037.8,713.4z"/>
<path class="st1" d="M1114.8,713.4c0.2,1.9-1.7,3.5-4.2,3.5h-54.8c-2.5,0-4.6-1.6-4.8-3.5l-3-41.9c-0.1-1.9,1.7-3.4,4.2-3.4h53.6 c2.4,0,4.6,1.5,4.8,3.4L1114.8,713.4z"/>
<path class="st1" d="M416.9,655.1c-0.4,1.8-2.8,3.3-5.2,3.3h-53.3c-2.4,0-4-1.5-3.5-3.3l10.6-39.6c0.5-1.8,2.8-3.2,5.2-3.2h52.1 c2.4,0,4,1.4,3.5,3.2L416.9,655.1z"/>
<path class="st1" d="M491,655.1c-0.4,1.8-2.7,3.3-5.1,3.3h-53.3c-2.4,0-4-1.5-3.6-3.3l9.2-39.6c0.4-1.8,2.7-3.2,5-3.2h52.1 c2.4,0,4,1.4,3.7,3.2L491,655.1z"/>
<path class="st1" d="M565.1,655.1c-0.3,1.8-2.5,3.3-4.9,3.3h-53.3c-2.4,0-4.1-1.5-3.7-3.3l7.7-39.6c0.3-1.8,2.6-3.2,4.9-3.2h52.1 c2.4,0,4.1,1.4,3.8,3.2L565.1,655.1z"/>
<path class="st1" d="M639.3,655.1c-0.2,1.8-2.4,3.3-4.8,3.3h-53.3c-2.4,0-4.2-1.5-3.9-3.3l6.3-39.6c0.3-1.8,2.4-3.2,4.8-3.2h52.1 c2.4,0,4.1,1.4,3.9,3.2L639.3,655.1z"/>
<path class="st1" d="M713.4,655.1c-0.2,1.8-2.3,3.3-4.7,3.3h-53.3c-2.4,0-4.2-1.5-4-3.3l4.9-39.6c0.2-1.8,2.3-3.2,4.7-3.2H713 c2.4,0,4.2,1.4,4,3.2L713.4,655.1z"/>
<path class="st1" d="M787.5,655.1c-0.1,1.8-2.2,3.3-4.6,3.3h-53.3c-2.4,0-4.3-1.5-4.1-3.3l3.4-39.6c0.2-1.8,2.2-3.2,4.6-3.2h52.1 c2.4,0,4.2,1.4,4.1,3.2L787.5,655.1z"/>
<path class="st1" d="M861.6,655.1c0,1.8-2,3.3-4.5,3.3h-53.3c-2.4,0-4.3-1.5-4.2-3.3l2-39.6c0.1-1.8,2.1-3.2,4.5-3.2h52.1 c2.4,0,4.3,1.4,4.2,3.2L861.6,655.1z"/>
<path class="st1" d="M935.7,655.1c0,1.8-1.9,3.3-4.3,3.3h-53.3c-2.4,0-4.4-1.5-4.3-3.3l0.5-39.6c0-1.8,2-3.2,4.3-3.2h52.1 c2.4,0,4.3,1.4,4.3,3.2L935.7,655.1z"/>
<path class="st1" d="M1009.8,655.1c0.1,1.8-1.8,3.3-4.2,3.3h-53.3c-2.4,0-4.4-1.5-4.5-3.3l-0.9-39.6c0-1.8,1.9-3.2,4.2-3.2h52.1 c2.4,0,4.4,1.4,4.5,3.2L1009.8,655.1z"/>
<path class="st1" d="M1084,655.1c0.2,1.8-1.7,3.3-4.1,3.3h-53.3c-2.4,0-4.5-1.5-4.6-3.3l-2.3-39.6c-0.1-1.8,1.7-3.2,4.1-3.2h52.1 c2.4,0,4.4,1.4,4.6,3.2L1084,655.1z"/>
<path class="st1" d="M1158.1,655.1c0.2,1.8-1.6,3.3-4,3.3h-53.3c-2.4,0-4.5-1.5-4.7-3.3l-3.8-39.6c-0.2-1.8,1.6-3.2,4-3.2h52.1 c2.4,0,4.5,1.4,4.7,3.2L1158.1,655.1z"/>
<g>
<g>
<path class="st1" d="M1168.9,612.2c-2.4,0-4.1,1.4-3.9,3.2l5.2,39.6c0.2,1.8,2.4,3.3,4.8,3.3h17.1c2.4,0,4.6,1.5,4.9,3.3 l7.4,51.6c0.3,1.9,2.5,3.5,5,3.5h40.4c2.5,0,4.3-1.6,3.9-3.5l-16.4-97.9c-0.3-1.8-2.5-3.2-4.8-3.2H1168.9z"/>
</g>
<g>
<path class="st1" d="M1176.3,668.1c-2.4,0-6.4,0-8.8,0h-39.9c-2.4,0-4.3,1.5-4.1,3.4l4.5,41.9c0.2,1.9,2.4,3.5,4.9,3.5h40.9 c2.5,0,6.6,0,9,0h4.9c2.5,0,4.3-1.6,4-3.5l-5.8-41.9c-0.3-1.9-2.5-3.4-4.9-3.4H1176.3z"/>
</g>
</g>
<path class="st1" d="M387.2,534.6c-0.4,1.6-2.7,3-4.9,3h-50.2c-2.3,0-3.7-1.3-3.3-3l10.5-35.1c0.5-1.6,2.7-2.8,4.9-2.8h49.1 c2.2,0,3.7,1.3,3.3,2.8L387.2,534.6z"/>
<path class="st1" d="M463,534.6c-0.4,1.6-2.5,3-4.8,3H408c-2.3,0-3.8-1.3-3.4-3l9.1-35.1c0.4-1.6,2.6-2.8,4.8-2.8h49.1 c2.2,0,3.8,1.3,3.4,2.8L463,534.6z"/>
<path class="st1" d="M538.8,534.6c-0.3,1.6-2.4,3-4.7,3h-50.2c-2.3,0-3.8-1.3-3.5-3l7.7-35.1c0.3-1.6,2.4-2.8,4.7-2.8h49.1 c2.2,0,3.8,1.3,3.5,2.8L538.8,534.6z"/>
<path class="st1" d="M614.6,534.6c-0.2,1.6-2.3,3-4.6,3h-50.2c-2.3,0-3.9-1.3-3.6-3l6.3-35.1c0.3-1.6,2.3-2.8,4.6-2.8h49.1 c2.2,0,3.9,1.3,3.6,2.8L614.6,534.6z"/>
<path class="st1" d="M691.8,534.6c-0.2,1.6-2.2,3-4.5,3h-50.2c-2.3,0-3.9-1.3-3.7-3l4.9-35.1c0.2-1.6,2.2-2.8,4.4-2.8H692 c2.2,0,3.9,1.3,3.7,2.8L691.8,534.6z"/>
<path class="st1" d="M767.6,534.6c-0.1,1.6-2.1,3-4.3,3h-50.2c-2.3,0-4-1.3-3.8-3l3.5-35.1c0.2-1.6,2.1-2.8,4.3-2.8h49.1 c2.2,0,4,1.3,3.8,2.8L767.6,534.6z"/>
<path class="st1" d="M843.4,534.6c0,1.6-2,3-4.2,3H789c-2.3,0-4.1-1.3-4-3l2.1-35.1c0.1-1.6,2-2.8,4.2-2.8h49.1c2.2,0,4,1.3,4,2.8 L843.4,534.6z"/>
<path class="st1" d="M919.2,534.6c0,1.6-1.8,3-4.1,3H865c-2.3,0-4.1-1.3-4.1-3l0.8-35.1c0-1.6,1.9-2.8,4.1-2.8h49.1 c2.2,0,4.1,1.3,4.1,2.8L919.2,534.6z"/>
<path class="st1" d="M996.5,534.6c0.1,1.6-1.7,3-4,3h-50.2c-2.3,0-4.2-1.3-4.2-3l-0.7-35.1c0-1.6,1.8-2.8,4-2.8h49.1 c2.2,0,4.1,1.3,4.2,2.8L996.5,534.6z"/>
<path class="st1" d="M1072.3,534.6c0.1,1.6-1.6,3-3.9,3h-50.2c-2.3,0-4.2-1.3-4.3-3l-2-35.1c-0.1-1.6,1.7-2.8,3.9-2.8h49.1 c2.2,0,4.2,1.3,4.3,2.8L1072.3,534.6z"/>
<path class="st1" d="M1148.1,534.6c0.2,1.6-1.5,3-3.8,3h-50.2c-2.3,0-4.3-1.3-4.4-3l-3.4-35.1c-0.2-1.6,1.5-2.8,3.8-2.8h49.1 c2.2,0,4.2,1.3,4.4,2.8L1148.1,534.6z"/>
<path class="st1" d="M1223.9,534.6c0.3,1.6-1.4,3-3.6,3h-50.2c-2.3,0-4.3-1.3-4.5-3l-4.8-35.1c-0.2-1.6,1.4-2.8,3.7-2.8h49.1 c2.2,0,4.3,1.3,4.5,2.8L1223.9,534.6z"/>
<path class="st1" d="M1316.8,534.6c0.4,1.6-1.2,3-3.5,3h-50.2c-2.3,0-4.4-1.3-4.7-3l-6.5-35.1c-0.3-1.6,1.3-2.8,3.5-2.8h49.1 c2.2,0,4.3,1.3,4.7,2.8L1316.8,534.6z"/>
<path class="st1" d="M1390.1,534.6c0.4,1.6-1.1,3-3.4,3h-50.2c-2.3,0-4.4-1.3-4.8-3l-7.9-35.1c-0.3-1.6,1.2-2.8,3.4-2.8h49.1 c2.2,0,4.4,1.3,4.8,2.8L1390.1,534.6z"/>
<path class="st1" d="M1463.4,534.6c0.5,1.6-1,3-3.3,3h-50.2c-2.3,0-4.5-1.3-4.9-3l-9.2-35.1c-0.4-1.6,1.1-2.8,3.3-2.8h49.1 c2.2,0,4.4,1.3,4.9,2.8L1463.4,534.6z"/>
<path class="st1" d="M1330.9,599.7c0.4,1.7-1.2,3.2-3.6,3.2h-51.9c-2.4,0-4.5-1.4-4.9-3.2l-7-37.5c-0.3-1.7,1.3-3,3.6-3h50.7 c2.3,0,4.5,1.4,4.8,3L1330.9,599.7z"/>
<path class="st1" d="M1406.6,599.7c0.4,1.7-1.1,3.2-3.5,3.2h-51.9c-2.4,0-4.6-1.4-5-3.2l-8.4-37.5c-0.4-1.7,1.2-3,3.5-3h50.7 c2.3,0,4.5,1.4,5,3L1406.6,599.7z"/>
<path class="st1" d="M1482.4,599.7c0.5,1.7-1,3.2-3.4,3.2h-51.9c-2.4,0-4.6-1.4-5.1-3.2l-9.8-37.5c-0.4-1.7,1.1-3,3.4-3h50.7 c2.3,0,4.6,1.4,5.1,3L1482.4,599.7z"/>
<path class="st1" d="M1565.1,599.7c0.6,1.7-0.9,3.2-3.2,3.2H1510c-2.4,0-4.7-1.4-5.2-3.2l-11.4-37.5c-0.5-1.7,1-3,3.3-3h50.7 c2.3,0,4.6,1.4,5.2,3L1565.1,599.7z"/>
<path class="st1" d="M1637.1,599.7c0.6,1.7-0.8,3.2-3.1,3.2h-51.9c-2.4,0-4.8-1.4-5.3-3.2l-12.8-37.5c-0.6-1.7,0.9-3,3.2-3h50.7 c2.3,0,4.7,1.4,5.3,3L1637.1,599.7z"/>
<path class="st1" d="M1709.2,599.7c0.7,1.7-0.6,3.2-3,3.2h-51.9c-2.4,0-4.8-1.4-5.5-3.2l-14.1-37.5c-0.6-1.7,0.7-3,3-3h50.7 c2.3,0,4.7,1.4,5.4,3L1709.2,599.7z"/>
<path class="st1" d="M1781.2,599.7c0.8,1.7-0.5,3.2-2.9,3.2h-51.9c-2.4,0-4.9-1.4-5.6-3.2l-15.5-37.5c-0.7-1.7,0.6-3,2.9-3h50.7 c2.3,0,4.8,1.4,5.5,3L1781.2,599.7z"/>
<path class="st1" d="M1583.6,655.1c0.6,1.8-0.9,3.3-3.3,3.3H1527c-2.4,0-4.9-1.5-5.4-3.3l-12-39.6c-0.5-1.8,1-3.2,3.3-3.2h52.1 c2.4,0,4.8,1.4,5.4,3.2L1583.6,655.1z"/>
<path class="st1" d="M1657.6,655.1c0.7,1.8-0.7,3.3-3.2,3.3h-53.3c-2.4,0-4.9-1.5-5.5-3.3l-13.5-39.6c-0.6-1.8,0.8-3.2,3.2-3.2 h52.1c2.4,0,4.8,1.4,5.5,3.2L1657.6,655.1z"/>
<path class="st1" d="M1731.7,655.1c0.7,1.8-0.6,3.3-3,3.3h-53.3c-2.4,0-5-1.5-5.7-3.3l-14.9-39.6c-0.7-1.8,0.7-3.2,3.1-3.2h52.1 c2.4,0,4.9,1.4,5.6,3.2L1731.7,655.1z"/>
<path class="st1" d="M1805.7,655.1c0.8,1.8-0.5,3.3-2.9,3.3h-53.3c-2.4,0-5-1.5-5.8-3.3l-16.3-39.6c-0.7-1.8,0.6-3.2,3-3.2h52.1 c2.4,0,4.9,1.4,5.7,3.2L1805.7,655.1z"/>
<path class="st1" d="M1603.1,713.7c0.6,1.9-0.9,3.5-3.3,3.5H1545c-2.5,0-5-1.6-5.6-3.5l-12.7-41.9c-0.6-1.9,1-3.4,3.4-3.4h53.6 c2.4,0,4.9,1.5,5.5,3.4L1603.1,713.7z"/>
<path class="st1" d="M1679.3,713.7c0.7,1.9-0.7,3.5-3.2,3.5h-54.8c-2.5,0-5.1-1.6-5.7-3.5l-14.2-41.9c-0.6-1.9,0.8-3.4,3.3-3.4 h53.6c2.4,0,5,1.5,5.7,3.4L1679.3,713.7z"/>
<path class="st1" d="M1755.5,713.7c0.8,1.9-0.6,3.5-3.1,3.5h-54.8c-2.5,0-5.1-1.6-5.9-3.5l-15.8-41.9c-0.7-1.9,0.7-3.4,3.1-3.4 h53.6c2.4,0,5,1.5,5.8,3.4L1755.5,713.7z"/>
<path class="st1" d="M1831.7,713.7c0.9,1.9-0.5,3.5-3,3.5h-54.8c-2.5,0-5.2-1.6-6-3.5l-17.3-41.9c-0.8-1.9,0.6-3.4,3-3.4h53.6 c2.4,0,5.1,1.5,5.9,3.4L1831.7,713.7z"/>
<path class="st1" d="M1623.9,775.7c0.7,2.1-0.8,3.7-3.4,3.7H1564c-2.6,0-5.2-1.7-5.8-3.7l-13.5-44.4c-0.6-2,1-3.6,3.5-3.6h55.1 c2.5,0,5.1,1.6,5.7,3.6L1623.9,775.7z"/>
<path class="st1" d="M1702.3,775.7c0.8,2.1-0.7,3.7-3.3,3.7h-56.5c-2.6,0-5.2-1.7-5.9-3.7l-15.1-44.4c-0.7-2,0.8-3.6,3.3-3.6h55.1 c2.5,0,5.1,1.6,5.9,3.6L1702.3,775.7z"/>
<path class="st1" d="M1780.7,775.7c0.8,2.1-0.6,3.7-3.1,3.7h-56.5c-2.6,0-5.3-1.7-6.1-3.7l-16.7-44.4c-0.7-2,0.7-3.6,3.2-3.6h55.1 c2.5,0,5.2,1.6,6,3.6L1780.7,775.7z"/>
<path class="st1" d="M1887.4,839.5c1,2.2-0.4,4-3,4h-58.1c-2.6,0-5.5-1.8-6.4-4l-44.6-108.2c-0.8-2,0.6-3.6,3.1-3.6h55.1 c2.5,0,5.3,1.6,6.1,3.6L1887.4,839.5z"/>
<path class="st1" d="M1726.6,841.5c0.8,2.2-0.7,4-3.3,4h-139.1c-2.6,0-5.3-1.8-6-4l-14.3-47.1c-0.6-2.1,1-3.8,3.5-3.8h135.7 c2.6,0,5.3,1.7,6.1,3.8L1726.6,841.5z"/>
<path class="st1" d="M1807.4,841.5c0.9,2.2-0.5,4-3.2,4h-58.2c-2.6,0-5.5-1.8-6.3-4l-17.7-47.1c-0.8-2.1,0.7-3.8,3.3-3.8h56.8 c2.6,0,5.4,1.7,6.2,3.8L1807.4,841.5z"/>
<path class="st1" d="M1342.8,655.1c0.4,1.8-1.3,3.3-3.7,3.3h-53.3c-2.4,0-4.7-1.5-5-3.3l-7.4-39.6c-0.3-1.8,1.3-3.2,3.7-3.2h52.1 c2.4,0,4.6,1.4,5,3.2L1342.8,655.1z"/>
<path class="st1" d="M1420.7,655.1c0.5,1.8-1.1,3.3-3.5,3.3h-53.3c-2.4,0-4.7-1.5-5.1-3.3l-8.9-39.6c-0.4-1.8,1.2-3.2,3.6-3.2 h52.1c2.4,0,4.7,1.4,5.1,3.2L1420.7,655.1z"/>
<path class="st1" d="M1498.6,655.1c0.5,1.8-1,3.3-3.4,3.3h-53.3c-2.4,0-4.8-1.5-5.3-3.3l-10.4-39.6c-0.5-1.8,1.1-3.2,3.5-3.2h52.1 c2.4,0,4.7,1.4,5.2,3.2L1498.6,655.1z"/>
<path class="st1" d="M1450.9,773.8c0.5,2.1-1.1,3.7-3.7,3.7h-56.4c-2.6,0-5-1.7-5.5-3.7l-9.9-44.3c-0.4-2,1.2-3.6,3.7-3.6h55.1 c2.5,0,4.9,1.6,5.4,3.6L1450.9,773.8z"/>
<path class="st1" d="M1382.6,839.5c0.5,2.2-1.3,4-3.9,4h-58.1c-2.6,0-5.1-1.8-5.5-4l-8.7-47c-0.4-2.1,1.4-3.8,4-3.8h56.7 c2.6,0,5,1.7,5.5,3.8L1382.6,839.5z"/>
<path class="st1" d="M1467.6,839.5c0.6,2.2-1.1,4-3.8,4h-58.1c-2.6,0-5.2-1.8-5.7-4l-10.5-47c-0.5-2.1,1.3-3.8,3.8-3.8h56.7 c2.6,0,5.1,1.7,5.6,3.8L1467.6,839.5z"/>
<path class="st1" d="M1552.5,839.5c0.6,2.2-1,4-3.6,4h-58.1c-2.6,0-5.3-1.8-5.8-4l-12.3-47c-0.5-2.1,1.1-3.8,3.7-3.8h56.7 c2.6,0,5.2,1.7,5.8,3.8L1552.5,839.5z"/>
<path class="st1" d="M1556.2,510.6c2.4,7-3.7,12.7-13.6,12.7c-9.9,0-19.8-5.7-22.1-12.7c-2.3-6.9,3.9-12.5,13.6-12.5 C1544,498.1,1553.8,503.7,1556.2,510.6z"/>
<path class="st1" d="M1622,510.6c2.6,7-3.2,12.7-13.1,12.7c-9.9,0-20-5.7-22.5-12.7c-2.5-6.9,3.4-12.5,13.2-12.5 C1609.3,498.1,1619.4,503.7,1622,510.6z"/>
<path class="st1" d="M1687.8,510.6c2.9,7-2.8,12.7-12.7,12.7c-9.9,0-20.2-5.7-23-12.7c-2.7-6.9,3-12.5,12.8-12.5 C1674.7,498.1,1684.9,503.7,1687.8,510.6z"/>
</g>
</g>
<g id="hand">
<g id="fingers">
<path id="thumb" class="st4" d="M1310.4,601.1l-81.9,67.3l-26.4,109.9l57.3,20.3l46.8-90.4l191-30.2l-6-22.8
c-13.6-51.5-66.1-82.6-117.9-69.7L1310.4,601.1z"/>
<polygon id="pinky" class="st4" points="1348.9,499.2 1242.7,571.9 1270.6,623.2 1230.2,631.3 1176.4,574.6 1253.5,432.3
1402,477.5 "/>
<polygon id="ring" class="st4" points="1374.8,415 1139.1,535 1133.8,619.7 1139.7,686.1 1186.8,680.6 1194.3,584.9 1246.6,510
"/>
<polygon id="middle" class="st4" points="1232.9,425.7 1125.5,494.3 1068.4,584.8 1053.5,719.1 1104.7,728.8 1135.6,609.3
1202,520.5 1384.2,445.9 "/>
<path id="index" class="st4" d="M1298.2,407.4l-176.7-53.8l-111.3,103.1l-5.3,123.7l48.2,5.8l24.2-91.7l55.9-41.8l120.1,65.1 l39.4-14.3c25.8-9.4,37.1-39.7,23.6-63.6L1298.2,407.4z"/>
</g>
<path id="arm" class="st4" d="M1497.2,678.1L1657,577.6l47.7-67.4l287.7-287.5l-181.6-84.6l-201.1,246.2l-311.6,23l-26.7,7.1 c-33.2,8.9-49.3,46.6-32.8,76.7l14.7,26.8l56.9,83.2l33.2,55.8L1497.2,678.1z"/>
</g>
</svg>
<style>
svg {
width: 80vw;
height: 40vw;
overflow: visible;
@media screen and (min-width: 768px) {
width: 60vw;
height: 30vw;
}
}
#hand {
opacity: 0;
}
#keys path {
opacity: 0;
}
.st0{fill:var(--color-bg);}
.st1{fill:var(--color-text)}
.st4{fill:var(--color-highlight, #000);}
</style>

View file

@ -0,0 +1,21 @@
<svg class="shape" x="0px" y="0px" viewBox="0 0 1000 1000" width="1000" height="1000">
<path class="morphshape" d="M1000,0 C1000,333.33333 1000,666.66667 1000,1000 666.66667,1000 333.33333,1000 0,1000 0,666.66667 0,333.33333 0,0 333.33333,0 666.66667,0 1000,0 z"/>
<circle class="sphere" cx="500" cy="500" r="500"/>
<path class="quartercirc" d="M0,0c0,552.3,447.7,1000,1000,1000V0L0,0z"/>
<polygon class="triangle" points="0,1000 0,0 1000,0 "/>
<rect class="rectangle" x="0" y="0" width="1000" height="1000"/>
</svg>
<style>
.shape {
width: 100%;
height: auto;
transform-origin: 50% 50%;
}
.shape > * {
transform-origin: 50% 50%;
}
.sphere, .quartercirc, .triangle, .rectangle {
fill: none;
}
</style>

After

Width:  |  Height:  |  Size: 744 B

View file

@ -0,0 +1,88 @@
<script lang="ts">
import HomeIlluShape from "./HomeIlluShape.svelte";
import gsap from "gsap";
import MorphSVGPlugin from "gsap/dist/MorphSVGPlugin";
import ScrollTrigger from "gsap/dist/ScrollTrigger";
import { onMount } from "svelte";
onMount( () => {
gsap.registerPlugin(MorphSVGPlugin, ScrollTrigger);
let introTl = gsap.timeline({
scrollTrigger: {
trigger: '.home-illu-shapes',
start: 'top 80%',
end: 'top 0%',
scrub: false,
// markers: true
}
});
document.querySelectorAll('.home-illu-shapes > .shape').forEach( (shape) => {
introTl.fromTo(shape,
{ autoAlpha: 0, x: Math.random() * 1000 - 500, y: Math.random() * 1000 - 500},
{ autoAlpha: 1, x: 0, y: 0, duration: 1, ease: "cubic.inOut" }, 0
)
})
let shapesToPaths = MorphSVGPlugin.convertToPath('.sphere, .quartercirc, .triangle, .rectangle');
let shapes = [shapesToPaths[0], shapesToPaths[1], shapesToPaths[2], shapesToPaths[3]]
const generateAngle = () => {
let rand = Math.floor(Math.random() * 2);
return rand === 0 ? 90 : -90;
}
const randomMorph = (shape: HTMLElement, index: number = 0) => {
const randomShape = shapes[Math.floor(Math.random() * shapes.length)];
let rowindex = (index: number) => {
// based on the index of an element within an array of 5x3 grid, return the columns index, so for example 0, 5 and 10 would return 0, index 1, 6 and 11 would return 1, etc
return index % 5;
};
gsap.to(shape, {
duration: 1,
rotationZ: "+=" + generateAngle(),
morphSVG: randomShape,
ease: 'power4.out',
delay: rowindex(index) * 0.1,
onComplete: () => { setTimeout( () => randomMorph(shape), 2000 ) }
});
}
document.querySelectorAll('.morphshape').forEach( (shape, index) => {
randomMorph(shape as HTMLElement, index);
})
})
</script>
<div class="home-illu-shapes">
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
<HomeIlluShape />
</div>
<style>
.home-illu-shapes {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
:global(.home-illu-shapes > *) {
flex-basis: calc(20% - 5px);
opacity: 0;
}
</style>

View file

@ -1,4 +1,9 @@
<svg id="floter-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 287.4 83.5" width="290" height="85"> <script lang="ts">
import { logotext } from "$lib/utils/stores";
// let $logotexttext = logotext.subscribe((value) => JSON.stringify(value));
</script>
<!-- <svg id="floter-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 287.4 83.5" width="290" height="85">
<path id="r" d="M259.9 82.4h-24.2l11.6-54.9h22l-2.7 12.9c4.5-8.9 11-14 18.1-14 1 0 2.1 0 2.7.2l-4.7 22.1c-1.4-.4-3.3-.9-6.4-.9-5.4 0-9.7 2.3-10.8 7.7l-5.6 26.9z"/> <path id="r" d="M259.9 82.4h-24.2l11.6-54.9h22l-2.7 12.9c4.5-8.9 11-14 18.1-14 1 0 2.1 0 2.7.2l-4.7 22.1c-1.4-.4-3.3-.9-6.4-.9-5.4 0-9.7 2.3-10.8 7.7l-5.6 26.9z"/>
<path id="e" d="M237.9 59.3h-35.7c.3 5.2 2.2 7.5 6.5 7.5 2.9 0 5.1-1.5 5.9-4.2h22.3c-4.3 13.2-14.5 20.9-30.4 20.9-16.3 0-26.5-9.7-26.5-25.2 0-17.8 13.4-32 32.3-32 16.3 0 26.5 9.7 26.5 25.2 0 2.7-.4 5.3-.9 7.8zM203.3 50h13.5c-.2-4-1.8-6.5-6-6.5-3.4 0-6.1 2.1-7.5 6.5z"/> <path id="e" d="M237.9 59.3h-35.7c.3 5.2 2.2 7.5 6.5 7.5 2.9 0 5.1-1.5 5.9-4.2h22.3c-4.3 13.2-14.5 20.9-30.4 20.9-16.3 0-26.5-9.7-26.5-25.2 0-17.8 13.4-32 32.3-32 16.3 0 26.5 9.7 26.5 25.2 0 2.7-.4 5.3-.9 7.8zM203.3 50h13.5c-.2-4-1.8-6.5-6-6.5-3.4 0-6.1 2.1-7.5 6.5z"/>
<path id="t" d="M171.5 65.9c1.9 0 4.3-.3 6.3-1L174 82.2c-2.5.8-7.1 1.3-11.1 1.3-14 0-23.2-5.1-19.6-22.3l3.5-16.7h-5.5l3.6-17h5.5l3.3-15.4H178l-3.3 15.4h11l-3.6 17h-11l-3.3 15.8c-.9 3.9.3 5.6 3.7 5.6z"/> <path id="t" d="M171.5 65.9c1.9 0 4.3-.3 6.3-1L174 82.2c-2.5.8-7.1 1.3-11.1 1.3-14 0-23.2-5.1-19.6-22.3l3.5-16.7h-5.5l3.6-17h5.5l3.3-15.4H178l-3.3 15.4h11l-3.6 17h-11l-3.3 15.8c-.9 3.9.3 5.6 3.7 5.6z"/>
@ -6,13 +11,25 @@
<path id="o" d="M111.4 26.4c16.7 0 27.2 9.7 27.2 25.2 0 17.8-13.7 32-33.1 32-16.7 0-27.2-9.7-27.2-25.2 0-17.9 13.8-32 33.1-32zm-3.9 36.7c5.3 0 8.8-4.3 8.8-9.4 0-4.2-2.5-6.8-6.6-6.8-5.4 0-8.9 4.3-8.9 9.4 0 4.1 2.5 6.8 6.7 6.8z"/> <path id="o" d="M111.4 26.4c16.7 0 27.2 9.7 27.2 25.2 0 17.8-13.7 32-33.1 32-16.7 0-27.2-9.7-27.2-25.2 0-17.9 13.8-32 33.1-32zm-3.9 36.7c5.3 0 8.8-4.3 8.8-9.4 0-4.2-2.5-6.8-6.6-6.8-5.4 0-8.9 4.3-8.9 9.4 0 4.1 2.5 6.8 6.7 6.8z"/>
<polygon id="l" points="45.5,82.4 63,0 87.1,0 69.7,82.4"/> <polygon id="l" points="45.5,82.4 63,0 87.1,0 69.7,82.4"/>
<polygon id="F" points="17.5,0 59.7,0 55.5,19.8 36.9,19.8 34.1,33 50.5,33 46.3,52.7 29.9,52.7 23.6,82.4 0,82.4"/> <polygon id="F" points="17.5,0 59.7,0 55.5,19.8 36.9,19.8 34.1,33 50.5,33 46.3,52.7 29.9,52.7 23.6,82.4 0,82.4"/>
</svg> </svg> -->
<div id="floter-logo">{$logotext}</div>
<style> <style>
#floter-logo { /* #floter-logo {
fill: currentColor; fill: currentColor;
height: 100%; height: 100%;
width: auto; width: auto;
display: block; display: block;
} */
#floter-logo {
text-decoration: none;
display: block;
font-size: 36px;
letter-spacing: -0.033em;
line-height: 36px;
@media screen and (min-width: 768px) {
font-size: 48px;
}
} }
</style> </style>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,6 +1,7 @@
<script lang='ts'> <script lang='ts'>
import { onMount } from "svelte"; import { onMount } from "svelte";
import { gsap } from "gsap"; import { gsap } from "gsap";
import { page } from "$app/stores";
onMount(() => { onMount(() => {
@ -15,6 +16,9 @@
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)=> {
if (e.target?.toString() === $page.url.toString()) {
return;
}
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: '100%', autoAlpha: 1, ease: 'power4.out'}); gsap.to('.content > *', {duration: 0.5, y: '100%', autoAlpha: 1, ease: 'power4.out'});
@ -48,9 +52,9 @@
<span class="close">×</span> <span class="close">×</span>
</label> </label>
<nav id="nav"> <nav id="nav">
<a href="/">Home</a> <a href="/" class="navlink {$page.route.id === '/' ? 'current' : ''}">Home</a>
<a href="/work">About</a> <a href="/about" class="navlink {$page.route.id === '/about' ? 'current' : ''}">About</a>
<a href="/work">Hire</a> <a href="/work" class="navlink {$page.route.id === '/work' ? 'current' : ''}">Work</a>
</nav> </nav>
</header> </header>
@ -122,5 +126,9 @@
&:first-child { &:first-child {
margin-top: 1em; margin-top: 1em;
} }
&.current {
text-decoration: underline;
}
} }
</style> </style>

View file

@ -13,24 +13,30 @@ import { tick } from 'svelte';
export let textsToCanvas: Array<HTMLElement> = []; export let textsToCanvas: Array<HTMLElement> = [];
export let imgsToCanvas: Array<HTMLElement> = []; export let imgsToCanvas: Array<HTMLElement> = [];
export let bulgeFactor: number = 0.15; export let bulgeFactor: number = 0.15; // comes from attribute
let app: PIXI.Application; let app: PIXI.Application;
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
onMount(()=>{ onMount( () => {
let is_fine = window.matchMedia('(pointer:fine)').matches let is_fine = window.matchMedia('(pointer:fine)').matches
let is_landscape = window.matchMedia('(orientation:landscape)').matches let is_landscape = window.matchMedia('(orientation:landscape)').matches
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText); gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
const root = document.querySelector(':root') as HTMLElement;
const bgColorFromRoot = () => { return getComputedStyle(root).getPropertyValue('--color-bg') || 'rgb(255, 255, 255)'};
function textColorFromRoot(){ return getComputedStyle(root).getPropertyValue('--color-text') || 'rgb(0, 0, 0)' };
const highlightColorFromRoot = () => { return getComputedStyle(root).getPropertyValue('--color-highlight') || 'rgb(0, 0, 0)' };
const thisElemBgColor = (elem: HTMLElement) => { return getComputedStyle(elem).getPropertyValue('background-color') || 'rgb(255, 255, 255)' };
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: 1, backgroundColor: bgColorFromRoot(),
backgroundColor: 0x223ad4, backgroundAlpha: 0,
view: canvas, view: canvas,
}); });
@ -52,15 +58,19 @@ onMount(()=>{
group.y = window.innerHeight / 2; group.y = window.innerHeight / 2;
app.stage.addChild(group); app.stage.addChild(group);
let recty = new PIXI.Graphics(); let group_background = new PIXI.Graphics();
recty.beginFill('rgb(0, 0, 0)'); function draw_group_background(group_background: PIXI.Graphics) {
recty.drawRect(0, 0, xFrac(1), yFrac(1)); group_background.clear();
recty.endFill(); group_background.beginFill(bgColorFromRoot());
recty.alpha = 0; group_background.drawRect(0, 0, xFrac(1), yFrac(1));
recty.pivot.set(xFrac(.5), yFrac(.5)); group_background.endFill();
recty.x = xFrac(0.5); group_background.alpha = 0;
recty.y = yFrac(0.5); group_background.pivot.set(xFrac(.5), yFrac(.5));
group.addChild(recty); group_background.x = xFrac(0.5);
group_background.y = yFrac(0.5);
}
draw_group_background(group_background);
group.addChild(group_background);
let center = [0.5, 0.5]; let center = [0.5, 0.5];
let bulgefilter = new BulgePinchFilter(); let bulgefilter = new BulgePinchFilter();
@ -68,8 +78,9 @@ onMount(()=>{
bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25; bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25;
bulgefilter.center = center; bulgefilter.center = center;
bulgefilter.resolution = 2; bulgefilter.resolution = 2;
app.stage.filters = [bulgefilter];
app.stage.filters = [bulgefilter];
/*---------------------------------- /*----------------------------------
* Convert text to canvas using * Convert text to canvas using
@ -87,7 +98,6 @@ onMount(()=>{
}) })
} }
/*---------------------------------- /*----------------------------------
* Function to update text on canvas * Function to update text on canvas
* runs in the Ticker * runs in the Ticker
@ -95,11 +105,11 @@ onMount(()=>{
function updateText(){ function updateText(){
canvasTexts.forEach((text, index) => { canvasTexts.forEach((text, index) => {
let headlinePosition = elems[index].getBoundingClientRect(); let headlinePosition = elems[index].getBoundingClientRect();
text.position.set(headlinePosition.x, headlinePosition.y); text.position.set(headlinePosition.x - ((tween.x - 0.5) * 50), headlinePosition.y - ((tween.y - 0.5) * 50));
// text.position.x = headlinePosition.x; text.alpha = window.getComputedStyle(elems[index]).opacity as unknown as number;
// ^ This bcs pos:fixed doesn't update fast enough when mobile browser chrome changes on scroll text.style.fill = window.getComputedStyle(elems[index]).color;
text.alpha = elems[index].style.opacity as unknown as number || 0.3;
}) })
} }
/*---------------------------------- /*----------------------------------
@ -112,7 +122,7 @@ onMount(()=>{
function convertImgs(){ function convertImgs(){
imgsToCanvas.forEach((element) => { imgsToCanvas.forEach((element) => {
imgElems.push(element); imgElems.push(element);
let canvasImg = createCanvasImg(element as HTMLImageElement, app.stage); let canvasImg = createCanvasImg(element as HTMLImageElement, group);
canvasImgs.push(canvasImg); canvasImgs.push(canvasImg);
}) })
} }
@ -122,6 +132,7 @@ onMount(()=>{
* Function to update text on canvas * Function to update text on canvas
* runs in the Ticker * runs in the Ticker
----------------------------------*/ ----------------------------------*/
function updateImgs(){ function updateImgs(){
canvasImgs.forEach((image, index) => { canvasImgs.forEach((image, index) => {
let imagePosition = imgElems[index].getBoundingClientRect(); let imagePosition = imgElems[index].getBoundingClientRect();
@ -133,7 +144,44 @@ onMount(()=>{
}) })
} }
let workinfoBgs: Array<PIXI.Graphics> = [];
let workinfos = document.querySelectorAll('.work-info');
/*----------------------------------
* Create background for workinfo
----------------------------------*/
function createWorkInfoBgs() {
workinfos.forEach( workinfo => {
const workinfoRect = workinfo.getBoundingClientRect();
let workinfoGraphic = new PIXI.Graphics();
workinfoGraphic.beginFill(textColorFromRoot());
workinfoGraphic.drawRect(workinfoRect.x, workinfoRect.y, workinfoRect.width, workinfoRect.height);
workinfoGraphic.endFill();
workinfoGraphic.pivot.set(workinfoRect.x, workinfoRect.y);
workinfoBgs.push(workinfoGraphic);
app.stage.addChild(workinfoGraphic);
})
}
/*----------------------------------
* Update background for workinfo
----------------------------------*/
function updateWorkInfoBgs() {
workinfos.forEach((workinfo, index) => {
const workinfoRect = workinfo.getBoundingClientRect();
workinfoBgs[index].clear();
workinfoBgs[index].beginFill(thisElemBgColor(workinfo as HTMLElement));
workinfoBgs[index].drawRect(workinfoRect.x, workinfoRect.y, workinfoRect.width, workinfoRect.height);
workinfoBgs[index].endFill();
workinfoBgs[index].pivot.set(workinfoRect.x, workinfoRect.y);
workinfoBgs[index].position.set(workinfoRect.x - ((tween.x - 0.5) * 50), workinfoRect.y - ((tween.y - 0.5) * 50));
workinfoBgs[index].alpha = window.getComputedStyle(workinfo).opacity as unknown as number;
})
}
createWorkInfoBgs();
setTimeout(() => { setTimeout(() => {
convertImgs(); convertImgs();
convertText(); convertText();
@ -177,6 +225,7 @@ onMount(()=>{
bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25; bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25;
updateImgs(); updateImgs();
updateText(); updateText();
updateWorkInfoBgs();
}) })
}) // <- end onMount }) // <- end onMount

View file

@ -7,6 +7,7 @@ type Post = {
header_bg_image: string header_bg_image: string
svg: string svg: string
video: string video: string
order: number
} }
default: { default: {
render: () => string render: () => string

View file

@ -1,12 +1,12 @@
:root { :root {
--spacing-outer: 5vw; --spacing-outer: 5vw;
--spacing-nav: 5vw; --spacing-nav: 5vw;
// --color-bg: #FFF; --color-bg: #3c71c8;
// --color-text: #000; --color-text: #ffeee6;
// --color-bg: #00117f; --color-highlight: #000000;
--color-bg: #223ad4; // --color-bg: #000000;
// --color-text: #FF9494; // --color-text: #FFFFFF;
--color-text: #FFF; // --color-highlight: #FF4D00;
--aspect-ratio-heroes: 1.5; --aspect-ratio-heroes: 1.5;
--font-size-p: clamp(20px, 1.6vw, 1.6vw); --font-size-p: clamp(20px, 1.6vw, 1.6vw);
@ -30,17 +30,34 @@ body {
color: var(--color-text); color: var(--color-text);
min-height: 100svh; min-height: 100svh;
} }
// body:after {
// content: '';
// display: block;
// position: fixed;
// top: 0;
// left: 0;
// width: calc(100vw - 00px);
// height: calc(100svh - 30px);
// border: 15px solid var(--color-text);
// z-index: 1;
// pointer-events: none;
// }
body * { body * {
box-sizing: border-box; box-sizing: border-box;
} }
h1, h2, h3, h4, h5 { h1, h2, h3, h4, h5 {
font-size: 2em; font-size: 2em;
line-height: 1.2; line-height: 1.1;
font-weight: 900; font-weight: 400;
font-style: italic; letter-spacing: -0.025em;
letter-spacing: -0.02em; }
h1 {
font-size: 3.5em;
} }
h2 { h2 {
font-size: 2em;
}
h3 {
font-size: 1.5em; font-size: 1.5em;
} }
ul, ol { ul, ol {
@ -57,12 +74,14 @@ p, li {
a { a {
color: inherit; color: inherit;
} }
.button { .cta {
font-size: clamp(20px, 1.6vw, 1.6vw); font-size: clamp(20px, 1.6vw, 1.6vw);
}
.button {
font-weight: 900; font-weight: 900;
font-style: italic; font-style: italic;
display: inline-block; display: inline-block;
margin: 1em 0.5em 1em 0; margin: 1em 0.125em;
padding: .75em; padding: .75em;
text-decoration: none; text-decoration: none;
box-sizing: border-box; box-sizing: border-box;
@ -71,38 +90,37 @@ a {
position: relative; position: relative;
z-index: 2; z-index: 2;
transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
letter-spacing: -0.01em;
&:hover { &:hover {
letter-spacing: 0.01em; font-size: clamp(21px, 1.7vw, 1.7vw);
} }
&:before { &:before {
content: ''; content: '';
display: block; display: block;
position: absolute; position: absolute;
z-index: -1; z-index: -1;
bottom: 0;
left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
left: 0px;
bottom: 0;
border: 2px solid var(--color-text); border: 2px solid var(--color-text);
border-radius: 0; background-color: var(--color-bg);
box-sizing: border-box; box-sizing: border-box;
transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
&:hover:before { &:hover:before {
left: -10px; width: 100%;
width: calc(100% + 20px); height: calc(100% + 10px);
height: calc(100% - 10px); left: 0;
bottom: 5px; bottom: -5px;
border-radius: .25em;
transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
&.button--primary { &.button--primary {
color: var(--color-bg); color: var(--color-bg);
&:before { &:before {
background-color: var(--color-text); background-color: var(--color-highlight);
border: 2px solid var(--color-highlight);
} }
} }
&.button--xl { &.button--xl {

View file

@ -5,18 +5,25 @@ export default function createCanvasText( element: HTMLImageElement, stage: PIX
const elem = element; const elem = element;
const elemSrc = elem.currentSrc || elem.src; const elemSrc = elem.currentSrc || elem.src;
const elemPosition = elem.getBoundingClientRect(); const elemPosition = elem.getBoundingClientRect();
let canvasImg: PIXI.Sprite;
let scalefactor = 1;
if (elemSrc.includes('.svg')) {
scalefactor = Number(elem.attributes.getNamedItem('data-svgscale')?.value);
const canvasImgTexture = PIXI.Texture.from(elemSrc, { resourceOptions: { scale: scalefactor } });
canvasImg = new PIXI.Sprite(canvasImgTexture);
} else {
canvasImg = PIXI.Sprite.from(elemSrc);
}
const canvasImg = PIXI.Sprite.from(elemSrc);
canvasImg.position.set(elemPosition.x, elemPosition.y); canvasImg.position.set(elemPosition.x, elemPosition.y);
canvasImg.width = elemPosition.width; canvasImg.width = elemPosition.width/scalefactor;
canvasImg.height = elemPosition.height; canvasImg.height = elemPosition.height;
canvasImg.on('added', () => { canvasImg.on('added', () => {
console.log('canvas imgs added');
elem.classList.add('canvas-img-added'); elem.classList.add('canvas-img-added');
elem.style.visibility = 'hidden'; elem.style.visibility = 'hidden';
}); });
stage.addChild(canvasImg); stage.addChild(canvasImg);
// elem.style.opacity = '0';
return canvasImg; return canvasImg;
} }

View file

@ -9,12 +9,16 @@ export default function createCanvasText( element: HTMLElement, stage: PIXI.Con
const elemFontWeight = elemStyles.getPropertyValue('font-weight') || 'normal'; const elemFontWeight = elemStyles.getPropertyValue('font-weight') || 'normal';
const elemFontFamily = elemStyles.getPropertyValue('font-family') || 'Arial'; const elemFontFamily = elemStyles.getPropertyValue('font-family') || 'Arial';
const elemFontStyle = elemStyles.getPropertyValue('font-style') || 'normal'; const elemFontStyle = elemStyles.getPropertyValue('font-style') || 'normal';
const elemLetterSpacing = parseInt(elemStyles.getPropertyValue('letter-spacing')) || 0; const elemLetterSpacing = Number(elemStyles.getPropertyValue('letter-spacing').replace('px','')) || 0;
const elemColor = elemStyles.getPropertyValue('color') || 'black'; const elemColor = elemStyles.getPropertyValue('color') || 'black';
const elemAlignment = elemStyles.getPropertyValue('text-align') || 'left'; const elemAlignment = elemStyles.getPropertyValue('text-align') || 'left';
const elemPosition = elem.getBoundingClientRect(); const elemPosition = elem.getBoundingClientRect();
const canvasText = new Text(elem?.textContent as string, { const elemTextTransform = elemStyles.getPropertyValue('text-transform') || 'none';
if (elemTextTransform === 'uppercase') {
elem.textContent = elem.textContent?.toUpperCase() as string;
}
const canvasText = new Text(elem.textContent as string, {
fontFamily: elemFontFamily, fontFamily: elemFontFamily,
fontSize: elemFontSize, fontSize: elemFontSize,
fontWeight: elemFontWeight as PIXI.TextStyleFontWeight, fontWeight: elemFontWeight as PIXI.TextStyleFontWeight,
@ -22,16 +26,15 @@ export default function createCanvasText( element: HTMLElement, stage: PIXI.Con
letterSpacing: elemLetterSpacing, letterSpacing: elemLetterSpacing,
fill: elemColor, fill: elemColor,
align: elemAlignment as PIXI.TextStyleAlign, align: elemAlignment as PIXI.TextStyleAlign,
padding: 20,
}); });
canvasText.on('added', () => { canvasText.on('added', () => {
console.log('canvas text added');
elem.classList.add('canvas-text-added'); elem.classList.add('canvas-text-added');
elem.style.opacity = '0';
elem.style.visibility = 'hidden'; elem.style.visibility = 'hidden';
}); });
canvasText.position.set(elemPosition.x, elemPosition.y); canvasText.position.set(elemPosition.x, elemPosition.y);
// canvasText.zIndex = 100;
stage.addChild(canvasText); stage.addChild(canvasText);
return canvasText; return canvasText
} }

View file

@ -1,52 +0,0 @@
import sharp from 'sharp';
export const IMAGE_DIR='/src/lib/assets/';
export async function dominantColour({ source }: { source: string }){
try {
const image = sharp(source);
const{ dominant }=await image.stats();
return dominant;
} catch (error) {
console.error('Error determining dominant colour: ', source);
}
}
export async function lowResolutionPlaceholder({ source }: { source: string }) {
try {
const image = sharp(source);
const buffer = await image
.resize(10)
.jpeg({
quality: 50,
progressive: true,
optimiseScans: true,
chromaSubsampling: '4:2:0',
trellisQuantisation: true,
quantisationTable: 2,
})
.toBuffer({ resolveWithObject: false });
return `data:image/jpeg;base64,${(await buffer).toString('base64')}`;
} catch (error) {
console.error('Error generating low resolution placeholder: ', source);
}
}
export const dominantColourPlaceholder = async ({ source }: {source: string})=>{
try{
const dominant = await dominantColour({ source }) as { r: number; g: number; b: number };
const{ r, g, b }= dominant;
const buffer = await sharp({
create:{
width:3,
height:2,
channels:3,
background:{ r, g, b },
},
})
.jpeg()
.toBuffer({resolveWithObject:false});
return`data:image/jpeg;base64,${buffer.toString('base64')}`;
}catch(error){
console.error('Error determining dominant colour: ', source);
}
};

45
src/lib/utils/rgbToHex.ts Normal file
View file

@ -0,0 +1,45 @@
function hslToHex(h:number, s:number, l:number) {
l /= 100;
const a = s * Math.min(l, 1 - l) / 100;
const f = (n:number) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color).toString(16).padStart(2, '0'); // convert to Hex and prefix "0" if needed
};
return `0x${f(0)}${f(8)}${f(4)}`;
}
export default function RGBToHex(colorstring: string) {
if (colorstring.charAt(0) == "#"){
colorstring = colorstring.replace("#", "0x");
return colorstring;
}
if (colorstring.charAt(0) == "r") {
// Choose correct separator
const sep = colorstring.indexOf(",") > -1 ? "," : " ";
// Turn "rgb(r,g,b)" into [r,g,b]
const rgbArray = colorstring.substr(4).split(")")[0].split(sep);
let r = (+rgbArray[0]).toString(16),
g = (+rgbArray[1]).toString(16),
b = (+rgbArray[2]).toString(16);
if (r.length == 1)
r = "0" + r;
if (g.length == 1)
g = "0" + g;
if (b.length == 1)
b = "0" + b;
return "0x" + r + g + b;
}
if (colorstring.charAt(0) == "h") {
const hslArray = colorstring.substr(4).split(")")[0].split(",");
const h = Number(hslArray[0]);
const s = Number(hslArray[1].replace("%", ""));
const l = Number(hslArray[2].replace("%", ""));
return hslToHex(h, s, l);
}
}

View file

@ -1,4 +1,5 @@
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
export const workbulge = writable(0.25); export const workbulge = writable(0.25);
export const loading = writable(false); export const loading = writable(false);
export const logotext = writable('Flöter');

View file

@ -5,10 +5,13 @@
import { gsap } from 'gsap'; import { gsap } from 'gsap';
import ScrollTrigger from 'gsap/dist/ScrollTrigger'; import ScrollTrigger from 'gsap/dist/ScrollTrigger';
import SplitText from 'gsap/dist/SplitText'; import SplitText from 'gsap/dist/SplitText';
import HomeIlluDev from '$lib/components/HomeIlluDev.svelte';
import HomeIlluShapes from '$lib/components/HomeIlluShapes.svelte';
let canvasElems: Array<HTMLElement>; let canvasElems: Array<HTMLElement>;
let imgElems: Array<HTMLElement>;
let mounted = false; let mounted = false;
onMount( () => { onMount( () => {
mounted = true; mounted = true;
@ -16,33 +19,39 @@
gsap.registerPlugin( ScrollTrigger, SplitText ); gsap.registerPlugin( ScrollTrigger, SplitText );
const sections = document.querySelectorAll('section'); const sections = document.querySelectorAll('section');
sections.forEach( (section) => { sections.forEach( (section) => {
if ( section.classList.contains('splash')){ if ( section.classList.contains('splash')){
let split = new SplitText(section.querySelectorAll('h1'), { type: 'words', wordsClass: 'lineChildren' }); let split = new SplitText(section.querySelectorAll('h1'), { type: 'words', wordsClass: 'wordChildren' });
split.words.forEach( (word) => {
word.innerHTML = word.innerHTML.replace(' ', '');
})
gsap.set(split.words, { gsap.set(split.words, {
opacity: 0, opacity: 1,
y: 60, y: -window.innerHeight,
transformOrigin: '50% 100%' transformOrigin: '50% 100%'
}) })
gsap.to(split.words, { gsap.to(split.words, {
duration: 0.5, duration: 1,
opacity: 1, opacity: 1,
y: 0, y: 0,
stagger: 0.033, stagger: -0.01,
ease: 'back.out', ease: 'elastic.out(1, .5)',
delay: .3 delay: .3
}) })
} }
else { else {
let split = new SplitText(section.querySelectorAll('h2'), { type: 'lines', linesClass: 'lineChildren' }); let split = new SplitText(section.querySelectorAll('h2'), { type: 'words', wordsClass: 'wordChildren' });
gsap.set(split.lines, { transformOrigin: '0% 100%' }); split.words.forEach( (word) => {
gsap.set(split.lines, { yPercent: 100, opacity: 0 }); word.innerHTML = word.innerHTML.replace(' ', '');
gsap.to(split.lines, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.1, ease: 'power4.out', })
scrollTrigger: { trigger: split.lines, start: 'top 90%', end: 'bottom 70%', scrub: false } gsap.set(split.words, { transformOrigin: '0% 100%' });
gsap.set(split.words, { yPercent: 100, opacity: 0 });
gsap.to(split.words, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.05, ease: 'power4.out',
scrollTrigger: { trigger: split.words, start: 'top 90%', end: 'bottom 70%', scrub: false }
}) })
if (section.querySelector('p')) { if (section.querySelector('.toCanvas')) {
let splitp = new SplitText(section.querySelectorAll('p'), { type: 'lines', linesClass: 'lineChildren' }); let splitp = new SplitText(section.querySelectorAll('.toCanvas'), { type: 'lines', linesClass: 'lineChildren' });
gsap.set(splitp.lines, { transformOrigin: '0% 100%' }); gsap.set(splitp.lines, { transformOrigin: '0% 100%' });
gsap.set(splitp.lines, { yPercent: 100, opacity: 0 }); gsap.set(splitp.lines, { yPercent: 100, opacity: 0 });
gsap.to(splitp.lines, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.05, ease: 'power4.out', gsap.to(splitp.lines, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.05, ease: 'power4.out',
@ -50,9 +59,10 @@
}) })
} }
} }
})
canvasElems = Array.from(document.querySelectorAll('.lineChildren'));
})
canvasElems = Array.from(document.querySelectorAll('.lineChildren, .wordChildren'));
imgElems = Array.from(document.querySelectorAll('img'));
return () => { return () => {
gsap.killTweensOf(canvasElems); gsap.killTweensOf(canvasElems);
ScrollTrigger.getAll().forEach( instance => instance.kill() ); ScrollTrigger.getAll().forEach( instance => instance.kill() );
@ -65,33 +75,49 @@
{/if} {/if}
<article class="scroller"> <article class="scroller">
<section class="splash"> <section class="splash">
<h1>Simon Flöter creates products that stand out.</h1> <h1>Hallo! I'm Simon.<br> I forge websites<br/><em>that stand out</em> with great beauty.</h1>
</section> </section>
<section class="intro"> <section class="intro">
<h2>As a Creative Web Developer ...</h2> <figure class="intro-image">
<p>I specialise in delivering beautifully crafted bespoke websites.</p> <HomeIlluDev />
</figure>
<h2><em>Creative</em> Development</h2>
<p class="toCanvas">I specialise in fashioning exquisitly tailored websites and webapps for the discerning enterprise executive.</p>
<div class="cta"> <div class="cta">
<a href="/work" class="button">Learn More</a> <a href="/service" class="button">My Services</a>
<a href="/work" class="button button--primary">Hire Simon</a> <a href="/work" class="button button--primary">Hire Simon</a>
</div> </div>
</section> </section>
<section class="more"> <section class="design">
<h2>As a UX & Graphic Designer...</h2> <figure class="design-illu">
<p>I have designed Websites, Housestyles, Typefaces, Advertising campaigns and Print publications for them.</p> <HomeIlluShapes />
</figure>
<h2>Visual Design</h2>
<p class="toCanvas">With years in the craft, I've mastered the art of designing websites, user interfaces, illustrations, house styles, and everything betwixt.</p>
<div class="cta"> <div class="cta">
<a href="/work" class="button">Learn More</a> <a href="/service" class="button">My Services</a><a href="/work" class="button button--primary">Hire Simon</a>
<a href="/work" class="button button--primary">Hire Simon</a>
</div> </div>
</section> </section>
<section class="more"> <section class="more">
<h2>I create products that help great companies reach their audiences. Need help?</h2> <h2>I create products that help great companies reach their audiences.</h2>
<div class="cta"> <div class="cta">
<a href="/work" class="button button--xl">Reach out!</a> <a href="/work" class="button button--xl">Reach out!</a>
</div> </div>
</section> </section>
</article> </article>
<HomeCanvas textsToCanvas={canvasElems}/> <HomeCanvas textsToCanvas={canvasElems} imgsToCanvas={imgElems}/>
<div class="canvasResizeToThis"></div>
<style lang="scss"> <style lang="scss">
.canvasResizeToThis {
position: fixed;
top: -10vh;
left: -10vw;
width: 120vw;
height: 120vh;
pointer-events: none;
z-index: -1;
}
.scroller { .scroller {
font-size: clamp(32px, 4.5vw, 4.5vw); font-size: clamp(32px, 4.5vw, 4.5vw);
} }
@ -99,13 +125,16 @@
scroll-snap-align: start; scroll-snap-align: start;
box-sizing: border-box; box-sizing: border-box;
padding: var(--spacing-outer); padding: var(--spacing-outer);
overflow: hidden; min-height: 100svh;
display: flex;
flex-direction: column;
gap: var(--spacing-outer);
justify-content: center;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
padding: var(--spacing-outer) calc(var(--spacing-outer) * 2.5); max-width: 75vw;
} margin: 0 auto;
&:last-child{ gap: 0;
padding-bottom: 50svh;
} }
} }
.splash { .splash {
@ -114,14 +143,37 @@
justify-content: start; justify-content: start;
min-height: 100svh; min-height: 100svh;
justify-content: center; justify-content: center;
padding: var(--spacing-outer);
margin-bottom: -1em; margin-bottom: -1em;
max-width: 100%;
padding: var(--spacing-outer);
@media screen and (min-width: 768px) {
padding: var(--spacing-outer) calc(var(--spacing-outer) * 2);
}
}
.intro-image {
position:relative;
left: 0;
text-align: center;
display: block;
margin: 0 0 -.5em 0;
z-index: -2;
}
.design {
overflow: hidden;
}
.design-illu {
position:relative;
left: 0;
width: 40%;
margin: 0 auto;
text-align: center;
display: block;
margin-bottom: -1em;
z-index: -2;
} }
h1, h2 { h1, h2 {
line-height: 1.1; line-height: 1.1;
letter-spacing: -0.025em;
font-weight: 400;
font-style: normal;
visibility: hidden; visibility: hidden;
margin: 0; margin: 0;
-webkit-touch-callout: none; /* Safari */ -webkit-touch-callout: none; /* Safari */
@ -131,28 +183,44 @@
user-select: none; user-select: none;
} }
h1 { h1 {
letter-spacing: -0.05em; line-height: 1;
line-height: .9; font-size: 11vw;
font-size: 17vw;
margin-top: -.5em; margin-top: -.5em;
// text-align: center; letter-spacing: -0.05em;
opacity: 0;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
font-size: 12vw; font-size: 9vw;
line-height: .9;
}
& em {
color: var(--color-highlight);
font-style: normal;
} }
} }
h2 { h2 {
font-size: 1.25em; font-size: 1.5em;
font-weight: 800; letter-spacing: -0.033em;
font-style: italic; margin-bottom: 0;
margin-bottom: .5em; line-height: .9;
& em {
color: var(--color-highlight);
font-style: normal;
}
} }
p { .toCanvas {
font-size: 0.7em; visibility: hidden;
font-size: .66em;
margin: 1.25em 0 0.25em 0;
-webkit-touch-callout: none; /* Safari */ -webkit-touch-callout: none; /* Safari */
-webkit-user-select: none; /* Chrome */ -webkit-user-select: none; /* Chrome */
-moz-user-select: none; /* Firefox */ -moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */ -ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; user-select: none;
@media screen and (min-width: 768px) {
font-size: 0.5em;
}
} }
a { a {
-webkit-touch-callout: none; /* Safari */ -webkit-touch-callout: none; /* Safari */
@ -161,4 +229,15 @@
-ms-user-select: none; /* Internet Explorer/Edge */ -ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; user-select: none;
} }
.cta {
margin-top: 0em;
padding-top: 0em;
text-align: center;
@media screen and (min-width: 768px) {
// background-color: var(--color-bg);
// border-top: 1px solid var(--color-text);
padding-top: 1em;
margin-top: 2em;
}
}
</style> </style>

View file

@ -0,0 +1,53 @@
<script lang='ts'>
import * as PIXI from 'pixi.js';
import { onMount } from 'svelte';
import { gsap } from 'gsap';
onMount( async () => {
// const canvas = document.querySelector('canvas') as HTMLCanvasElement;
// const app = new PIXI.Application({
// backgroundColor: 0x000000,
// backgroundAlpha: 0,
// resizeTo: window,
// antialias: true,
// resolution: 2,
// view: canvas
// })
// const imageurl = 'work/peak/peak_hero.png'
// // create a PIXI texture and create one sprite per quarter of the original image of the texture
// const texture = await PIXI.Texture.from(imageurl)
// texture.baseTexture.width = window.innerWidth
// texture.baseTexture.height = window.innerWidth / 1.5
// const rows = 50
// const cols = 50
// for (let i = 0; i < rows; i++) {
// for (let j = 0; j < cols; j++) {
// const thisTexture = new PIXI.Texture(texture.baseTexture, new PIXI.Rectangle(
// j * window.innerWidth / cols,
// i * window.innerHeight / rows,
// window.innerWidth / cols,
// window.innerHeight / rows
// ))
// const sprite = new PIXI.Sprite(thisTexture)
// sprite.width = window.innerWidth / cols
// sprite.height = window.innerHeight / rows
// sprite.x = sprite.width * j
// sprite.y = sprite.height * i
// app.stage.addChild(sprite)
// }
// }
})
</script>
<article>
<h1>Hello world</h1>
<p>Is this the text you're looking for?</p>
</article>
<canvas></canvas>
<style src="./about.scss" lang="scss"></style>

View file

@ -0,0 +1,10 @@
article {
padding: var(--spacing-outer);
}
canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

View file

@ -0,0 +1,176 @@
<script lang="ts">
import { onMount } from 'svelte';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
import Faq from '$lib/components/Faq.svelte';
import ServiceCanvas from './ServiceCanvas.svelte';
onMount( () => {
gsap.registerPlugin( ScrollTrigger );
let introTl = gsap.timeline({
paused: true,
});
introTl.fromTo('h1', {
opacity: 0, yPercent: 200
},{
opacity: 1, yPercent: 0,
duration: .75, ease: 'back.out(.75)'
}, 0.1)
introTl.play();
gsap.to('.services', {
autoAlpha: 1,
scrollTrigger: {
trigger: 'article',
start: 'top top',
end: '200px top',
scrub: true,
// markers: true,
}
})
return () => {
ScrollTrigger.getAll().forEach( (trigger) => {
trigger.kill();
});
gsap.killTweensOf('canvas');
gsap.killTweensOf('h1');
gsap.killTweensOf('section');
gsap.killTweensOf('.services');
}
})
</script>
<ServiceCanvas />
<article>
<h1>What I will (and won't) do to earn a living</h1>
<div class="services">
<section>
<h2>Web Development</h2>
<div class="service-content">
<ul class="bullets">
<li><em>Consultation</em> on the best technology solutions for your situation (eg CMS, frontend frameworks, etc)</li>
<li><em>Advice</em> on how to enhance the user experience through savvy use of technology</li>
<li><em>Development</em> in HTML/JS/CSS and/or whichever framework is best suited to your project</li>
</ul>
<div class="tech">
<h3>FAQs</h3>
<Faq summary="What kind of websites do you create?">
<p>In frontend work, I blend professionalism and creativity. My aim is simple: bring your ideas to life. Projects include:</p>
<ul>
<li>Marketing websites</li>
<li>E-commerce websites</li>
<li>Mobile web apps</li>
<li>Interactive online comics</li>
<li>Browser games</li>
</ul>
<p>I center on crafting interfaces that dazzle visually and deliver an instinctive user journey. The essence is to make your users feel at home in the interaction with your content.</p>
<p>Should your venture demand a backend touch, like managing databases or Content Management, I'm well-versed in leveraging existing open source solutions. I advocate for savvy fixes, seamlessly tailored to harmonize with your project.</p>
</Faq>
<Faq summary="What kind of websites do you NOT create?">
<p>As a frontend developer, I'm not your guy for the intricate machinery that powers colossal enterprise web applications. Put simply, I can't whip up an Amazon or a TikTok from the ground up.</p>
<p>Moreover, my moral code is steadfast. Requests involving, but not confined to, promoting weapons manufacturers or propagating conspiracy theories won't find a home with me. I must politely decline such propositions.</p>
</Faq>
<Faq summary="Which technologies and frameworks do you use/support?">
<p>A web browser grasps just HTML, CSS, and Javascript. Mastery of these is the bedrock for crafting top-notch web applications.</p>
<p>Yet, I've treaded diverse coding landscapes, navigating the realms of PHP, Perl, and Python. Among the myriad frameworks danced with, names like React, Svelte, Eleventy, Astro, and the esteemed Ruby on Rails echo.</p>
<p>I serve as your counsel, steering you toward the optimal solution tailored to your project's idiosyncrasies.</p>
<p>Should you possess a standing website, yearning for expansion, toss me the code, and we'll unravel the possibilities together. Not encountered a site I couldn't tame, so far.</p>
<p>And, sometimes, the most fitting scaffold is none at all. I crafted some elegant, straightforward websites in the raw embrace of HTML, CSS, and JS.</p>
</Faq>
<Faq summary="Which Content Management System (CMS) do you recommend?">
<p>I've tinkered with various Content Management Systems — the likes of WordPress, Strapi, Builder, Magento, and Shopify. Each carries its own set of virtues and vices.</p>
<p>Let's talk about the folks responsible for constructing and upkeeping your content. Only then can we jointly discern the optimal solution.</p>
</Faq>
</div>
</div>
</section>
<section>
<h2>UX/Visual Design</h2>
<div class="service-content">
<ul class="bullets">
<li><em>Concept & Mockup</em><br>In a collaborative effort we shall unearth the possibilities your brief holds. Then decide which road to follow down to </li>
<li><em>Prototyping</em> for interactive products, to gain understanding of the user experience prior to production</li>
<li><em>Illustration & animation</em> to bring your ideas to life</li>
<li><em>Data visualisation</em> to aid crucial information cross the seas of abstraction</li>
</ul>
<div class="tech">
<h3>FAQs</h3>
<Faq summary="What do you design?">
<p>Primarily, I craft beautiful web experiences for my clients, aiming to seize their audience's imagination.</p>
<p>I first was schooled in the art of graphic design. Over time, my focus shifted towards web projects, pulling me into the worlds of development and more UX/interaction-centric design.</p>
<p>Beyond websites and user interfaces, I've crafted promotional posters and publications for print, as well as entire Housestyles for budding brands.</p>
<p>And, well, I'm also an Illustrator, but that's a tale of its own. You can follow it <a href="https://instagram.com/floter.ink">on instagram</a>.</p>
</Faq>
<Faq summary="What do you NOT design?">
<p>Despite doing animations for websites, mostly achieved through code, I am not a traditional motion designer. If you require a static video file as final product, you will want to look for someone with skills in video editing and motion design software such as After Effects.</p>
<p>However it is easy to add animations made through such a process to a website and integrate them with the rest of the content.</p>
</Faq>
<Faq summary="What do you require to start designing?">
<p>A good brief includes all limitations and aspirations of your project, your businesses proposition, values and intentions as well as any information you have on your target audience. References to competitors and examples of similar products you like are very helpful as well. Generally though, it all starts with a chat between you and yours truly.</p>
</Faq>
</div>
</div>
</section>
</div>
</article>
<style lang="scss">
article {
margin: auto;
max-width: 1200px;
padding: calc(50vh - var(--spacing-outer) - 35vw) var(--spacing-outer) var(--spacing-outer) var(--spacing-outer);
@media screen and (min-width: 768px) {
padding: calc(50vh - var(--spacing-outer) - 12vw) var(--spacing-outer) var(--spacing-outer) var(--spacing-outer);
}
}
h1 {
font-size: 14vw;
@media screen and (min-width: 768px) {
font-size: 8vw;
letter-spacing: -0.045em;
}
}
.services {
opacity: 0; //changed in ServiceCanvas
}
.service-content {
@media screen and (min-width: 768px) {
display: flex;
gap: 1.5em;
}
}
.service-content > :first-child {
flex: 0 0 40%;
}
.service-content > *,
.service-content > * > :first-child{
margin-top: 0;
padding-top: 0;
}
h2 {
border-bottom: 1px solid;
padding-bottom: .5em;
}
em {
font-weight: 800;
color: var(--color-highlight);
}
ul li {
margin-bottom: .75em;
line-height: 1.25;
}
li, p {
font-size: 1.15em;
}
</style>

View file

@ -0,0 +1,189 @@
<script lang="ts">
import * as PIXI from 'pixi.js';
import { BulgePinchFilter } from 'pixi-filters';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
import { onMount } from 'svelte';
let canvas: HTMLCanvasElement;
let introDone = false;
onMount( () => {
let is_fine = window.matchMedia('(pointer:fine)').matches
let is_landscape = window.matchMedia('(orientation:landscape)').matches
gsap.registerPlugin(ScrollTrigger);
let app = new PIXI.Application({
resizeTo: window,
antialias: true,
autoDensity: true,
resolution: 2,
backgroundColor: 'rgb(255, 255, 255)',
backgroundAlpha: 0,
view: canvas,
});
let textgroup = new PIXI.Container();
textgroup.pivot.set(0, 0);
textgroup.x = 0;
textgroup.y = - window.innerHeight;
textgroup.height = window.innerHeight;
textgroup.width = window.innerWidth;
app.stage.addChild(textgroup);
let tweens: Array<GSAPTween> = [];
let fontSize = window.innerHeight / 3;
function createText(string: string){
let text = new PIXI.Text(string,
{ fontFamily: 'Stratos',
fontSize: fontSize,
// fontWeight: '800',
lineHeight: 0,
letterSpacing: -20,
fill: `#000`,
padding: 0
}
);
text.anchor.set(0);
textgroup.addChild(text);
return text
}
let allTexts = [
createText('SERVICES SERVICES '), createText('SERVICES SERVICES '),
createText('CONSULTATION DESIGN WEB DEVELOPMENT '), createText('CONSULTATION DESIGN WEB DEVELOPMENT '),
createText('SERVICES SERVICES '), createText('SERVICES SERVICES '),
createText('CONSULTATION DESIGN WEB DEVELOPMENT '), createText('CONSULTATION DESIGN WEB DEVELOPMENT ')
]
let textRows = [
[allTexts[0], allTexts[1]],
[allTexts[2], allTexts[3]],
[allTexts[4], allTexts[5]],
[allTexts[6], allTexts[7]]
]
textRows.forEach( (row, index) => {
if (index % 2 === 0) {
row[0].x = 0;
row[1].x = row[0].width;
} else {
row[0].x = -row[0].width;
row[1].x = 0;
}
row[0].y = (fontSize * 0.8 * index);
row[1].y = (fontSize * 0.8 * index);
})
let textRowsright = gsap.to([textRows[0], textRows[2]], {
x: '+=' + -textRows[0][0].width,
duration: 10,
ease: 'none',
repeat: -1,
overwrite: true
})
tweens.push(textRowsright);
let textRowsLeft = gsap.to([textRows[1], textRows[3]], {
x: '+=' + textRows[1][0].width,
duration: 10,
ease: 'none',
repeat: -1,
overwrite: true
})
tweens.push(textRowsLeft);
//move textgroup so left side is offscreen
textgroup.x = -textRows[0][0].width/4;
textgroup.rotation = -0.2;
textgroup.alpha = 0;
let bulgefilter = new BulgePinchFilter();
bulgefilter.radius = is_landscape ? window.innerWidth / 2 : window.innerWidth;
bulgefilter.strength = .66;
bulgefilter.center = new PIXI.Point(0.5, 0.5);
app.stage.filters = [bulgefilter];
let textgroupIn = gsap.to(textgroup, {
y: is_landscape ? textRows[0][0].height * 0.4 : textRows[0][0].height * 0.15,
alpha: 1,
duration: 1.5,
ease: 'power4.out',
overwrite: true,
onComplete: () => {
introDone = true;
createScrollTrigger();
}
})
tweens.push(textgroupIn);
let mouse = { x: 0.5, y: 0.5 };
window.addEventListener('mousemove', (e) => {
gsap.to(mouse, {
x: e.clientX / window.innerWidth,
duration: 1,
ease: 'power3.out',
overwrite: true
})
mouse.y = e.clientY / window.innerHeight;
})
let elapsed = 0;
app.ticker.add((delta) => {
elapsed += delta;
bulgefilter.center = new PIXI.Point(mouse.x, 0.5);
})
function createScrollTrigger() {
gsap.to([textRows[0], textRows[1]], {
y: '+=' + -textRows[0][0].height * 0.9,
duration: 1,
ease: 'none',
scrollTrigger: {
trigger: 'article',
start: 'top top',
end: '200px top',
scrub: true,
// markers: true,
}
})
gsap.to([textRows[2], textRows[3]], {
y: '+=' + textRows[0][0].height * 0.9,
duration: 1,
ease: 'none',
scrollTrigger: {
trigger: 'article',
start: 'top top',
end: '200px top',
scrub: true,
// markers: true,
}
})
}
return () => {
app.destroy(true, { children: true, texture: true, baseTexture: true });
tweens.forEach( tween => tween.kill() );
}
})
</script>
<canvas bind:this={canvas} id="service-canvas"></canvas>
<style>
#service-canvas {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
/* z-index: 2; */
pointer-events: none;
}
</style>

View file

@ -1,13 +1,15 @@
<script lang="ts"> <script lang="ts">
import WorkCanvas from '$lib/components/WorkCanvas.svelte'; import WorkCanvas from '$lib/components/WorkCanvas.svelte';
import { onDestroy, onMount } from 'svelte'; import { onMount } from 'svelte';
import { workClickHandler, initWorkPage } from './workUtils.js'; import { workClickHandler, initWorkPage } from './workUtils.js';
import { workbulge } from '$lib/utils/stores.js'; import { workbulge } from '$lib/utils/stores.js';
import { CldImage } from 'svelte-cloudinary'; import { CldImage } from 'svelte-cloudinary';
import { browser } from '$app/environment';
import { fade } from 'svelte/transition';
export let data; export let data;
const orderedPosts = data.posts.sort((a, b) => {
return a.meta.order - b.meta.order;
});
let canvasTextElems: Array<HTMLElement>; let canvasTextElems: Array<HTMLElement>;
let canvasImgElems: Array<HTMLElement>; let canvasImgElems: Array<HTMLElement>;
let bulge = {factor: 0}; let bulge = {factor: 0};
@ -18,40 +20,52 @@
onMount(() => { onMount(() => {
const headline: HTMLElement = document.querySelector('.headline') as HTMLElement; const headline: HTMLElement = document.querySelector('.headline') as HTMLElement;
const headlines: Array<HTMLElement> = Array.from(document.querySelectorAll('h2, li'));
const images: Array<HTMLElement> = Array.from(document.querySelectorAll('.work img')); const images: Array<HTMLElement> = Array.from(document.querySelectorAll('.work img'));
let canvasElems = initWorkPage( headline, images ); let canvasElems = initWorkPage( headlines, images );
canvasTextElems = canvasElems.text as Array<HTMLElement>; canvasTextElems = canvasElems.text as Array<HTMLElement>;
canvasImgElems = canvasElems.images; canvasImgElems = canvasElems.images;
}); });
</script> </script>
<div class="works-wrapper">
<h1 class="headline"><span>Happy Clients</span></h1> <h1 class="headline"><span>Outstanding work</span></h1>
<div class="works"> <div class="works">
{#each data.posts as work, i} {#each orderedPosts as work, i}
<a <a
data-sveltekit-preload-data data-sveltekit-preload-data
href="{work.path}" href="{work.path}"
class="work" class="work"
on:click={ (e) => workClickHandler(e) } on:click={ (e) => workClickHandler(e) }
> >
<CldImage <CldImage
src={work.meta.header_bg_image} src={work.meta.header_bg_image}
sizes="(min-width: 768px) 20vw, 50vw" sizes={ i === 0 ? `(min-width: 768px) 60vw, 50vw` : `(min-width: 768px) 20vw, 50vw`}
alt={work.meta.title} alt={work.meta.title}
width="2100" width="2100"
height="1400" height="1400"
objectFit="fill" objectFit="fill"
loading= {i < 10 ? "eager" : "lazy"} loading= "lazy"
/> />
<h2>{work.meta.title}</h2> <div class="work-info">
</a> <h2 class="title"><span class="title-words">{work.meta.title}</span></h2>
{/each} {#if work.meta.tags}
</div> <ul class="tags">
<WorkCanvas {#each work.meta.tags as tag, index}
textsToCanvas={canvasTextElems} <li class="tag">{tag}{index < work.meta.tags.length-1 ? ' | ' : ''}</li>
imgsToCanvas={canvasImgElems} {/each}
bulgeFactor={bulge.factor} </ul>
/> {/if}
</div>
</a>
{/each}
</div>
<WorkCanvas
textsToCanvas={canvasTextElems}
imgsToCanvas={canvasImgElems}
bulgeFactor={bulge.factor}
/>
</div>
<style src="./work.scss" lang="scss"></style> <style src="./work.scss" lang="scss"></style>

View file

@ -1,7 +1,7 @@
export async function load( { params }: { params: { slug: string }} ){ export async function load( { params }: { params: { slug: string }} ){
try { try {
const post = await import(`../md/${params.slug}.md`) const post = await import(`../md/${params.slug}.md`)
const { title, date, header_bg_image, svg, video } = post.metadata const { title, date, header_bg_image, svg, video, tags } = post.metadata
const Content = post.default.render() const Content = post.default.render()
return { return {
@ -10,6 +10,7 @@ export async function load( { params }: { params: { slug: string }} ){
header_bg_image, header_bg_image,
svg, svg,
video, video,
tags,
Content, Content,
} }
} catch (error) { } catch (error) {

View file

@ -17,7 +17,7 @@
gsap.to('.work', { gsap.to('.work', {
xPercent: -100, xPercent: -100,
duration: .4, duration: .6,
ease: "expo.out", ease: "expo.out",
delay: .2 delay: .2
}) })
@ -26,8 +26,8 @@
gsap.to('.heromask', { gsap.to('.heromask', {
clipPath: "polygon(0 0, 60% 0, 35% 100%, 0% 100%)", clipPath: "polygon(0 0, 60% 0, 35% 100%, 0% 100%)",
duration: .6, duration: 1,
ease: "cubic.inOut", ease: "power4.out",
onStart: () => { onStart: () => {
setTimeout(() => { setTimeout(() => {
document.querySelector('.coverclone')?.remove(); document.querySelector('.coverclone')?.remove();
@ -35,12 +35,12 @@
}, },
onComplete: () => { onComplete: () => {
gsap.to('.heromask', { gsap.to('.heromask', {
ease: "power1.inOut", ease: "none",
clipPath: "polygon(0 0, 50% 0, 50% 100%, 0% 100%)", clipPath: "polygon(0 0, 50% 0, 50% 100%, 0% 100%)",
scrollTrigger: { scrollTrigger: {
trigger: '.work', trigger: '.work',
start: '0% top', start: 'top top',
end: `100px top`, end: `200px top`,
scrub: true scrub: true
} }
}) })
@ -138,6 +138,13 @@
<article class="work"> <article class="work">
{#if visible} {#if visible}
<div class="work-content"> <div class="work-content">
{#if data.tags != undefined && data.tags.length > 0 }
<div class="tags">
{#each data.tags as tag }
<div class="tag">{tag}</div>
{ /each }
</div>
{/if}
<h1><span class="svg-logo">{@html data.svg}</span><span class="name">{data.title}</span></h1> <h1><span class="svg-logo">{@html data.svg}</span><span class="name">{data.title}</span></h1>
<div class="work-content-text"> <div class="work-content-text">
{@html data.Content.html} {@html data.Content.html}
@ -152,8 +159,8 @@
min-height: 100svh; min-height: 100svh;
overflow: hidden; overflow: hidden;
box-sizing: border-box; box-sizing: border-box;
// background-color: var(--color-bg);
transform: translateY(100%); transform: translateY(100%);
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
transform: translateX(100%); transform: translateX(100%);
} }
@ -167,6 +174,7 @@
& a { & a {
text-decoration: none; text-decoration: none;
color: var(--color-highlight);
} }
} }
.heromask { .heromask {
@ -196,10 +204,9 @@
z-index: 1; z-index: 1;
color: var(--color-text); color: var(--color-text);
& :last-child { & > :last-child {
margin-bottom: 100px; margin-bottom: 100px;
} }
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
margin-left: 40vw; margin-left: 40vw;
max-width: 60vw; max-width: 60vw;
@ -208,19 +215,14 @@
padding-right: calc(var(--spacing-outer) * 2.5); padding-right: calc(var(--spacing-outer) * 2.5);
} }
} }
.work-content-text {
@media screen and (min-width: 768px) {
border-top: 1px solid var(--color-text);
}
}
h1 { h1 {
position: relative; position: relative;
z-index: 1; z-index: 1;
margin: 0; margin: 0;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
padding: 0 0 1em 0; padding: 0 0 1em 0;
} }
& .name { & .name {
display: none; display: none;
} }
@ -237,6 +239,37 @@
} }
} }
} }
.tags {
padding-bottom: .25em;
font-size: 1em;
margin-bottom: 2em;
line-height: 1.1;
&:after {
content: '';
display: block;
width: calc(100% + var(--spacing-outer) * 2.5);
height: 1px;
background-color: var(--color-text);
margin-top: .5em;
}
}
.tag {
display: inline-block;
margin-right: .5em;
padding: .125em 0;
font-weight: 400;
text-transform: uppercase;
letter-spacing: -.005em;
&:after {
content: ','
}
&:last-child:after {
content: none
}
}
:global(.header-nav){ :global(.header-nav){
transition: all .3s cubic-bezier(0.075, 0.82, 0.165, 1); transition: all .3s cubic-bezier(0.075, 0.82, 0.165, 1);
} }

View file

@ -2,8 +2,12 @@
title: Adidas title: Adidas
header_bg_image: adidas_hero_ceurd8 header_bg_image: adidas_hero_ceurd8
order: 12 order: 12
tags: ['graphic design', 'illustration']
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. 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 id="adidas-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1000 674.2" style="enable-background:new 0 0 1000 674.2; fill: currentColor" xml:space="preserve"><path d="M654.5 442.2 448.9 84.8 596.6 0l255.7 442.2H654.5"/><path d="m106.8 392.1 147.7-85.4 78.2 135.5H135.5l-28.7-50.1"/><path d="M396.7 670.2h42V500.1h-42v170.1z"/><path d="M923.6 674.2c-47 0-75.3-24.3-76.8-58.5h44.3c0 10.7 6.7 26.4 35.4 26.9 19.1 0 28.1-11.3 28.1-19.7-1.1-13.4-18-14.5-35.9-17.4-18-2.9-33.3-6.1-44.3-11.8-14.1-7.3-23.7-22.9-23.7-40.9 0-30.4 26.4-54.5 70.3-54.5 42.6 0 69.6 22.4 72.4 55.6h-42.8c-.4-9-2.1-23.1-27.3-23.1-17 0-28.3 3.4-29.2 15.3 0 17.4 35.4 16.2 62.9 23.5 26.4 6.7 43.2 23.1 43.2 46.1-.2 42.2-34.4 58.5-76.6 58.5"/><path d="m280 240.4 147.7-85.2 165.7 287H438.8v42h-42V442L280 240.4"/><path class="st0" d="M283.8 674.2c-48.9 0-88.7-39.9-88.7-88.3 0-48.9 39.7-87.5 88.7-87.5 18.5 0 35.4 5 50.1 15.1v-71.3h42v228h-42v-11.3c-14.8 9.6-31.6 15.3-50.1 15.3zm-48.4-88.3c0 26.4 22.5 48.3 49.5 48.3 26.4 0 48.9-22 48.9-48.3 0-26.4-22.5-48.9-48.9-48.9-26.9 0-49.5 22.5-49.5 48.9"/><path class="st0" d="M594.5 442.2H636v228h-41.5v-11.3c-14.1 9.6-31.5 15.3-50.6 15.3-48.3 0-88.1-39.9-88.1-88.3 0-48.9 39.7-87.5 88.1-87.5 19.1 0 35.9 5 50.6 15.1v-71.3zm-97.8 143.7c0 26.4 22.5 48.3 48.3 48.3 26.9 0 49.5-22 49.5-48.3 0-26.4-22.5-48.9-49.5-48.9-25.8 0-48.3 22.5-48.3 48.9"/><path class="st0" d="M738.2 674.2c-48.2 0-88.1-39.9-88.1-88.3 0-48.9 39.9-87.5 88.1-87.5 18.5 0 35.9 5 50.1 15.1v-13.6h42v170.3h-42v-11.3c-14.2 9.6-31 15.3-50.1 15.3zM691 585.9c0 26.4 22.5 48.3 48.9 48.3s48.3-22 48.3-48.3c0-26.4-22-48.9-48.3-48.9-26.4 0-48.9 22.5-48.9 48.9"/><path class="st0" d="M40.5 585.9c0 26.4 22.5 48.3 48.9 48.3 26.9 0 49.5-22 49.5-48.3 0-26.4-22.5-48.9-49.5-48.9-26.3 0-48.9 22.5-48.9 48.9zm47.8 88.3c-48.4 0-88.3-40-88.3-88.3 0-48.9 39.9-87.5 88.3-87.5 18.5 0 35.9 5 50.6 15.1v-13.6h41.5v170.3h-41.5v-11.3c-14.1 9.6-31.5 15.3-50.6 15.3"/></svg>' svg: '<svg id="adidas-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1000 674.2" style="enable-background:new 0 0 1000 674.2; fill: currentColor" xml:space="preserve"><path d="M654.5 442.2 448.9 84.8 596.6 0l255.7 442.2H654.5"/><path d="m106.8 392.1 147.7-85.4 78.2 135.5H135.5l-28.7-50.1"/><path d="M396.7 670.2h42V500.1h-42v170.1z"/><path d="M923.6 674.2c-47 0-75.3-24.3-76.8-58.5h44.3c0 10.7 6.7 26.4 35.4 26.9 19.1 0 28.1-11.3 28.1-19.7-1.1-13.4-18-14.5-35.9-17.4-18-2.9-33.3-6.1-44.3-11.8-14.1-7.3-23.7-22.9-23.7-40.9 0-30.4 26.4-54.5 70.3-54.5 42.6 0 69.6 22.4 72.4 55.6h-42.8c-.4-9-2.1-23.1-27.3-23.1-17 0-28.3 3.4-29.2 15.3 0 17.4 35.4 16.2 62.9 23.5 26.4 6.7 43.2 23.1 43.2 46.1-.2 42.2-34.4 58.5-76.6 58.5"/><path d="m280 240.4 147.7-85.2 165.7 287H438.8v42h-42V442L280 240.4"/><path class="st0" d="M283.8 674.2c-48.9 0-88.7-39.9-88.7-88.3 0-48.9 39.7-87.5 88.7-87.5 18.5 0 35.4 5 50.1 15.1v-71.3h42v228h-42v-11.3c-14.8 9.6-31.6 15.3-50.1 15.3zm-48.4-88.3c0 26.4 22.5 48.3 49.5 48.3 26.4 0 48.9-22 48.9-48.3 0-26.4-22.5-48.9-48.9-48.9-26.9 0-49.5 22.5-49.5 48.9"/><path class="st0" d="M594.5 442.2H636v228h-41.5v-11.3c-14.1 9.6-31.5 15.3-50.6 15.3-48.3 0-88.1-39.9-88.1-88.3 0-48.9 39.7-87.5 88.1-87.5 19.1 0 35.9 5 50.6 15.1v-71.3zm-97.8 143.7c0 26.4 22.5 48.3 48.3 48.3 26.9 0 49.5-22 49.5-48.3 0-26.4-22.5-48.9-49.5-48.9-25.8 0-48.3 22.5-48.3 48.9"/><path class="st0" d="M738.2 674.2c-48.2 0-88.1-39.9-88.1-88.3 0-48.9 39.9-87.5 88.1-87.5 18.5 0 35.9 5 50.1 15.1v-13.6h42v170.3h-42v-11.3c-14.2 9.6-31 15.3-50.1 15.3zM691 585.9c0 26.4 22.5 48.3 48.9 48.3s48.3-22 48.3-48.3c0-26.4-22-48.9-48.3-48.9-26.4 0-48.9 22.5-48.9 48.9"/><path class="st0" d="M40.5 585.9c0 26.4 22.5 48.3 48.9 48.3 26.9 0 49.5-22 49.5-48.3 0-26.4-22.5-48.9-49.5-48.9-26.3 0-48.9 22.5-48.9 48.9zm47.8 88.3c-48.4 0-88.3-40-88.3-88.3 0-48.9 39.9-87.5 88.3-87.5 18.5 0 35.9 5 50.6 15.1v-13.6h41.5v170.3h-41.5v-11.3c-14.1 9.6-31.5 15.3-50.6 15.3"/></svg>'
--- ---
# adidas is all in
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. 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.

View file

@ -3,6 +3,7 @@ title: Formo.bio
header_bg_image: formo_hero_xgb6xo header_bg_image: formo_hero_xgb6xo
video: /work/formo/formo-rec.webm video: /work/formo/formo-rec.webm
order: 12 order: 12
tags: ['tech consultancy', 'web development', 'UX Design']
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. 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" viewBox="0 0 70 20" style="enable-background:new 0 0 70 20" xml:space="preserve"><path d="m3.4 5.6 7.9-3.3c.1 0 .1-.1.1-.2l-.9-2c-.1-.1-.2-.1-.2-.1L2.4 3.3C.9 3.9 0 5.3 0 6.9v12.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.7c.2.1.3.1.5.2l7.2 1.8c.1 0 .1 0 .1-.1l.6-2.1c0-.1 0-.1-.1-.1L3.6 8.3C2.7 8 2.5 7.2 2.5 7s0-1 .9-1.4zm59.7.7c-3.8 0-6.9 3-6.9 6.8s3.1 6.8 6.9 6.8 6.9-3 6.9-6.8-3.1-6.8-6.9-6.8zm0 11.1c-2.4 0-4.4-1.9-4.4-4.3s2-4.3 4.4-4.3 4.4 1.9 4.4 4.3-2 4.3-4.4 4.3zM18.8 6.3c-3.8 0-6.9 3-6.9 6.8s3.1 6.8 6.9 6.8 6.9-3 6.9-6.8-3.1-6.8-6.9-6.8zm0 11.1c-2.4 0-4.4-1.9-4.4-4.3s2-4.3 4.4-4.3 4.4 1.9 4.4 4.3-2 4.3-4.4 4.3zM53.1 7.1c-.9-.7-2-.9-3-.6l-3.2.9c-.3.1-.6.2-.9.4-.2-.3-.4-.5-.7-.7-.9-.7-2-.9-3-.6l-3.3.9c-1.6.4-2.7 1.9-2.7 3.5v8.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.3c0-.5.4-1 .9-1.1l3.2-.9c.4-.1.7.1.8.2.3.2.4.5.4.8v9.4c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1V11c0-.5.4-1 .9-1.1l3.2-.9c.4-.1.7.1.8.2.3.2.4.5.4.8v9.4c0 .1.1.1.1.1H54c.1 0 .1 0 .1-.1V9.9c.4-1.1-.1-2.1-1-2.8zm-23 .3c-1.6.4-2.7 1.9-2.7 3.5v8.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.3c0-.5.4-1 .9-1.1l4.6-1.3c.1 0 .1-.1.1-.1l-.6-2.1c0-.1-.1-.1-.1-.1l-4.6 1.2z" style="fill:currentColor"/></svg>' svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 20" style="enable-background:new 0 0 70 20" xml:space="preserve"><path d="m3.4 5.6 7.9-3.3c.1 0 .1-.1.1-.2l-.9-2c-.1-.1-.2-.1-.2-.1L2.4 3.3C.9 3.9 0 5.3 0 6.9v12.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.7c.2.1.3.1.5.2l7.2 1.8c.1 0 .1 0 .1-.1l.6-2.1c0-.1 0-.1-.1-.1L3.6 8.3C2.7 8 2.5 7.2 2.5 7s0-1 .9-1.4zm59.7.7c-3.8 0-6.9 3-6.9 6.8s3.1 6.8 6.9 6.8 6.9-3 6.9-6.8-3.1-6.8-6.9-6.8zm0 11.1c-2.4 0-4.4-1.9-4.4-4.3s2-4.3 4.4-4.3 4.4 1.9 4.4 4.3-2 4.3-4.4 4.3zM18.8 6.3c-3.8 0-6.9 3-6.9 6.8s3.1 6.8 6.9 6.8 6.9-3 6.9-6.8-3.1-6.8-6.9-6.8zm0 11.1c-2.4 0-4.4-1.9-4.4-4.3s2-4.3 4.4-4.3 4.4 1.9 4.4 4.3-2 4.3-4.4 4.3zM53.1 7.1c-.9-.7-2-.9-3-.6l-3.2.9c-.3.1-.6.2-.9.4-.2-.3-.4-.5-.7-.7-.9-.7-2-.9-3-.6l-3.3.9c-1.6.4-2.7 1.9-2.7 3.5v8.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.3c0-.5.4-1 .9-1.1l3.2-.9c.4-.1.7.1.8.2.3.2.4.5.4.8v9.4c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1V11c0-.5.4-1 .9-1.1l3.2-.9c.4-.1.7.1.8.2.3.2.4.5.4.8v9.4c0 .1.1.1.1.1H54c.1 0 .1 0 .1-.1V9.9c.4-1.1-.1-2.1-1-2.8zm-23 .3c-1.6.4-2.7 1.9-2.7 3.5v8.3c0 .1.1.1.1.1h2.2c.1 0 .1-.1.1-.1v-8.3c0-.5.4-1 .9-1.1l4.6-1.3c.1 0 .1-.1.1-.1l-.6-2.1c0-.1-.1-.1-.1-.1l-4.6 1.2z" style="fill:currentColor"/></svg>'
--- ---

View file

@ -3,6 +3,7 @@ title: JustPeace Labs
header_bg_image: jpl_hero_eukxaw header_bg_image: jpl_hero_eukxaw
description: JustPeace Labs is a non-profit organization that works with local communities to build peace and prevent violence. description: JustPeace Labs is a non-profit organization that works with local communities to build peace and prevent violence.
order: 11 order: 11
tags: ['branding', 'logo design', 'graphic design', 'illustration']
svg: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0" y="0" viewBox="0 0 240 63" style="enable-background:new 0 0 240 63" xml:space="preserve"><style>.st0{fill:currentColor}.st1{fill:currentColor}</style><g id="Layer_1-2"><path class="st0" d="M82.4 23.4c.4-2.3.6-4.7.5-7.1V3.1h4.6v13.1c.1 2.5 0 5-.3 7.5-.8 4.1-4.9 6-7.4 6.1l-1.1-2.4c1.9-.6 3.3-2.1 3.7-4zM92 3.1h4.5v12.3c0 5.1 1.6 6.2 4.4 6.2s4.3-1.3 4.3-6.2V3.1h4.5v12.7c0 6.1-3 9.5-8.9 9.5-6.6 0-8.8-3.8-8.8-9.6V3.1zM114 20.3c1.7.9 3.7 1.4 5.7 1.4 2.4 0 3.2-.8 3.2-2.2s-.9-2.2-4.2-3.9c-2.6-1.3-5.4-3.2-5.4-6.8 0-4.3 3.5-5.9 7.7-5.9 2-.1 3.9.4 5.7 1.3l-.8 3.6c-1.4-.9-3.1-1.4-4.7-1.4-2.4 0-3.3.9-3.3 2.2 0 1.6 1.1 2.2 3.8 3.7 3.4 1.8 6 3.4 6 7 0 4-3.1 6.1-7.5 6.1-2.3 0-4.5-.4-6.6-1.3l.4-3.8zM135.3 6.6H129V3.1h17.2v3.5h-6.3V25h-4.6V6.6zM149.4 3.1h1.4c2.4 0 4.4-.2 6.5-.2 5 0 8 2.2 8 7.6 0 5-3.1 8-8.8 8H154V25h-4.6V3.1zm7 11.8c2.2 0 4.3-.9 4.3-4.6 0-2.8-1.5-4.3-4.4-4.2-.8 0-1.6.1-2.4.2v8.4c.8.2 1.6.2 2.5.2zM168.4 3.1h13.4v3.5H173V12h6.8v3.5H173v5.9h9.7V25h-14.3V3.1zM192.8 2.9h4.6l8.2 22.1h-5l-1.5-4.6H191l-1.5 4.6h-4.9l8.2-22.1zm5.3 14.2-2.4-7.5-.6-2.3-.6 2.3-2.4 7.5h6zM216.4 2.9c2 0 4 .3 6 .9l-.7 4c-1.5-.9-3.2-1.3-5-1.3-3.6 0-6.3 2.7-6.3 7.3s2.5 7.9 6.7 7.9c1.8 0 3.5-.5 5.1-1.4v3.8c-1.7.8-3.6 1.2-5.5 1.1-6.8 0-11-4.5-11-11.1 0-7.3 4.7-11.2 10.7-11.2zM225.7 3.1h13.4v3.5h-8.8V12h6.7v3.5h-6.7v5.9h9.7V25h-14.3V3.1z"/><path class="st1" d="M80.4 39h2.5v20H92v2H80.4V39zM98 52.1c2.1-.7 4.2-1 6.4-1v-1.9c0-2.7-1.4-3.1-3.8-3.1-1.7.1-3.4.5-4.8 1.4l-.6-1.6c1.8-1 3.9-1.6 6-1.6 3.3 0 5.6.9 5.6 5v11.9h-1c-.8 0-1.3-.1-1.3-1.2v-.6c-1.4 1.2-3.2 1.8-5.1 1.8-2.9 0-5-1.7-5-4.6 0-2.1 1.3-3.6 3.6-4.5zm2.2 7.3c1.5 0 3-.5 4.2-1.4v-5.3c-1.7 0-3.4.2-5.1.8-1.6.6-2.5 1.5-2.5 3 0 1.7 1 2.9 3.4 2.9zM112 37h2.4v6.8l-.1 2.5c1.3-1.3 3.1-2 5-2 3.6 0 6.5 2.6 6.5 7.8s-3.3 9.1-8.3 9.1c-1.9 0-3.8-.4-5.5-1.2V37zm5.8 22.4c2.9 0 5.5-2.3 5.6-7 0-4.1-1.6-6.3-4.7-6.3-1.6 0-3.1.6-4.2 1.7v10.9c.9.6 2.1.8 3.3.7zM129.4 58.2c1.5.8 3.1 1.2 4.7 1.2 2.1 0 3.6-.8 3.6-2.5s-2-2.5-3.9-3.3c-2.5-1-4.7-2.4-4.7-5.1s2.7-4.1 5.7-4.2c1.5 0 2.9.3 4.2.9l-.4 1.8c-1.1-.6-2.4-.9-3.7-.9-2.4 0-3.6.9-3.6 2.2 0 1.7 1.4 2.5 3.6 3.4s5 2.2 5 5-2.2 4.5-5.7 4.5c-1.8 0-3.6-.4-5.2-1.2l.4-1.8zM7.2 31.7c0-12.2 8.9-22.6 21-24.4L27.1 0C11.6 2.4.1 15.7 0 31.5c0 6.8 2.2 13.5 6.2 19l5.8-4.3C8.9 42 7.2 36.9 7.2 31.7zM17.1 51.4l-4.2 5.7c4.2 3.1 9.1 5.1 14.2 5.9l1-7c-4-.6-7.8-2.2-11-4.6zM36.5 0l-1.1 7.3c13.5 2 22.7 14.5 20.7 28-.6 3.9-2.1 7.7-4.5 10.9l5.7 4.2c4.1-5.5 6.3-12.1 6.2-19 .1-15.7-11.4-29-27-31.4zM35.5 56l1 7c5.2-.8 10-2.8 14.2-5.9l-4.2-5.7c-3.2 2.4-7 4-11 4.6z"/></g></svg>' svg: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0" y="0" viewBox="0 0 240 63" style="enable-background:new 0 0 240 63" xml:space="preserve"><style>.st0{fill:currentColor}.st1{fill:currentColor}</style><g id="Layer_1-2"><path class="st0" d="M82.4 23.4c.4-2.3.6-4.7.5-7.1V3.1h4.6v13.1c.1 2.5 0 5-.3 7.5-.8 4.1-4.9 6-7.4 6.1l-1.1-2.4c1.9-.6 3.3-2.1 3.7-4zM92 3.1h4.5v12.3c0 5.1 1.6 6.2 4.4 6.2s4.3-1.3 4.3-6.2V3.1h4.5v12.7c0 6.1-3 9.5-8.9 9.5-6.6 0-8.8-3.8-8.8-9.6V3.1zM114 20.3c1.7.9 3.7 1.4 5.7 1.4 2.4 0 3.2-.8 3.2-2.2s-.9-2.2-4.2-3.9c-2.6-1.3-5.4-3.2-5.4-6.8 0-4.3 3.5-5.9 7.7-5.9 2-.1 3.9.4 5.7 1.3l-.8 3.6c-1.4-.9-3.1-1.4-4.7-1.4-2.4 0-3.3.9-3.3 2.2 0 1.6 1.1 2.2 3.8 3.7 3.4 1.8 6 3.4 6 7 0 4-3.1 6.1-7.5 6.1-2.3 0-4.5-.4-6.6-1.3l.4-3.8zM135.3 6.6H129V3.1h17.2v3.5h-6.3V25h-4.6V6.6zM149.4 3.1h1.4c2.4 0 4.4-.2 6.5-.2 5 0 8 2.2 8 7.6 0 5-3.1 8-8.8 8H154V25h-4.6V3.1zm7 11.8c2.2 0 4.3-.9 4.3-4.6 0-2.8-1.5-4.3-4.4-4.2-.8 0-1.6.1-2.4.2v8.4c.8.2 1.6.2 2.5.2zM168.4 3.1h13.4v3.5H173V12h6.8v3.5H173v5.9h9.7V25h-14.3V3.1zM192.8 2.9h4.6l8.2 22.1h-5l-1.5-4.6H191l-1.5 4.6h-4.9l8.2-22.1zm5.3 14.2-2.4-7.5-.6-2.3-.6 2.3-2.4 7.5h6zM216.4 2.9c2 0 4 .3 6 .9l-.7 4c-1.5-.9-3.2-1.3-5-1.3-3.6 0-6.3 2.7-6.3 7.3s2.5 7.9 6.7 7.9c1.8 0 3.5-.5 5.1-1.4v3.8c-1.7.8-3.6 1.2-5.5 1.1-6.8 0-11-4.5-11-11.1 0-7.3 4.7-11.2 10.7-11.2zM225.7 3.1h13.4v3.5h-8.8V12h6.7v3.5h-6.7v5.9h9.7V25h-14.3V3.1z"/><path class="st1" d="M80.4 39h2.5v20H92v2H80.4V39zM98 52.1c2.1-.7 4.2-1 6.4-1v-1.9c0-2.7-1.4-3.1-3.8-3.1-1.7.1-3.4.5-4.8 1.4l-.6-1.6c1.8-1 3.9-1.6 6-1.6 3.3 0 5.6.9 5.6 5v11.9h-1c-.8 0-1.3-.1-1.3-1.2v-.6c-1.4 1.2-3.2 1.8-5.1 1.8-2.9 0-5-1.7-5-4.6 0-2.1 1.3-3.6 3.6-4.5zm2.2 7.3c1.5 0 3-.5 4.2-1.4v-5.3c-1.7 0-3.4.2-5.1.8-1.6.6-2.5 1.5-2.5 3 0 1.7 1 2.9 3.4 2.9zM112 37h2.4v6.8l-.1 2.5c1.3-1.3 3.1-2 5-2 3.6 0 6.5 2.6 6.5 7.8s-3.3 9.1-8.3 9.1c-1.9 0-3.8-.4-5.5-1.2V37zm5.8 22.4c2.9 0 5.5-2.3 5.6-7 0-4.1-1.6-6.3-4.7-6.3-1.6 0-3.1.6-4.2 1.7v10.9c.9.6 2.1.8 3.3.7zM129.4 58.2c1.5.8 3.1 1.2 4.7 1.2 2.1 0 3.6-.8 3.6-2.5s-2-2.5-3.9-3.3c-2.5-1-4.7-2.4-4.7-5.1s2.7-4.1 5.7-4.2c1.5 0 2.9.3 4.2.9l-.4 1.8c-1.1-.6-2.4-.9-3.7-.9-2.4 0-3.6.9-3.6 2.2 0 1.7 1.4 2.5 3.6 3.4s5 2.2 5 5-2.2 4.5-5.7 4.5c-1.8 0-3.6-.4-5.2-1.2l.4-1.8zM7.2 31.7c0-12.2 8.9-22.6 21-24.4L27.1 0C11.6 2.4.1 15.7 0 31.5c0 6.8 2.2 13.5 6.2 19l5.8-4.3C8.9 42 7.2 36.9 7.2 31.7zM17.1 51.4l-4.2 5.7c4.2 3.1 9.1 5.1 14.2 5.9l1-7c-4-.6-7.8-2.2-11-4.6zM36.5 0l-1.1 7.3c13.5 2 22.7 14.5 20.7 28-.6 3.9-2.1 7.7-4.5 10.9l5.7 4.2c4.1-5.5 6.3-12.1 6.2-19 .1-15.7-11.4-29-27-31.4zM35.5 56l1 7c5.2-.8 10-2.8 14.2-5.9l-4.2-5.7c-3.2 2.4-7 4-11 4.6z"/></g></svg>'
--- ---

View file

@ -3,6 +3,7 @@ title: peak.capital
header_bg_image: peak_hero_ewp1wb header_bg_image: peak_hero_ewp1wb
order: 12 order: 12
description: Peak Capital description description: Peak Capital description
tags: ['early-stage investment fund', 'venture capital', 'fund', 'investor']
svg: '<svg class="peak-logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 102 102"><style>.peak-logo-svg-circle{fill: currentColor}.peak-logo-svg-letters{fill:var(--color-bg)}</style><circle class="peak-logo-svg-circle" cx="50" cy="50" r="50"></circle><polygon class="peak-logo-svg-letters" points="70.45 39.19 70.45 61.48 75.19 61.48 75.19 53.82 78.47 50.48 84.61 61.48 90.66 61.48 82.14 46.79 89.65 39.19 83.69 39.19 75.19 47.68 75.19 39.19 70.45 39.19"></polygon><polygon class="peak-logo-svg-letters" points="43.83 43.41 43.83 39.22 28.98 39.22 28.98 61.48 43.83 61.48 43.83 57.29 33.71 57.29 33.71 52.23 43.2 52.23 43.2 48.03 33.71 48.03 33.71 43.41 43.83 43.41"></polygon><path class="peak-logo-svg-letters" d="M45.77,61.48h5.12L51.48,60a3,3,0,0,1,.16-.36,6,6,0,0,1,11-.21,2.92,2.92,0,0,1,.14.31l.7,1.78h5.15l-8.9-22.26h-5Zm13.95-9.63a10.56,10.56,0,0,0-2.53-.31,9.85,9.85,0,0,0-2.55.33l2.56-6.52Z"></path><path class="peak-logo-svg-letters" d="M9.34,39.22V61.48h4.73V53.57h3.4c5.56,0,9-2.71,9-7.18s-3.46-7.17-9-7.17Zm12.29,7.17c0,1.91-1.48,3-4.16,3h-3.4v-6h3.4C20.15,43.41,21.63,44.49,21.63,46.39Z"></path></svg>' svg: '<svg class="peak-logo-svg" xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 102 102"><style>.peak-logo-svg-circle{fill: currentColor}.peak-logo-svg-letters{fill:var(--color-bg)}</style><circle class="peak-logo-svg-circle" cx="50" cy="50" r="50"></circle><polygon class="peak-logo-svg-letters" points="70.45 39.19 70.45 61.48 75.19 61.48 75.19 53.82 78.47 50.48 84.61 61.48 90.66 61.48 82.14 46.79 89.65 39.19 83.69 39.19 75.19 47.68 75.19 39.19 70.45 39.19"></polygon><polygon class="peak-logo-svg-letters" points="43.83 43.41 43.83 39.22 28.98 39.22 28.98 61.48 43.83 61.48 43.83 57.29 33.71 57.29 33.71 52.23 43.2 52.23 43.2 48.03 33.71 48.03 33.71 43.41 43.83 43.41"></polygon><path class="peak-logo-svg-letters" d="M45.77,61.48h5.12L51.48,60a3,3,0,0,1,.16-.36,6,6,0,0,1,11-.21,2.92,2.92,0,0,1,.14.31l.7,1.78h5.15l-8.9-22.26h-5Zm13.95-9.63a10.56,10.56,0,0,0-2.53-.31,9.85,9.85,0,0,0-2.55.33l2.56-6.52Z"></path><path class="peak-logo-svg-letters" d="M9.34,39.22V61.48h4.73V53.57h3.4c5.56,0,9-2.71,9-7.18s-3.46-7.17-9-7.17Zm12.29,7.17c0,1.91-1.48,3-4.16,3h-3.4v-6h3.4C20.15,43.41,21.63,44.49,21.63,46.39Z"></path></svg>'
--- ---
Peak is an early-stage investment fund backed by entrepreneurs in Europe. Peak is an early-stage investment fund backed by entrepreneurs in Europe.

View file

@ -2,6 +2,7 @@
title: Uncommonbio.co title: Uncommonbio.co
header_bg_image: uncommon_hero_jf1in9 header_bg_image: uncommon_hero_jf1in9
order: 12 order: 12
tags: ['tech consultancy', 'web development', 'UX Design', 'Knoterputer', 'Henkenstein']
description: Peak Capital description description: Peak Capital description
svg: '<svg id="uncommonLogo" x="0" y="0" viewBox="0 0 932 110.7" style="enable-background:new 0 0 932 110.7; fill: currentColor;"><path id="n7" class="uncommonLogo-letter" d="M828.9 3.5h30.5v9.6C865.6 4.9 878.2 0 889.3 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.8c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="o6" class="uncommonLogo-letter" d="M801.2 17.2c-10.8-10.7-24.1-16-39.6-16s-28.7 5.3-39.5 16C711.4 27.7 706 40.6 706 56c0 15.3 5.4 28.3 16.1 39 10.7 10.5 23.9 15.8 39.5 15.8s28.8-5.3 39.6-16C812 84.3 817.5 71.3 817.5 56c0-15.4-5.4-28.3-16.3-38.8zm-21.7 57.1c-4.9 5-10.8 7.5-17.9 7.5s-13-2.5-17.7-7.5c-4.9-5-7.3-11.1-7.3-18.4 0-7.2 2.4-13.4 7.1-18.4 4.9-5 10.8-7.5 17.9-7.5s13 2.5 17.9 7.5c4.9 5 7.3 11.1 7.3 18.4 0 7.3-2.5 13.4-7.3 18.4z"></path><path id="mm5" class="uncommonLogo-letter" d="M446.9 3.5h30.5v9.6C483.6 4.9 496.2 0 507.3 0c10.2 0 21.6 3.1 28.1 9.1 3.3 2.9 6.3 6.7 8.7 10.8 3.7-4.2 6.3-6.8 6.3-6.8C557.1 6.2 569.1 0 580.2 0c10.2 0 21.6 3.1 28.1 9.1 3.3 3 6.3 6.7 8.7 10.9 3.7-4.2 6.4-6.9 6.4-6.9C630.1 6.2 642.1 0 653.2 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.7V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.6V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="o4" class="uncommonLogo-letter" d="M420 17.2c-10.8-10.7-24.1-16-39.6-16s-28.7 5.3-39.5 16c-10.7 10.5-16.1 23.5-16.1 38.8 0 15.3 5.4 28.3 16.1 39 10.7 10.5 23.9 15.8 39.5 15.8s28.8-5.3 39.6-16c10.8-10.5 16.3-23.5 16.3-38.8 0-15.4-5.4-28.3-16.3-38.8zm-21.7 57.1c-4.9 5-10.8 7.5-17.9 7.5s-13-2.5-17.7-7.5c-4.9-5-7.3-11.1-7.3-18.4 0-7.2 2.4-13.4 7.1-18.4 4.9-5 10.8-7.5 17.9-7.5s13 2.5 17.9 7.5c4.9 5 7.3 11.1 7.3 18.4 0 7.3-2.4 13.4-7.3 18.4z"></path><path id="c3" class="uncommonLogo-letter" d="M247.1 16.8c10.4-10.4 23.4-15.6 39.1-15.6 13.6 0 25.5 4.5 35.6 13.4l-11.3 26.5c-6.8-7.3-14.6-11-23.2-11-7.2 0-13.2 2.5-18.1 7.5-4.9 4.9-7.3 11.2-7.3 18.9 0 7.6 2.4 13.7 7.1 18.4 4.9 4.7 10.8 7 17.9 7 8.9 0 16.7-3.7 23.6-11l11.3 26.5c-10.1 8.9-22 13.4-35.6 13.4-15.7 0-28.8-5.2-39.3-15.6-10.4-10.4-15.5-23.5-15.5-39.1s5.2-28.9 15.7-39.3z"></path><path id="n2" class="uncommonLogo-letter" d="M117.8 3.5h30.5v9.6C154.5 4.9 167.1 0 178.2 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="u1" class="uncommonLogo-letter" d="M103.1 107.2H72.6v-9.6c-6.2 8.2-18.8 13.1-29.9 13.1-10.2 0-21.6-3.1-28.1-9.1C6.3 94.1 0 81.7 0 69.6V3.2h30.3V62c0 5 1.8 12.9 4.6 15.7 2.7 2.8 6.7 6.8 16.2 6.8s14.8-4.9 17.5-8.9c2.3-3.3 4.1-7.4 4.1-13.6V3.2h30.5v104z"></path></svg>' svg: '<svg id="uncommonLogo" x="0" y="0" viewBox="0 0 932 110.7" style="enable-background:new 0 0 932 110.7; fill: currentColor;"><path id="n7" class="uncommonLogo-letter" d="M828.9 3.5h30.5v9.6C865.6 4.9 878.2 0 889.3 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.8c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="o6" class="uncommonLogo-letter" d="M801.2 17.2c-10.8-10.7-24.1-16-39.6-16s-28.7 5.3-39.5 16C711.4 27.7 706 40.6 706 56c0 15.3 5.4 28.3 16.1 39 10.7 10.5 23.9 15.8 39.5 15.8s28.8-5.3 39.6-16C812 84.3 817.5 71.3 817.5 56c0-15.4-5.4-28.3-16.3-38.8zm-21.7 57.1c-4.9 5-10.8 7.5-17.9 7.5s-13-2.5-17.7-7.5c-4.9-5-7.3-11.1-7.3-18.4 0-7.2 2.4-13.4 7.1-18.4 4.9-5 10.8-7.5 17.9-7.5s13 2.5 17.9 7.5c4.9 5 7.3 11.1 7.3 18.4 0 7.3-2.5 13.4-7.3 18.4z"></path><path id="mm5" class="uncommonLogo-letter" d="M446.9 3.5h30.5v9.6C483.6 4.9 496.2 0 507.3 0c10.2 0 21.6 3.1 28.1 9.1 3.3 2.9 6.3 6.7 8.7 10.8 3.7-4.2 6.3-6.8 6.3-6.8C557.1 6.2 569.1 0 580.2 0c10.2 0 21.6 3.1 28.1 9.1 3.3 3 6.3 6.7 8.7 10.9 3.7-4.2 6.4-6.9 6.4-6.9C630.1 6.2 642.1 0 653.2 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.7V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.6V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="o4" class="uncommonLogo-letter" d="M420 17.2c-10.8-10.7-24.1-16-39.6-16s-28.7 5.3-39.5 16c-10.7 10.5-16.1 23.5-16.1 38.8 0 15.3 5.4 28.3 16.1 39 10.7 10.5 23.9 15.8 39.5 15.8s28.8-5.3 39.6-16c10.8-10.5 16.3-23.5 16.3-38.8 0-15.4-5.4-28.3-16.3-38.8zm-21.7 57.1c-4.9 5-10.8 7.5-17.9 7.5s-13-2.5-17.7-7.5c-4.9-5-7.3-11.1-7.3-18.4 0-7.2 2.4-13.4 7.1-18.4 4.9-5 10.8-7.5 17.9-7.5s13 2.5 17.9 7.5c4.9 5 7.3 11.1 7.3 18.4 0 7.3-2.4 13.4-7.3 18.4z"></path><path id="c3" class="uncommonLogo-letter" d="M247.1 16.8c10.4-10.4 23.4-15.6 39.1-15.6 13.6 0 25.5 4.5 35.6 13.4l-11.3 26.5c-6.8-7.3-14.6-11-23.2-11-7.2 0-13.2 2.5-18.1 7.5-4.9 4.9-7.3 11.2-7.3 18.9 0 7.6 2.4 13.7 7.1 18.4 4.9 4.7 10.8 7 17.9 7 8.9 0 16.7-3.7 23.6-11l11.3 26.5c-10.1 8.9-22 13.4-35.6 13.4-15.7 0-28.8-5.2-39.3-15.6-10.4-10.4-15.5-23.5-15.5-39.1s5.2-28.9 15.7-39.3z"></path><path id="n2" class="uncommonLogo-letter" d="M117.8 3.5h30.5v9.6C154.5 4.9 167.1 0 178.2 0c10.2 0 21.6 3.1 28.1 9.1 8.4 7.5 14.7 19.9 14.7 32v66.4h-30.3V48.7c0-5-1.8-12.9-4.6-15.7-2.7-2.8-6.7-6.8-16.2-6.8s-14.8 4.9-17.5 8.9c-2.3 3.3-4.1 7.4-4.1 13.6v58.8h-30.5V3.5z"></path><path id="u1" class="uncommonLogo-letter" d="M103.1 107.2H72.6v-9.6c-6.2 8.2-18.8 13.1-29.9 13.1-10.2 0-21.6-3.1-28.1-9.1C6.3 94.1 0 81.7 0 69.6V3.2h30.3V62c0 5 1.8 12.9 4.6 15.7 2.7 2.8 6.7 6.8 16.2 6.8s14.8-4.9 17.5-8.9c2.3-3.3 4.1-7.4 4.1-13.6V3.2h30.5v104z"></path></svg>'
--- ---

View file

@ -1,76 +1,108 @@
.works-wrapper {
max-width: 1200px;
margin: auto;
}
h1 { h1 {
font-size: 16vw; font-size: 16vw;
font-style: italic; margin: var(--spacing-nav) var(--spacing-nav) .25em var(--spacing-nav);
margin: 0 0 0.5em 0; padding: 0 0 calc(var(--spacing-nav) / 3) 0;
letter-spacing: -0.04em; position: relative;
text-align: center; z-index: -1;
position: fixed;
top: calc(50svh - 16vw);
width: 100%;
visibility: hidden;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
border-bottom: 1px solid;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
font-size: 7vw; font-size: 7vw;
top: calc(50svh - 3.5vw);
} }
& span {
display: inline-block;
padding: 0 0.25em;
}
}
h2 {
line-height: 1.1;
letter-spacing: -0.025em;
font-size: 2.5vw;
opacity: 0;
position: absolute;
left: .5em;
bottom: .5em;
transform: scale(0.8) translateY(100%);
margin: 0;
padding: 0.1em 0.4em 0.2em 0.4em;
text-align: center;
transform-origin: center center;
width: auto;
margin: 0;
background-color: var(--color-bg);
color: var(--color-text);
transition: all .3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
.works .work:not(.active):hover & {
opacity: 1;
transform: scale(1) translateY(0);
}
} }
.works { .works {
padding: 0.5em; padding: 0.5em;
display: flex; display: flex;
gap: 0.25em; gap: 0.25em;
flex-wrap: wrap; flex-wrap: wrap;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
gap: 0.25em; display: grid;
padding: 8.5vw 0.5em 0.5em 0.5em; grid-template-columns: repeat(3, 1fr);
width: 100%; gap: 1px;
max-width: 1200px; padding: 0 var(--spacing-nav);
margin: 0 auto; margin: 0 auto;
padding-bottom: 20svh; padding-bottom: 20svh;
} }
} }
.work-info,
.work:visited .work-info {
position: absolute;
left: 0.25em;
top: 0.25em;
padding: 0.5em .75em;
overflow: hidden;
box-sizing: border-box;
background-color: var(--color-text);
visibility: hidden;
& h2 {
text-transform: none;
font-style: normal;
font-weight: 400;
margin: 0;
padding: 0;
font-size: 1.2em;
letter-spacing: -0.02em;
line-height: 1;
visibility: hidden;
color: var(--color-bg);
}
& .tags {
visibility: hidden;
list-style: none;
padding: 0;
margin: 10px 0 0 0 ;
display: flex;
flex-wrap: wrap;
gap: 0.15em;
transition: all .4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
& .tag {
font-size: .6em;
line-height: 1;
letter-spacing: -0.01em;
box-sizing: border-box;
padding: 0;
border-radius: 3px;
text-transform: uppercase;
// font-weight: 800;
// font-style: italic;
color: var(--color-text);
}
}
.work:hover .work-info {
background-color: var(--color-bg);
& h2 {
color: var(--color-text);
}
}
.work { .work {
flex: 0 0 calc(50% - 0.125em ); flex: 0 0 calc(50% - 0.125em );
display: block; display: block;
position: relative; position: relative;
padding: 0; padding: 0;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); // transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-decoration: none; text-decoration: none;
overflow: hidden; overflow: hidden;
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
flex: 0 0 calc(33% - .125em); grid-column-end: span 1;
&:first-child {
grid-column-end: span 2;
grid-row-end: span 2;
}
} }
} }
.work .tag {
opacity: 0;
}
:global(.work img) { :global(.work img) {
width: 100%; width: 100%;
height: auto; height: auto;

View file

@ -8,38 +8,97 @@ workbulge.subscribe(value => {
bulge.factor = value; bulge.factor = value;
}) })
export function initWorkPage( h1: HTMLElement, canvasImgElems: Array<HTMLElement>) { export function initWorkPage( canvasTextElems: Array<HTMLElement>, canvasImgElems: Array<HTMLElement>) {
workbulge.set(0.25); workbulge.set(0);
gsap.to(bulge, {
duration: .5,
factor: 0.15,
delay: .8,
ease: 'back.out(3)',
onUpdate: () => {
workbulge.set(bulge.factor);
}
})
const workinfos: Array<HTMLElement> = Array.from(document.querySelectorAll('.work-info'));
workinfos.forEach((workinfo) => {
const workinfoTitle = workinfo.querySelector('h2') as HTMLElement;
const workinfoTitleWords = workinfoTitle.querySelector('span') as HTMLElement;
const expanded = {
height: workinfo.getBoundingClientRect().height,
width: workinfo.getBoundingClientRect().width + 2,
paddingTop: Number(window.getComputedStyle(workinfo).paddingTop.replace('px','')) as number,
paddingLeft: Number(window.getComputedStyle(workinfo).paddingLeft.replace('px','')) as number,
}
const contracted = {
height: workinfoTitle.offsetHeight * 1.2 + 2 * expanded.paddingTop,
width: workinfoTitleWords.offsetWidth + 2 * expanded.paddingLeft,
}
workinfo.style.width = `${contracted.width}px`;
workinfo.style.height = `${contracted.height}px`;
const tags = workinfo.querySelector('.tags') as HTMLElement;
tags.style.width = `${expanded.width}px`;
workinfo.parentElement?.addEventListener('mouseenter', () => {
gsap.to(workinfo, {
duration: .25,
width: expanded.width,
height: expanded.height,
ease: 'power2.inOut',
overwrite: true
})
})
workinfo.parentElement?.addEventListener('mouseleave', () => {
gsap.to(workinfo, {
duration: .25,
width: contracted.width,
height: contracted.height,
ease: 'power2.inOut',
overwrite: true
})
})
})
gsap.registerPlugin( SplitText ); gsap.registerPlugin( SplitText );
const h1Text = h1?.innerHTML || ''; const work = document.querySelectorAll('.work');
h1.innerHTML = h1Text + h1Text + h1Text + h1Text || ''; gsap.set(document.querySelectorAll('.tag'), {opacity: 0, yPercent: 200});
h1.style.overflow = 'hidden'; gsap.set(document.querySelectorAll('h2'), {opacity: 1 });
h1.style.whiteSpace = 'nowrap'; work.forEach((el) => {
const spans = Array.from(h1.querySelectorAll('span')); el.addEventListener('mouseenter', (e) => {
spans.forEach((span, index) => { const target = e.target as HTMLElement;
gsap.set(span, { opacity: 1, y: -window.innerHeight/1.5 }) gsap.to(target?.querySelectorAll('.tag'), {duration: 0.5, opacity: 1, yPercent: 0, ease: 'back.out(1.7)', stagger: 0.025, overwrite: true});
gsap.to(span, { opacity: 1, y: 0, duration: 1, ease: 'power3.out', delay: index * 0.025 }) gsap.to(target?.querySelector('h2'), {duration: 0.5, opacity: 1, ease: 'back.out(1.7)', overwrite: true});
gsap.to(span, { xPercent: -100, duration: 4, ease: 'none', repeat: -1 }) });
el.addEventListener('mouseleave', (e) => {
const target = e.target as HTMLElement;
gsap.to(target?.querySelectorAll('.tag'), {duration: 0.3, opacity: 0, yPercent: 200, ease: 'power2.out', overwrite: true});
gsap.to(target?.querySelector('h2'), {duration: 0.5, opacity: 1, ease: 'back.out(1.7)', overwrite: true});
});
}); });
gsap.set(canvasImgElems, { gsap.set('.work', {
opacity: 0, yPercent: 50 opacity: 0, yPercent: 50
}) })
gsap.to(canvasImgElems, { gsap.to('.work', {
duration: 1, duration: 1,
opacity: .8, opacity: 1,
yPercent: 0, yPercent: 0,
stagger: 0.05, stagger: 0.05,
ease: 'elastic.out(0.75, 0.5)', ease: 'elastic.out(0.75, 0.5)',
delay: 0.3 delay: 0.3,
}) })
return { return {
text: spans, text: canvasTextElems,
images: canvasImgElems images: canvasImgElems
} }
} }
@ -67,12 +126,30 @@ export function workClickHandler(e:Event){
document.body.appendChild(coverclone); document.body.appendChild(coverclone);
gsap.to('.work .work-info', {
duration: .3,
opacity: 0,
yPercent: -10,
ease: 'power4.out',
})
gsap.to('.work:not(.active) img', { gsap.to('.work:not(.active) img', {
duration: .3, duration: .3,
opacity: 0, opacity: 0,
yPercent: 10, yPercent: 20,
ease: 'power4.out', ease: 'power4.out',
}) })
gsap.to('.work h2', {
duration: .3,
opacity: 0,
// scale: 0,
ease: 'power3.out'
})
gsap.to('.work .tag', {
duration: .3,
opacity: 0,
// scale: 0,
ease: 'power3.out'
})
gsap.set(targetImg, { gsap.set(targetImg, {
zIndex: 100, zIndex: 100,
}) })

274
static/cursor.ai Normal file

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50" style="enable-background:new 0 0 40 50" xml:space="preserve" width="40" height="50"><path style="fill:#ff9494;stroke:#00117f;stroke-width:3;stroke-miterlimit:10" d="M5.4 5 5 44.6l13.1-10.9L35 31.2z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50" width="40" height="50" style="enable-background:new 0 0 40 50" xml:space="preserve"><path d="M2.4 5 2 46.8l15.8-13.6 14.2-2L2.4 5z" style="opacity:.5"/><path d="M5.4 0 5 39.6l13.1-10.9L35 26.2 5.4 0z" style="fill:#fff"/></svg>

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

291
static/home/creative-dev.ai Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 406 KiB

1070
static/home/design-shapes.ai Normal file

File diff suppressed because it is too large Load diff

BIN
static/home/simon-hicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

View file

@ -0,0 +1,40 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 2000 1000" width="2000" height="1000" style="enable-background:new 0 0 2000 1000;" xml:space="preserve">
<style type="text/css">
.st0{fill:var(--color-text, #FFF);}
.st1{fill:var(--color-highlight, #000);}
</style>
<g id="keys">
<polygon class="st0" points="174.3,857.9 85.6,857.9 44.8,898.7 44.8,930.6 133.5,930.6 174.3,889.7 "/>
<polygon class="st0" points="299.5,857.9 210.8,857.9 170,898.7 170,930.6 258.7,930.6 299.5,889.7 "/>
<polygon class="st0" points="257.3,812.6 257.3,780.7 168.6,780.7 127.8,821.6 127.8,853.4 216.5,853.4 "/>
<polygon class="st0" points="382.6,780.7 293.9,780.7 253.1,821.6 253.1,853.4 341.8,853.4 382.6,812.6 "/>
<polygon class="st0" points="423.4,857.9 334.7,857.9 293.9,898.7 293.9,930.6 382.6,930.6 423.4,889.7 "/>
<polygon class="st0" points="419.2,898.7 419.2,930.6 507.9,930.6 548.7,889.7 548.7,857.9 460,857.9 "/>
<polygon class="st0" points="506.5,812.6 506.5,780.7 417.8,780.7 376.9,821.6 376.9,853.4 465.6,853.4 "/>
<polygon class="st0" points="502.2,821.6 502.2,853.4 590.9,853.4 631.7,812.6 631.7,780.7 543,780.7 "/>
<polygon class="st0" points="337.5,735.4 337.5,703.6 248.8,703.6 208,744.4 208,776.2 296.7,776.2 "/>
<polygon class="st0" points="333.3,776.2 422,776.2 462.8,735.4 462.8,703.6 374.1,703.6 333.3,744.4 "/>
<polygon class="st0" points="457.2,776.2 545.9,776.2 586.7,735.4 586.7,703.6 498,703.6 457.2,744.4 "/>
<polygon class="st0" points="623.3,703.6 582.4,744.4 582.4,776.2 671.1,776.2 712,735.4 712,703.6 "/>
<polygon class="st0" points="409.6,624.6 320.9,624.6 280.1,665.4 280.1,697.2 368.8,697.2 409.6,656.4 "/>
<polygon class="st0" points="534.9,624.6 446.2,624.6 405.4,665.4 405.4,697.2 494.1,697.2 534.9,656.4 "/>
<polygon class="st0" points="492.7,579.2 492.7,547.4 404,547.4 363.1,588.2 363.1,620.1 451.8,620.1 "/>
<polygon class="st0" points="617.9,547.4 529.2,547.4 488.4,588.2 488.4,620.1 577.1,620.1 617.9,579.2 "/>
<polygon class="st0" points="658.8,624.6 570.1,624.6 529.2,665.4 529.2,697.2 617.9,697.2 658.8,656.4 "/>
<polygon class="st0" points="654.5,665.4 654.5,697.2 743.2,697.2 784,656.4 784,624.6 695.3,624.6 "/>
<polygon class="st0" points="741.8,579.2 741.8,547.4 653.1,547.4 612.3,588.2 612.3,620.1 701,620.1 "/>
<polygon class="st0" points="737.5,588.2 737.5,620.1 826.2,620.1 867.1,579.2 867.1,547.4 778.4,547.4 "/>
<polygon class="st0" points="572.9,502.1 572.9,470.2 484.2,470.2 443.4,511.1 443.4,542.9 532.1,542.9 "/>
<polygon class="st0" points="568.6,542.9 657.3,542.9 698.2,502.1 698.2,470.2 609.5,470.2 568.6,511.1 "/>
<polygon class="st0" points="692.5,542.9 781.2,542.9 822,502.1 822,470.2 733.3,470.2 692.5,511.1 "/>
<polygon class="st0" points="858.6,470.2 817.8,511.1 817.8,542.9 906.5,542.9 947.3,502.1 947.3,470.2 "/>
</g>
<path id="thumb" class="st1" d="M936.6,532.9l-135.2,67l-72.1,144l73,46.7l94-110.3l274.7,19.6l-1-33.6
c-2.3-75.9-65.1-135.9-141-134.7L936.6,532.9z"/>
<polygon id="pinky" class="st1" points="1022.9,403.8 852.1,470.6 874.4,550.7 815.7,548.9 759.3,452.9 912.1,280.3 1103.5,390.8
"/>
<polygon id="ring" class="st1" points="1085.9,295.4 720.3,385.9 685.7,501.8 672.5,595.7 739.6,603.4 780.8,472.9 877.5,385.9 "/>
<polygon id="middle" class="st1" points="885.6,264.5 714.6,325.1 606.2,432.2 542.3,613.8 610.1,643.8 691.5,487.9 812.3,386.2 1089,341.4"/>
<path id="index" class="st1" d="M982.1,260.2L754.4,128.7L566.8,235.9l-47.1,169.9l65.1,23.6L647.8,310l91-39.9l145.6,129l59.2-7.2 c38.8-4.7,64.2-43.1,53.3-80.6L982.1,260.2z"/>
<path id="arm" class="st1" d="M1170.9,699.7l254-87.9l87.9-78.2l491.7-306.1L1779.9,51.8l-358.2,276.8l-439.6-68.4l-39.4,1.3 c-48.9,1.6-83.4,48.7-70.1,95.8l11.8,41.8l52.2,133.8l28.1,88L1170.9,699.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

314
static/pointer.ai Normal file

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50" style="enable-background:new 0 0 40 50" xml:space="preserve" width="40" height="50"><path d="m17.2 12.2-5.7-8.1c-1.3-1.9-3.9-2.3-5.7-1l-.2.2C3.7 4.6 3.3 7.2 4.6 9l6.3 8.9c-3 1.7-2.4 4.8-2.4 4.8-2.2.8-3.2 2.4-3 4.8 0 0-3.9 2.1-3.1 6.1l6.4 9.1c3.5 5 10.4 6.2 15.3 2.7l4.6-3.3c3-2.1 4.7-5.5 4.7-9.1-.1-6.1 1-8.2-2-13.5l-4-9.6c-.6-1.1-1.8-1.6-3-1.3l-.7.2c-1.2.3-2 1.4-2 2.6l.4 7.6-4.9-6.8z" style="fill:#ff9494;stroke:#00117f;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:10"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50" width="40" height="50" style="enable-background:new 0 0 40 50" xml:space="preserve"><path d="M15.1 12.5 9.4 3.8c-1.3-2-3.9-2.5-5.7-1.1l-.2.3c-1.9 1.3-2.3 4.1-1 6l5.3 8.5c-3 1.8-2.4 5.1-2.4 5.1-2.2.9-3.2 2.6-3 5.1 0 0-2.9 3.2-2.1 7.5L6.7 45c3.5 5.3 10.4 6.6 15.3 2.9l4.6-3.5c3-2.2 4.7-5.9 4.7-9.7-.1-6.5 1-8.7-2-14.4L25.3 8c-.6-1.2-1.8-1.7-3-1.4l-.7.2c-1.2.3-2 1.5-2 2.8l.4 10.1-4.9-7.2z" style="opacity:.5"/><path d="M15.8 10.3 9.2 2.9C7.7 1.2 5.1 1 3.4 2.5l-.1.2c-1.8 1.5-1.9 4.2-.4 5.8l7.2 8.2c-2.8 2-1.9 5-1.9 5-2.1 1-2.9 2.7-2.5 5.1 0 0-3.7 2.5-2.4 6.4l7.3 8.4c4 4.6 11 5.1 15.5 1.1l4.2-3.8c2.8-2.4 4.1-6 3.7-9.6-.8-6.1.1-8.3-3.4-13.2l-5-9.1c-.7-1-2-1.4-3.1-1l-.7.3c-1.2.4-1.8 1.6-1.7 2.8l1.2 7.5-5.5-6.3z" style="fill:#fff"/></svg>

Before

Width:  |  Height:  |  Size: 548 B

After

Width:  |  Height:  |  Size: 796 B