Hey! Ich bin Patrick, Webdesign-Lehrling aus Tirol. Ich erstelle moderne, professionelle Websites für Unternehmen und liebe es, mit neuen Technologien zu experimentieren.
Seit September 2024 in der Ausbildung, arbeite ich nebenbei an eigenen Projekten und ersten Kundenprojekten - von der Planung bis zum Launch.
Das Fundament jeder Website. Ich strukturiere Inhalte semantisch, barrierefrei und suchmaschinenfreundlich – sauberer Code von Anfang an.
Semantisches Markup, zugängliche Formulare, korrekte Dokumentenstruktur. Die Basis auf der alles aufbaut.
— klick mich —
Webdesigner aus Tirol
<h2>Hallo, ich bin Patrick.</h2>
<p>Webdesigner aus Tirol</p>
<button>Kontakt</button>
<button>E-Mail</button>
— klick mich —
Webdesigner aus Tirol
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Patrick</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style>
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #e9e9e9;
font-family: 'Inter', sans-serif;
}
.container {
text-align: center;
}
h1 {
font-family: 'Playfair Display', serif;
font-size: 56px;
margin: 0 0 10px 0;
color: #111;
}
.subtitle {
font-size: 24px;
color: #666;
margin-bottom: 40px;
}
.buttons {
display: flex;
gap: 20px;
justify-content: center;
}
.btn {
padding: 16px 40px;
border-radius: 40px;
font-size: 20px;
font-weight: 600;
text-decoration: none;
transition: all 0.25s ease;
}
.btn-primary {
background: #7b5aa6;
color: white;
}
.btn-primary:hover {
background: #6b4c93;
transform: translateY(-3px);
}
.btn-outline {
border: 3px solid #7b5aa6;
color: #7b5aa6;
}
.btn-outline:hover {
background: #7b5aa6;
color: white;
transform: translateY(-3px);
}
</style>
</head>
<body>
<div class="container">
<h1>Hallo, ich bin Patrick.</h1>
<div class="subtitle">Webdesigner aus Tirol</div>
<div class="buttons">
<a href="#" class="btn btn-primary">Kontakt</a>
<a href="#" class="btn btn-outline">E-Mail</a>
</div>
</div>
</body>
</html>
Von simplen Layouts bis zu komplexen Animationen. Ich gestalte Interfaces, die nicht nur funktionieren, sondern begeistern.
Flexbox, Grid, Custom Properties, Animationen & moderne Effekte. Design, das im Gedächtnis bleibt.
Interaktivität, die funktioniert. Von Typing-Effekten über Canvas-Animationen bis zu API-Calls – ich bringe Websites zum Leben.
DOM Manipulation, Event Handling, Animationen, moderne ES6+ Syntax. Code, der nicht nur läuft, sondern begeistert.
— klick mich —
hover über die box
Webdesigner aus Tirol
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width,
initial-scale=1.0">
<title>Patrick –
Webdesigner aus Tirol
</title>
<link
href="https://fonts.googleapis
.com/css2?family=Syne:
wght@700;800&family=
DM+Sans:wght@400;500
&display=swap"
rel="stylesheet">
<style>
*, *::before, *::after {
box-sizing: border-box;
margin: 0; padding: 0; }
body {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f0f0f0;
font-family: 'DM Sans',
sans-serif; }
.hint {
letter-spacing: 0.18em;
font-size: 0.72rem;
text-transform: uppercase;
color: #aaa;
margin-bottom: 28px;
transition: opacity 0.4s; }
/* ── CARD ── */
.card {
position: relative;
width: min(680px, 92vw);
padding: 52px 48px 48px;
border-radius: 22px;
cursor: pointer;
overflow: hidden;
background: #1a1a1f;
border: 1.5px solid #333;
box-shadow: 0 4px 32px
rgba(0,0,0,0.18);
transition:
transform 0.55s
cubic-bezier(.22,1,.36,1),
box-shadow 0.55s
cubic-bezier(.22,1,.36,1),
border-color 0.55s ease; }
.card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: radial-gradient(
ellipse at 50% 110%,
rgba(120,80,200,0.55) 0%,
transparent 70%);
opacity: 0;
transition: opacity 0.55s ease;
pointer-events: none;
z-index: 0; }
.card::after {
content: '';
position: absolute;
inset: -3px;
border-radius: 24px;
background: transparent;
box-shadow: 0 0 0px 0px
rgba(130,80,220,0);
opacity: 0;
transition:
opacity 0.55s ease,
box-shadow 0.55s ease;
pointer-events: none;
z-index: -1; }
.card:hover {
transform: scale(1.045);
border-color:
rgba(150,100,240,0.7);
box-shadow:
0 0 0 1.5px
rgba(150,100,240,0.35),
0 24px 60px
rgba(100,60,180,0.35),
0 4px 16px
rgba(0,0,0,0.3); }
.card:hover::before { opacity: 1; }
.card:hover::after {
opacity: 1;
box-shadow: 0 0 80px 20px
rgba(120,70,200,0.3); }
.card-inner {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 14px; }
#particles {
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
z-index: 0;
opacity: 0;
transition: opacity 0.4s ease; }
.card:hover #particles {
opacity: 1; }
.name {
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: clamp(
1.9rem, 5vw, 2.6rem);
color: #e0e0e0;
transition: color 0.5s ease;
line-height: 1.1; }
.card:hover .name {
color: #ffffff; }
.role {
font-size: 1rem;
color: #666;
letter-spacing: 0.02em;
transition: color 0.5s ease; }
.card:hover .role {
color: rgba(200,170,255,0.85); }
.buttons {
display: flex;
gap: 14px;
margin-top: 10px; }
.btn {
padding: 13px 32px;
border-radius: 50px;
border: 1.5px solid #444;
background: #2a2a2f;
color: #888;
font-family: 'DM Sans',
sans-serif;
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
position: relative;
overflow: hidden;
transition:
background 0.45s ease,
border-color 0.45s ease,
color 0.45s ease,
transform 0.2s ease,
box-shadow 0.45s ease; }
.btn-ripple {
position: absolute;
border-radius: 50%;
background:
rgba(200,160,255,0.3);
transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none; }
@keyframes ripple {
to { transform: scale(4);
opacity: 0; } }
.card:hover .btn {
background:
rgba(100,60,180,0.55);
border-color:
rgba(170,120,255,0.6);
color: #e8d8ff;
box-shadow: 0 2px 18px
rgba(120,70,200,0.25); }
.card:hover .btn:hover {
background:
rgba(120,70,200,0.75);
transform:
translateY(-2px) scale(1.04);
box-shadow: 0 6px 24px
rgba(120,70,200,0.45); }
.card:hover .btn:active {
transform:
translateY(0) scale(0.98); }
.dot {
position: absolute;
border-radius: 50%;
background:
rgba(140,90,230,0.5);
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
filter: blur(1px); }
.card:hover .dot { opacity: 1; }
.dot-1 { width:6px; height:6px;
top:18px; right:32px;
animation: floatDot 3.2s
ease-in-out infinite; }
.dot-2 { width:4px; height:4px;
top:38px; right:58px;
animation: floatDot 2.7s
ease-in-out infinite 0.6s; }
.dot-3 { width:5px; height:5px;
bottom:24px; left:28px;
animation: floatDot 3.8s
ease-in-out infinite 1.2s; }
@keyframes floatDot {
0%,100% {
transform: translateY(0); }
50% {
transform: translateY(-8px); }
}
</style>
</head>
<body>
<p class="hint">
Hover über die Box
</p>
<div class="card"
id="card">
<canvas
id="particles"></canvas>
<span class="dot dot-1"></span>
<span class="dot dot-2"></span>
<span class="dot dot-3"></span>
<div class="card-inner">
<h1 class="name">
Hallo, ich bin Patrick.
</h1>
<p class="role">
Webdesigner aus Tirol
</p>
<div class="buttons">
<button class="btn"
id="btnKontakt">
Kontakt
</button>
<button class="btn"
id="btnEmail">
E-Mail
</button>
</div>
</div>
</div>
<script>
/* ── Particle system ── */
const canvas = document
.getElementById('particles');
const ctx = canvas
.getContext('2d');
const card = document
.getElementById('card');
let particles = [];
let animFrame;
let running = false;
function resizeCanvas() {
canvas.width =
card.offsetWidth;
canvas.height =
card.offsetHeight;
}
resizeCanvas();
window.addEventListener(
'resize', resizeCanvas);
class Particle {
constructor() {
this.reset(true);
}
reset(init = false) {
this.x = Math.random()
* canvas.width;
this.y = init
? Math.random()
* canvas.height
: canvas.height + 4;
this.r = Math.random()
* 1.8 + 0.4;
this.vy = -(Math.random()
* 0.6 + 0.25);
this.vx =
(Math.random() - 0.5)
* 0.4;
this.alpha =
Math.random() * 0.5 + 0.2;
this.hue =
Math.random() * 40 + 260;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.alpha -= 0.0015;
if (this.y < -4
|| this.alpha <= 0)
this.reset();
}
draw() {
ctx.save();
ctx.globalAlpha =
Math.max(0,
this.alpha);
ctx.fillStyle =
`hsl(${this.hue},70%,70%)`;
ctx.beginPath();
ctx.arc(this.x,
this.y,
this.r,
0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
function initParticles() {
particles =
Array.from(
{ length: 55 },
() => new Particle());
}
function animate() {
ctx.clearRect(0, 0,
canvas.width,
canvas.height);
particles.forEach(
p => {
p.update();
p.draw();
});
animFrame =
requestAnimationFrame(
animate);
}
card.addEventListener(
'mouseenter', () => {
if (!running) {
running = true;
initParticles();
animate();
}
});
card.addEventListener(
'mouseleave', () => {
running = false;
cancelAnimationFrame(
animFrame);
ctx.clearRect(0, 0,
canvas.width,
canvas.height);
});
/* ── Button ripple ── */
document.querySelectorAll(
'.btn').forEach(btn => {
btn.addEventListener(
'click', function(e) {
const rect =
btn
.getBoundingClientRect();
const ripple =
document
.createElement('span');
ripple.className =
'btn-ripple';
const size = Math.max(
rect.width,
rect.height);
ripple.style.cssText = `
width:${size}px;
height:${size}px;
left:${e.clientX
- rect.left
- size/2}px;
top:${e.clientY
- rect.top
- size/2}px;
`;
btn.appendChild(ripple);
ripple.addEventListener(
'animationend',
() => ripple.remove());
});
});
</script>
</body>
</html>