diff --git a/projects/sasch40/frontend/public/assets/characters/maja/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/maja/portrait.jpg
index 37794e9..5639a99 100644
Binary files a/projects/sasch40/frontend/public/assets/characters/maja/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/maja/portrait.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/characters/maja/portrait_v2.jpg b/projects/sasch40/frontend/public/assets/characters/maja/portrait_v2.jpg
new file mode 100644
index 0000000..5639a99
Binary files /dev/null and b/projects/sasch40/frontend/public/assets/characters/maja/portrait_v2.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/characters/miriam/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/miriam/portrait.jpg
index f7a85ad..34102f7 100644
Binary files a/projects/sasch40/frontend/public/assets/characters/miriam/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/miriam/portrait.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/characters/miriam/portrait_v2.jpg b/projects/sasch40/frontend/public/assets/characters/miriam/portrait_v2.jpg
new file mode 100644
index 0000000..34102f7
Binary files /dev/null and b/projects/sasch40/frontend/public/assets/characters/miriam/portrait_v2.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/characters/saskia/portrait.jpg b/projects/sasch40/frontend/public/assets/characters/saskia/portrait.jpg
index c213fed..c7130d9 100644
Binary files a/projects/sasch40/frontend/public/assets/characters/saskia/portrait.jpg and b/projects/sasch40/frontend/public/assets/characters/saskia/portrait.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/characters/saskia/portrait_v2.jpg b/projects/sasch40/frontend/public/assets/characters/saskia/portrait_v2.jpg
new file mode 100644
index 0000000..c7130d9
Binary files /dev/null and b/projects/sasch40/frontend/public/assets/characters/saskia/portrait_v2.jpg differ
diff --git a/projects/sasch40/frontend/public/assets/scenes/schankraum_v5.jpg b/projects/sasch40/frontend/public/assets/scenes/schankraum_v5.jpg
new file mode 100644
index 0000000..de618c3
Binary files /dev/null and b/projects/sasch40/frontend/public/assets/scenes/schankraum_v5.jpg differ
diff --git a/projects/sasch40/frontend/src/components/PlatformerView.vue b/projects/sasch40/frontend/src/components/PlatformerView.vue
index 0f4c1e5..a4a855f 100644
--- a/projects/sasch40/frontend/src/components/PlatformerView.vue
+++ b/projects/sasch40/frontend/src/components/PlatformerView.vue
@@ -542,36 +542,101 @@ function drawPlayer(ctx: CanvasRenderingContext2D) {
ctx.restore()
}
+const sisterImages: Record = {}
+
+function preloadSisterImages() {
+ const sources: Record = {
+ 1: CHARACTERS.saskia.portrait,
+ 2: CHARACTERS.maja.portrait,
+ 3: CHARACTERS.miriam.portrait
+ }
+ for (const [lvl, src] of Object.entries(sources)) {
+ const img = new Image()
+ img.src = src
+ sisterImages[Number(lvl)] = img
+ }
+}
+
function drawSisterSprite(ctx: CanvasRenderingContext2D, x: number, y: number, level: number) {
- // Dirndl color per sister
- const dirndlColor = level === 1 ? '#f43f5e' : level === 2 ? '#8b5cf6' : '#06b6d4'
- const hairColor = level === 1 ? '#fde047' : level === 2 ? '#78350f' : '#b45309'
+ const img = sisterImages[level]
+ const wave = Math.sin(Date.now() / 160) * 3
- // Body
- ctx.fillStyle = dirndlColor
- ctx.fillRect(x + 2, y + 14, 18, 18)
- // White apron
- ctx.fillStyle = '#ffffff'
- ctx.fillRect(x + 6, y + 18, 10, 14)
+ if (img && img.complete && img.naturalWidth > 0) {
+ const size = 32
+ const drawX = x - 4
+ const drawY = y - 4 + wave
- // Head
- ctx.fillStyle = '#fbcfe8'
- ctx.fillRect(x + 4, y + 4, 14, 12)
+ ctx.save()
+ // Golden border
+ ctx.beginPath()
+ ctx.arc(drawX + size / 2, drawY + size / 2, size / 2 + 2, 0, Math.PI * 2)
+ ctx.fillStyle = '#ffd700'
+ ctx.fill()
+ ctx.lineWidth = 2
+ ctx.strokeStyle = '#b45309'
+ ctx.stroke()
- // Hair
- ctx.fillStyle = hairColor
- ctx.fillRect(x + 2, y, 18, 6)
- ctx.fillRect(x + 1, y + 5, 4, 14) // Left braid
- ctx.fillRect(x + 17, y + 5, 4, 14) // Right braid
+ // Circular portrait
+ ctx.beginPath()
+ ctx.arc(drawX + size / 2, drawY + size / 2, size / 2, 0, Math.PI * 2)
+ ctx.clip()
+ ctx.drawImage(img, drawX, drawY, size, size)
+ ctx.restore()
- // Tiara / flowers
- ctx.fillStyle = '#ffd700'
- ctx.fillRect(x + 5, y - 2, 12, 3)
+ // Little waving hand
+ ctx.fillStyle = '#ffd700'
+ ctx.font = '10px monospace'
+ ctx.fillText('👋', drawX + size - 2, drawY + 8 + wave)
+ } else {
+ // Custom pixel-art styling per sister matching real photos
+ const dirndlColor = level === 1 ? '#f43f5e' : level === 2 ? '#8b5cf6' : '#06b6d4'
+ const hairColor = level === 1 ? '#3d2314' : level === 2 ? '#6b4226' : '#18181b'
- // Waving arm
- const wave = Math.sin(Date.now() / 150) * 4
- ctx.fillStyle = '#fbcfe8'
- ctx.fillRect(x - 3, y + 6 + wave, 5, 5)
+ // Body
+ ctx.fillStyle = dirndlColor
+ ctx.fillRect(x + 2, y + 14, 18, 18)
+ // White apron
+ ctx.fillStyle = '#ffffff'
+ ctx.fillRect(x + 6, y + 18, 10, 14)
+
+ // Head
+ ctx.fillStyle = '#fce7f3'
+ ctx.fillRect(x + 4, y + 4, 14, 12)
+
+ // Hair
+ ctx.fillStyle = hairColor
+ if (level === 1) {
+ // Saskia: elegant bun updo with side strands
+ ctx.fillRect(x + 2, y, 18, 6)
+ ctx.fillRect(x + 5, y - 5, 12, 6)
+ ctx.fillRect(x + 1, y + 5, 2, 6)
+ ctx.fillRect(x + 19, y + 5, 2, 6)
+ } else if (level === 2) {
+ // Maja: short pixie cut with side bangs
+ ctx.fillRect(x + 2, y, 18, 6)
+ ctx.fillRect(x + 1, y + 3, 5, 8)
+ // Gold hoop earring
+ ctx.fillStyle = '#ffd700'
+ ctx.fillRect(x + 1, y + 9, 2, 2)
+ ctx.fillStyle = hairColor
+ } else {
+ // Miriam: long flowing dark hair with sunglasses on head
+ ctx.fillRect(x + 2, y, 18, 6)
+ ctx.fillRect(x + 1, y + 4, 4, 16)
+ ctx.fillRect(x + 17, y + 4, 4, 16)
+ // Sunglasses
+ ctx.fillStyle = '#0f172a'
+ ctx.fillRect(x + 5, y - 3, 12, 3)
+ }
+
+ // Tiara
+ ctx.fillStyle = '#ffd700'
+ ctx.fillRect(x + 6, y - 2, 10, 3)
+
+ // Waving arm
+ ctx.fillStyle = '#fce7f3'
+ ctx.fillRect(x - 3, y + 6 + wave, 5, 5)
+ }
}
function drawHUD(ctx: CanvasRenderingContext2D) {
@@ -604,6 +669,7 @@ function gameLoop() {
}
onMounted(() => {
+ preloadSisterImages()
window.addEventListener('keydown', handleKeyDown)
window.addEventListener('keyup', handleKeyUp)
;(window as any).__platformer = {
@@ -652,6 +718,28 @@ onUnmounted(() => {
Gierige Kronkorken-Kobolde haben Saschas drei Schwestern Saskia, Maja und Miriam auf luftige Himmelszinnen entführt!
+
+
+
+
+
![Saskia]()
+
+
1. Saskia 👑
+
+
+
+
![Maja]()
+
+
2. Maja 🌸
+
+
+
+
![Miriam]()
+
+
3. Miriam ✨
+
+
+
☁️
@@ -962,6 +1050,46 @@ onUnmounted(() => {
font-size: 6.5px;
}
+/* Sisters Showcase in Act II Intro */
+.sisters-showcase {
+ display: flex;
+ justify-content: center;
+ gap: 12px;
+ margin: 10px 0 12px 0;
+ width: 100%;
+}
+
+.sister-mini-card {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+}
+
+.sister-mini-portrait {
+ width: 52px;
+ height: 52px;
+ border-radius: 8px;
+ border: 2px solid #ffd700;
+ box-shadow: 0 0 8px rgba(255, 215, 0, 0.4);
+ overflow: hidden;
+ background: #1e1b4b;
+}
+
+.sister-mini-portrait img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ image-rendering: crisp-edges;
+}
+
+.sister-mini-label {
+ font-family: 'Press Start 2P', monospace;
+ font-size: 5.5px;
+ color: #ffd700;
+ text-align: center;
+}
+
/* Animations */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s;
diff --git a/projects/sasch40/frontend/src/components/TavernView.vue b/projects/sasch40/frontend/src/components/TavernView.vue
index 9fc0bdb..3c356e7 100644
--- a/projects/sasch40/frontend/src/components/TavernView.vue
+++ b/projects/sasch40/frontend/src/components/TavernView.vue
@@ -580,10 +580,36 @@ function proceedToExpress() {
+
+
+
+ ⚜️
+ ✦
+ 👑
+ ✦
+ 🍻
+ ✦
+ ⚔️
+ ✦
+ 🛡️
+ ✦
+ 🌿
+ ✦
+ ⚜️
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+ ⚜️
+ ✦
+ 👑
+ ✦
+ 🍻
+ ✦
+ ⚔️
+ ✦
+ 🛡️
+ ✦
+ 🌿
+ ✦
+ ⚜️
+
+
+
+
+
+
{{
@@ -840,7 +887,6 @@ function proceedToExpress() {
-
@@ -1192,27 +1238,110 @@ function proceedToExpress() {