Round two of the outside eye: contrast, scale, and travel
The whiff darkens to slate and sweeps longer; the portal-cell opens a dark void behind its collapsing rings — an opening in space, not a selected square; the tacks grow half again and recoil harder; the streak's reveal slows so the travel reads even in a sampled frame; dust lifts its contrast a step without turning heavy. The sector ghosts stay board-machinery on purpose — the reviewer allowed it, and the maze grinding IS an operation, not a spell. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
bcaa06251a
commit
e713d69582
@@ -32,8 +32,8 @@
|
||||
|
||||
<defs>
|
||||
<radialGradient id={`dust-soft-${uid}`}>
|
||||
<stop offset="0" stop-color="#a5977a" stop-opacity="0.95" />
|
||||
<stop offset="0.75" stop-color="#8d8266" stop-opacity="0.55" />
|
||||
<stop offset="0" stop-color="#96876a" stop-opacity="1" />
|
||||
<stop offset="0.75" stop-color="#7d7358" stop-opacity="0.7" />
|
||||
<stop offset="1" stop-color="#8d8266" stop-opacity="0" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
@@ -47,7 +47,7 @@
|
||||
.puff.back { animation-name: blow-b; }
|
||||
.puff.late { animation-delay: 0.08s; }
|
||||
.puff.later { animation-delay: 0.16s; }
|
||||
.grit circle { fill: #5c523e; animation: grit-fall 0.6s ease-in forwards; }
|
||||
.grit circle { fill: #4a4232; animation: grit-fall 0.6s ease-in forwards; }
|
||||
@keyframes blow-a {
|
||||
0% { opacity: 1; transform: translate(0, 0) scale(0.8); }
|
||||
100% { opacity: 0; transform: translate(var(--ax), var(--ay)) scale(2); }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { FxOf } from "../fx";
|
||||
import { CELL } from "./geom";
|
||||
let { fx }: { fx: FxOf<"portal" | "portal-cell"> } = $props();
|
||||
const uid = $props.id();
|
||||
</script>
|
||||
|
||||
{#if fx.kind === "portal"}
|
||||
@@ -12,6 +13,17 @@
|
||||
<line {x1} {y1} {x2} {y2} class="curtain glow" />
|
||||
<line {x1} {y1} {x2} {y2} class="curtain" pathLength="100" />
|
||||
{:else}
|
||||
<defs>
|
||||
<radialGradient id={`portal-void-${uid}`}>
|
||||
<stop offset="0" stop-color="#0d2430" stop-opacity="0.85" />
|
||||
<stop offset="0.6" stop-color="#12414a" stop-opacity="0.5" />
|
||||
<stop offset="1" stop-color="#9be3e0" stop-opacity="0.1" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect x={fx.at.x * CELL + 5} y={fx.at.y * CELL + 5}
|
||||
width={CELL - 10} height={CELL - 10} rx="8"
|
||||
fill={`url(#portal-void-${uid})`} class="void"
|
||||
style={`transform-origin: ${fx.at.x * CELL + CELL / 2}px ${fx.at.y * CELL + CELL / 2}px`} />
|
||||
<rect x={fx.at.x * CELL + 3} y={fx.at.y * CELL + 3}
|
||||
width={CELL - 6} height={CELL - 6} rx="6" class="veil outer"
|
||||
style={`transform-origin: ${fx.at.x * CELL + CELL / 2}px ${fx.at.y * CELL + CELL / 2}px`} />
|
||||
@@ -55,6 +67,7 @@
|
||||
stroke-dasharray: 7 5;
|
||||
filter: drop-shadow(0 0 4px rgba(155, 227, 224, 0.8));
|
||||
}
|
||||
.void { animation: void-open 0.9s ease-out forwards; }
|
||||
.veil.outer { stroke-width: 2.5; animation: veil-in 0.9s ease-in forwards; }
|
||||
.veil.inner {
|
||||
stroke: rgba(180, 138, 224, 0.8);
|
||||
@@ -62,6 +75,12 @@
|
||||
animation: veil-in 0.9s ease-in 0.2s forwards;
|
||||
opacity: 0;
|
||||
}
|
||||
@keyframes void-open {
|
||||
0% { opacity: 0; transform: scale(0.4); }
|
||||
30% { opacity: 1; transform: scale(1); }
|
||||
75% { opacity: 0.9; transform: scale(0.92); }
|
||||
100% { opacity: 0; transform: scale(0.5); }
|
||||
}
|
||||
@keyframes veil-in {
|
||||
0% { opacity: 0; transform: scale(1.25); }
|
||||
25% { opacity: 1; }
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<path {d} pathLength="100" class="trail wide" />
|
||||
<path {d} pathLength="100" class="trail bright" />
|
||||
<circle r="4.5" class="head" cx="0" cy="0">
|
||||
<animateMotion dur="0.26s" fill="freeze" path={d} calcMode="spline"
|
||||
<animateMotion dur="0.38s" fill="freeze" path={d} calcMode="spline"
|
||||
keySplines="0.3 0 0.4 1" keyTimes="0;1" keyPoints="0;1" />
|
||||
</circle>
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 100 100;
|
||||
animation: draw-collapse 0.55s ease-out forwards;
|
||||
animation: draw-collapse 0.68s ease-out forwards;
|
||||
}
|
||||
.trail.wide { stroke: rgba(233, 225, 203, 0.4); stroke-width: 7; }
|
||||
.trail.bright { stroke: rgba(255, 253, 240, 0.9); stroke-width: 3; }
|
||||
.head {
|
||||
fill: #fffdf0;
|
||||
animation: head-life 0.5s ease-out forwards;
|
||||
animation: head-life 0.6s ease-out forwards;
|
||||
}
|
||||
/* Draw from source to head, then the tail chases it into the destination. */
|
||||
@keyframes draw-collapse {
|
||||
0% { stroke-dashoffset: 100; opacity: 0.95; }
|
||||
47% { stroke-dashoffset: 0; opacity: 0.95; }
|
||||
56% { stroke-dashoffset: 0; opacity: 0.95; }
|
||||
100% { stroke-dashoffset: -100; opacity: 0; }
|
||||
}
|
||||
@keyframes head-life {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
{#each TACKS as t (t.cls)}
|
||||
<g transform={`translate(${c.x + t.x} ${c.y + t.y}) rotate(${t.rot})`}>
|
||||
<g class={`tack ${t.cls}`}>
|
||||
<circle cx="0" cy="2.5" r="2.6" class="head" />
|
||||
<path d="M -1.4 1 L 0 -5 L 1.4 1 z" class="spike" />
|
||||
<circle cx="0" cy="3.8" r="3.9" class="head" />
|
||||
<path d="M -2.1 1.5 L 0 -7.5 L 2.1 1.5 z" class="spike" />
|
||||
</g>
|
||||
</g>
|
||||
{/each}
|
||||
@@ -34,10 +34,10 @@
|
||||
.tack.late { animation-delay: 0.1s; }
|
||||
.tack.later { animation-delay: 0.2s; }
|
||||
@keyframes tack-hop {
|
||||
0% { opacity: 0; transform: translateY(3px); }
|
||||
25% { opacity: 1; transform: translateY(-6px); }
|
||||
55% { transform: translateY(-1px); }
|
||||
75% { transform: translateY(-4px); }
|
||||
100% { opacity: 0; transform: translateY(-1px); }
|
||||
0% { opacity: 0; transform: translateY(4px); }
|
||||
22% { opacity: 1; transform: translateY(-10px); }
|
||||
50% { transform: translateY(-2px); }
|
||||
72% { transform: translateY(-7px); }
|
||||
100% { opacity: 0; transform: translateY(-2px); }
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,27 +6,27 @@
|
||||
</script>
|
||||
|
||||
<g class="whiff" style={`transform-origin: ${c.x}px ${c.y}px`}>
|
||||
<path d={`M ${c.x - 20} ${c.y - 8} q 14 -5 40 -3`} pathLength="100" class="streak a" />
|
||||
<path d={`M ${c.x - 22} ${c.y + 1} q 16 3 42 0`} pathLength="100" class="streak b" />
|
||||
<path d={`M ${c.x - 18} ${c.y + 9} q 12 5 38 4`} pathLength="100" class="streak c" />
|
||||
<path d={`M ${c.x - 30} ${c.y - 9} q 20 -7 58 -4`} pathLength="100" class="streak a" />
|
||||
<path d={`M ${c.x - 32} ${c.y + 1} q 24 4 62 0`} pathLength="100" class="streak b" />
|
||||
<path d={`M ${c.x - 28} ${c.y + 10} q 18 7 56 5`} pathLength="100" class="streak c" />
|
||||
</g>
|
||||
|
||||
<style>
|
||||
.streak {
|
||||
fill: none;
|
||||
stroke: rgba(190, 200, 210, 0.85);
|
||||
stroke-width: 2.4;
|
||||
stroke: rgba(110, 125, 140, 0.9);
|
||||
stroke-width: 3;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 30 100;
|
||||
stroke-dashoffset: 30;
|
||||
stroke-dasharray: 38 100;
|
||||
stroke-dashoffset: 38;
|
||||
animation: sweep 0.5s ease-out forwards;
|
||||
}
|
||||
.streak.b { animation-delay: 0.06s; stroke-width: 3; }
|
||||
.streak.c { animation-delay: 0.12s; stroke-width: 2; }
|
||||
.streak.b { animation-delay: 0.06s; stroke-width: 3.6; }
|
||||
.streak.c { animation-delay: 0.12s; stroke-width: 2.6; }
|
||||
.whiff { animation: wobble 0.55s ease-in-out forwards; }
|
||||
@keyframes sweep {
|
||||
0% { stroke-dashoffset: 30; opacity: 0; }
|
||||
20% { opacity: 0.9; }
|
||||
0% { stroke-dashoffset: 38; opacity: 0; }
|
||||
18% { opacity: 0.95; }
|
||||
100% { stroke-dashoffset: -100; opacity: 0; }
|
||||
}
|
||||
@keyframes wobble {
|
||||
|
||||
Reference in New Issue
Block a user