feat: engine improvements, new scenes, videos, subtitles, hotspot component and docs update

This commit is contained in:
2026-06-08 14:01:58 +08:00
parent e68ed9c962
commit 6b67989007
20 changed files with 354 additions and 35 deletions

View File

@@ -0,0 +1,85 @@
<script setup lang="ts">
import type { Hotspot } from '@engine/types'
const props = defineProps<{
hotspots: Hotspot[]
isImageScene: boolean
imageUrl?: string | null
}>()
const emit = defineEmits<{
clickHotspot: [hotspotId: string]
}>()
function hsStyle(hs: Hotspot) {
return {
left: `${hs.x * 100}%`,
top: `${hs.y * 100}%`,
width: `${hs.width * 100}%`,
height: `${hs.height * 100}%`,
}
}
</script>
<template>
<div class="hotspot-layer" v-if="(hotspots.length > 0) || (isImageScene && imageUrl)">
<img v-if="isImageScene && imageUrl" :src="imageUrl" class="hotspot-image" />
<div
v-for="hs in hotspots"
:key="hs.id"
class="hotspot-rect"
:style="hsStyle(hs)"
@click.stop="emit('clickHotspot', hs.id)"
:title="hs.label"
>
<span class="hotspot-label">{{ hs.label }}</span>
</div>
</div>
</template>
<style scoped>
.hotspot-layer {
position: absolute;
inset: 0;
z-index: 8;
pointer-events: none;
}
.hotspot-image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: contain;
}
.hotspot-rect {
position: absolute;
border: 2px solid rgba(255, 255, 255, 0.4);
background: rgba(255, 255, 255, 0.06);
border-radius: 4px;
cursor: pointer;
pointer-events: auto;
transition: background 0.15s, border-color 0.15s;
display: flex;
align-items: center;
justify-content: center;
}
.hotspot-rect:hover {
background: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.8);
}
.hotspot-label {
font-size: 13px;
color: #fff;
background: rgba(0, 0, 0, 0.65);
padding: 3px 10px;
border-radius: 3px;
white-space: nowrap;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
pointer-events: none;
}
</style>