This commit is contained in:
th committed 2026-04-20 00:07:08 +02:00
1 parent 6b6157d786
commit 3ef5fb5a2d
19 files changed
+1244 -94

No files matched your search

+71 -3
View File
@@ -1,4 +1,4 @@
import type { Asset, Layer, Scene } from '@/types/scene'
import type { AnimatableProps, Asset, Layer, Scene } from '@/types/scene'
import { sampleLayer } from './interpolate'
export async function loadSceneImages(scene: Scene): Promise<Record<string, HTMLImageElement>> {
@@ -24,6 +24,62 @@ export async function loadSceneImages(scene: Scene): Promise<Record<string, HTML
return result
}
interface ShadowState {
sx: number
sy: number
blur: number
color: string
}
function hexToRgba(hex: string, alpha: number): string {
const h = hex.trim().replace('#', '')
const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h
if (full.length < 6) return `rgba(0, 0, 0, ${alpha})`
const n = parseInt(full.slice(0, 6), 16)
if (Number.isNaN(n)) return `rgba(0, 0, 0, ${alpha})`
const r = (n >> 16) & 255
const g = (n >> 8) & 255
const b = n & 255
return `rgba(${r}, ${g}, ${b}, ${alpha})`
}
function computeShadow(p: AnimatableProps): ShadowState | null {
const opacity = p.shadowOpacity ?? 0
if (opacity <= 0) return null
const blur = p.shadowBlur ?? 0
const distance = p.shadowDistance ?? 0
if (blur <= 0 && distance <= 0) return null
const angle = p.shadowAngle ?? 90
const rad = (angle * Math.PI) / 180
return {
sx: Math.cos(rad) * distance,
sy: Math.sin(rad) * distance,
blur,
color: hexToRgba(p.shadowColor ?? '#000000', opacity),
}
}
function applyShadow(ctx: CanvasRenderingContext2D, s: ShadowState | null) {
if (!s) {
ctx.shadowColor = 'transparent'
ctx.shadowBlur = 0
ctx.shadowOffsetX = 0
ctx.shadowOffsetY = 0
return
}
ctx.shadowColor = s.color
ctx.shadowBlur = s.blur
ctx.shadowOffsetX = s.sx
ctx.shadowOffsetY = s.sy
}
function clearShadow(ctx: CanvasRenderingContext2D) {
ctx.shadowColor = 'transparent'
ctx.shadowBlur = 0
ctx.shadowOffsetX = 0
ctx.shadowOffsetY = 0
}
function drawLayers(
ctx: CanvasRenderingContext2D,
layers: Layer[],
@@ -44,18 +100,29 @@ function drawLayers(
ctx.rotate((p.rotation * Math.PI) / 180)
ctx.scale(p.scaleX, p.scaleY)
const shadow = computeShadow(p)
applyShadow(ctx, shadow)
if (asset.kind === 'rect') {
const offX = layer.offsetX ?? asset.width / 2
const offY = layer.offsetY ?? asset.height / 2
ctx.fillStyle = p.fill ?? asset.fill
const fill = p.fill ?? asset.fill
const blur = p.blur ?? asset.blur ?? 0
ctx.fillStyle = fill
if (blur > 0) ctx.filter = `blur(${blur}px)`
ctx.fillRect(-offX, -offY, asset.width, asset.height)
ctx.filter = 'none'
} else if (asset.kind === 'circle') {
const offX = layer.offsetX ?? 0
const offY = layer.offsetY ?? 0
ctx.fillStyle = p.fill ?? asset.fill
const fill = p.fill ?? asset.fill
const blur = p.blur ?? asset.blur ?? 0
ctx.fillStyle = fill
if (blur > 0) ctx.filter = `blur(${blur}px)`
ctx.beginPath()
ctx.arc(-offX, -offY, asset.radius, 0, Math.PI * 2)
ctx.fill()
ctx.filter = 'none'
} else if (asset.kind === 'text') {
const offX = layer.offsetX ?? 0
const offY = layer.offsetY ?? 0
@@ -72,6 +139,7 @@ function drawLayers(
}
}
clearShadow(ctx)
ctx.restore()
}
}