create-aura3d 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
- package/templates/cartoon-channel/README.md +38 -0
- package/templates/cartoon-channel/aura.assets.json +1364 -0
- package/templates/cartoon-channel/package.json +3 -2
- package/templates/cartoon-channel/public/aura-assets/luma.047f5e5f.glb +0 -0
- package/templates/cartoon-channel/public/aura-assets/luma.thumb.svg +1 -0
- package/templates/cartoon-channel/public/aura-assets/miko.047f5e5f.glb +0 -0
- package/templates/cartoon-channel/public/aura-assets/miko.thumb.svg +1 -0
- package/templates/cartoon-channel/public/aura-assets/moon-garden-feature-frame.png +0 -0
- package/templates/cartoon-channel/src/aura-assets.ts +5 -11
- package/templates/cartoon-channel/src/concept-episode-2-5d.css +159 -0
- package/templates/cartoon-channel/src/concept-episode-2-5d.ts +155 -0
- package/templates/cartoon-channel/src/image-puppet-episode.css +290 -0
- package/templates/cartoon-channel/src/image-puppet-episode.ts +139 -0
- package/templates/cartoon-channel/src/main.ts +89 -71
- package/templates/cartoon-channel/src/puppet-episode-2d.css +526 -0
- package/templates/cartoon-channel/src/puppet-episode-2d.ts +189 -0
- package/templates/cartoon-channel/src/render-plan.ts +1 -1
- package/templates/cartoon-channel/src/sample-episode-visual.css +457 -0
- package/templates/cartoon-channel/src/sample-episode-visual.ts +185 -0
- package/templates/cartoon-channel/test-results/.last-run.json +4 -0
- package/templates/cartoon-channel/tests/concept-2-5d-animation.spec.ts +18 -0
- package/templates/cartoon-channel/tests/concept-2-5d.spec.ts +30 -0
- package/templates/cartoon-channel/tests/image-puppet-animation.spec.ts +18 -0
- package/templates/cartoon-channel/tests/image-puppet.spec.ts +29 -0
- package/templates/cartoon-channel/tests/puppet-2d-animation.spec.ts +18 -0
- package/templates/cartoon-channel/tests/puppet-2d.spec.ts +26 -0
- package/templates/cartoon-channel/tests/reports/prompt-animation/cartoon-sample-episode.png +0 -0
- package/templates/cartoon-channel/tests/sample-episode-visual.spec.ts +45 -0
- package/templates/cartoon-channel/tests/storyboard-playback.spec.ts +1 -1
- package/templates/cartoon-studio/README.md +82 -0
- package/templates/cartoon-studio/aura.assets.json +157 -0
- package/templates/cartoon-studio/index.html +13 -0
- package/templates/cartoon-studio/package.json +32 -0
- package/templates/cartoon-studio/playwright.config.ts +13 -0
- package/templates/cartoon-studio/public/aura-assets/luma.047f5e5f.glb +0 -0
- package/templates/cartoon-studio/public/aura-assets/luma.humanoid-fixture.glb +0 -0
- package/templates/cartoon-studio/public/aura-assets/luma.thumb.svg +1 -0
- package/templates/cartoon-studio/public/aura-assets/miko.047f5e5f.glb +0 -0
- package/templates/cartoon-studio/public/aura-assets/miko.thumb.svg +1 -0
- package/templates/cartoon-studio/public/aura-assets/moonGarden.gltf +183 -0
- package/templates/cartoon-studio/scripts/episode.ts +276 -0
- package/templates/cartoon-studio/src/aura-assets.ts +61 -0
- package/templates/cartoon-studio/src/characters.ts +65 -0
- package/templates/cartoon-studio/src/contract.ts +1 -0
- package/templates/cartoon-studio/src/episode-renderer.ts +605 -0
- package/templates/cartoon-studio/src/episode.ts +306 -0
- package/templates/cartoon-studio/src/main.ts +333 -0
- package/templates/cartoon-studio/src/render-plan.ts +567 -0
- package/templates/cartoon-studio/src/review.ts +99 -0
- package/templates/cartoon-studio/src/sets.ts +14 -0
- package/templates/cartoon-studio/src/studio.ts +101 -0
- package/templates/cartoon-studio/test-results/.last-run.json +4 -0
- package/templates/cartoon-studio/tests/episode-render.spec.ts +44 -0
- package/templates/cartoon-studio/tests/motion-quality.spec.ts +45 -0
- package/templates/cartoon-studio/tests/route-health.spec.ts +7 -0
- package/templates/cartoon-studio/tests/storyboard-playback.spec.ts +99 -0
- package/templates/cartoon-studio/tests/visual-review.spec.ts +21 -0
- package/templates/cartoon-studio/tsconfig.json +12 -0
- package/templates/cinematic-scene/package.json +1 -1
- package/templates/episode-builder/README.md +46 -0
- package/templates/episode-builder/index.html +13 -0
- package/templates/episode-builder/package.json +21 -0
- package/templates/episode-builder/playwright.config.ts +13 -0
- package/templates/episode-builder/src/aura-assets.ts +14 -0
- package/templates/episode-builder/src/builder.ts +78 -0
- package/templates/episode-builder/src/characters.ts +28 -0
- package/templates/episode-builder/src/contract.ts +1 -0
- package/templates/episode-builder/src/episode.ts +300 -0
- package/templates/episode-builder/src/main.ts +265 -0
- package/templates/episode-builder/src/render-plan.ts +405 -0
- package/templates/episode-builder/src/sets.ts +14 -0
- package/templates/episode-builder/tests/route-health.spec.ts +7 -0
- package/templates/episode-builder/tests/storyboard-playback.spec.ts +98 -0
- package/templates/episode-builder/tsconfig.json +12 -0
- package/templates/fighting-game/package.json +1 -1
- package/templates/fighting-game/src/game/stage.ts +18 -4
- package/templates/fighting-game/src/main.ts +3 -2
- package/templates/mini-game/package.json +1 -1
- package/templates/product-viewer/package.json +1 -1
- package/templates/product-viewer/tests/screenshot.spec.ts +8 -16
- package/templates/prompt-cartoon-channel/package.json +1 -1
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
html,
|
|
2
|
+
body {
|
|
3
|
+
margin: 0;
|
|
4
|
+
min-height: 100%;
|
|
5
|
+
background:
|
|
6
|
+
radial-gradient(circle at 50% 22%, rgba(125, 226, 255, 0.2), transparent 34%),
|
|
7
|
+
linear-gradient(180deg, #06101f 0%, #0b1f32 58%, #07131d 100%);
|
|
8
|
+
color: #f8fff2;
|
|
9
|
+
font-family:
|
|
10
|
+
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
11
|
+
sans-serif;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#app {
|
|
15
|
+
position: absolute;
|
|
16
|
+
inset: 0;
|
|
17
|
+
z-index: 5;
|
|
18
|
+
opacity: 0.96;
|
|
19
|
+
pointer-events: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#app canvas {
|
|
23
|
+
width: 100% !important;
|
|
24
|
+
height: 100% !important;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#caption-overlay,
|
|
28
|
+
.aura-diagnostics-overlay {
|
|
29
|
+
display: none !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sample-episode {
|
|
33
|
+
position: fixed;
|
|
34
|
+
inset: 0;
|
|
35
|
+
display: grid;
|
|
36
|
+
place-items: center;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
background:
|
|
39
|
+
radial-gradient(circle at 50% 28%, rgba(64, 255, 191, 0.12), transparent 26%),
|
|
40
|
+
linear-gradient(180deg, rgba(8, 27, 42, 0.2), rgba(2, 8, 14, 0.76));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.sample-episode__frame {
|
|
44
|
+
position: relative;
|
|
45
|
+
width: min(1280px, calc(100vw - 48px));
|
|
46
|
+
aspect-ratio: 16 / 9;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
border: 1px solid rgba(125, 226, 255, 0.28);
|
|
49
|
+
border-radius: 24px;
|
|
50
|
+
background:
|
|
51
|
+
linear-gradient(rgba(125, 226, 255, 0.05) 1px, transparent 1px) 0 0 / 100% 10px,
|
|
52
|
+
radial-gradient(circle at 50% 42%, rgba(125, 226, 255, 0.2), transparent 24%),
|
|
53
|
+
linear-gradient(180deg, rgba(11, 36, 53, 0.9) 0%, rgba(19, 58, 73, 0.76) 57%, rgba(21, 47, 48, 0.72) 58%, rgba(13, 29, 34, 0.82) 100%);
|
|
54
|
+
box-shadow:
|
|
55
|
+
0 34px 90px rgba(0, 0, 0, 0.55),
|
|
56
|
+
0 0 80px rgba(64, 255, 191, 0.12);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.sample-episode__moon {
|
|
60
|
+
position: absolute;
|
|
61
|
+
z-index: 2;
|
|
62
|
+
left: 50%;
|
|
63
|
+
top: 10%;
|
|
64
|
+
width: 30%;
|
|
65
|
+
aspect-ratio: 1;
|
|
66
|
+
transform: translateX(-50%);
|
|
67
|
+
border: 2px solid rgba(125, 226, 255, 0.22);
|
|
68
|
+
border-radius: 999px;
|
|
69
|
+
background:
|
|
70
|
+
radial-gradient(circle at 42% 36%, rgba(248, 255, 242, 0.18), transparent 12%),
|
|
71
|
+
radial-gradient(circle at 64% 56%, rgba(64, 255, 191, 0.08), transparent 18%);
|
|
72
|
+
opacity: 0.82;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.sample-episode__skyline {
|
|
76
|
+
position: absolute;
|
|
77
|
+
z-index: 2;
|
|
78
|
+
inset: auto 0 28% 0;
|
|
79
|
+
height: 24%;
|
|
80
|
+
background:
|
|
81
|
+
linear-gradient(90deg, transparent 3%, rgba(6, 18, 26, 0.72) 3% 9%, transparent 9% 14%, rgba(6, 18, 26, 0.58) 14% 26%, transparent 26% 34%, rgba(6, 18, 26, 0.62) 34% 43%, transparent 43% 52%, rgba(6, 18, 26, 0.58) 52% 61%, transparent 61% 72%, rgba(6, 18, 26, 0.66) 72% 83%, transparent 83% 91%, rgba(6, 18, 26, 0.52) 91% 96%, transparent 96%);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sample-episode__garden {
|
|
85
|
+
position: absolute;
|
|
86
|
+
z-index: 3;
|
|
87
|
+
left: 10%;
|
|
88
|
+
right: 10%;
|
|
89
|
+
bottom: 18%;
|
|
90
|
+
height: 19%;
|
|
91
|
+
border-radius: 50% 50% 12px 12px / 46% 46% 12px 12px;
|
|
92
|
+
background:
|
|
93
|
+
radial-gradient(ellipse at 50% 0%, rgba(64, 255, 191, 0.36), transparent 44%),
|
|
94
|
+
linear-gradient(180deg, #173e3a 0%, #10282c 100%);
|
|
95
|
+
border-bottom: 8px solid rgba(64, 255, 191, 0.72);
|
|
96
|
+
box-shadow: 0 -4px 34px rgba(64, 255, 191, 0.18);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.sample-episode__path {
|
|
100
|
+
position: absolute;
|
|
101
|
+
z-index: 4;
|
|
102
|
+
left: 22%;
|
|
103
|
+
right: 22%;
|
|
104
|
+
bottom: 19%;
|
|
105
|
+
height: 6%;
|
|
106
|
+
border-radius: 999px;
|
|
107
|
+
background: linear-gradient(90deg, rgba(255, 225, 142, 0.16), rgba(255, 225, 142, 0.74), rgba(255, 225, 142, 0.16));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.sample-episode__stones,
|
|
111
|
+
.sample-episode__flowers {
|
|
112
|
+
position: absolute;
|
|
113
|
+
z-index: 5;
|
|
114
|
+
inset: auto 17% 25% 17%;
|
|
115
|
+
height: 8%;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.sample-episode__stones::before,
|
|
119
|
+
.sample-episode__stones::after,
|
|
120
|
+
.sample-episode__flowers::before,
|
|
121
|
+
.sample-episode__flowers::after {
|
|
122
|
+
content: "";
|
|
123
|
+
position: absolute;
|
|
124
|
+
bottom: 0;
|
|
125
|
+
width: 26px;
|
|
126
|
+
height: 18px;
|
|
127
|
+
border-radius: 999px;
|
|
128
|
+
background: #ffe18e;
|
|
129
|
+
box-shadow:
|
|
130
|
+
0 0 18px rgba(255, 225, 142, 0.8),
|
|
131
|
+
86px -10px 0 -5px #40ffbf,
|
|
132
|
+
86px -10px 22px -6px rgba(64, 255, 191, 0.74),
|
|
133
|
+
472px -4px 0 -4px #ffe18e,
|
|
134
|
+
472px -4px 20px -6px rgba(255, 225, 142, 0.8);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.sample-episode__stones::before {
|
|
138
|
+
left: 6%;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.sample-episode__stones::after {
|
|
142
|
+
right: 8%;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.sample-episode__flowers::before,
|
|
146
|
+
.sample-episode__flowers::after {
|
|
147
|
+
width: 14px;
|
|
148
|
+
height: 50px;
|
|
149
|
+
border-radius: 999px 999px 12px 12px;
|
|
150
|
+
background: #f8fff2;
|
|
151
|
+
box-shadow:
|
|
152
|
+
0 0 18px rgba(248, 255, 242, 0.55),
|
|
153
|
+
20px -6px 0 -4px #7de2ff,
|
|
154
|
+
130px 4px 0 -3px #f8fff2,
|
|
155
|
+
150px -5px 0 -5px #40ffbf;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.sample-episode__flowers::before {
|
|
159
|
+
left: 16%;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.sample-episode__flowers::after {
|
|
163
|
+
right: 18%;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.cartoon-robot {
|
|
167
|
+
--accent: #7de2ff;
|
|
168
|
+
--shadow: rgba(125, 226, 255, 0.28);
|
|
169
|
+
position: absolute;
|
|
170
|
+
bottom: 25%;
|
|
171
|
+
width: 15%;
|
|
172
|
+
min-width: 128px;
|
|
173
|
+
aspect-ratio: 0.62;
|
|
174
|
+
filter: drop-shadow(0 22px 26px rgba(0, 0, 0, 0.38)) drop-shadow(0 0 26px var(--shadow));
|
|
175
|
+
transition:
|
|
176
|
+
transform 420ms ease,
|
|
177
|
+
left 420ms ease,
|
|
178
|
+
right 420ms ease;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.sample-episode[data-uses-typed-assets="true"] .cartoon-robot {
|
|
182
|
+
display: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__moon,
|
|
186
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__skyline,
|
|
187
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__garden,
|
|
188
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__path,
|
|
189
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__stones,
|
|
190
|
+
.sample-episode[data-uses-typed-assets="true"] .sample-episode__flowers,
|
|
191
|
+
.sample-episode[data-uses-typed-assets="true"] .cartoon-broom {
|
|
192
|
+
display: none;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.cartoon-robot--miko {
|
|
196
|
+
left: 26%;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.cartoon-robot--luma {
|
|
200
|
+
--accent: #ffe18e;
|
|
201
|
+
--shadow: rgba(255, 225, 142, 0.32);
|
|
202
|
+
right: 26%;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.sample-episode[data-shot-id="shot-glow-stone-teamwork"] .cartoon-robot--miko {
|
|
206
|
+
transform: translateX(8%) rotate(-6deg);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.sample-episode[data-shot-id="shot-glow-stone-teamwork"] .cartoon-robot--luma {
|
|
210
|
+
transform: translateX(-8%) rotate(5deg);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.sample-episode[data-shot-id="shot-moon-garden-finish"] .cartoon-robot--miko {
|
|
214
|
+
transform: translateX(14%) scale(1.05);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.sample-episode[data-shot-id="shot-moon-garden-finish"] .cartoon-robot--luma {
|
|
218
|
+
transform: translateX(-14%) scale(1.05);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.cartoon-robot__antenna,
|
|
222
|
+
.cartoon-robot__head,
|
|
223
|
+
.cartoon-robot__body,
|
|
224
|
+
.cartoon-robot__arm,
|
|
225
|
+
.cartoon-robot__leg {
|
|
226
|
+
position: absolute;
|
|
227
|
+
left: 50%;
|
|
228
|
+
transform: translateX(-50%);
|
|
229
|
+
background:
|
|
230
|
+
radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.72), transparent 14%),
|
|
231
|
+
linear-gradient(145deg, color-mix(in srgb, var(--accent) 94%, white 22%), color-mix(in srgb, var(--accent) 82%, black 12%));
|
|
232
|
+
border: 2px solid rgba(255, 255, 255, 0.38);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.cartoon-robot__antenna {
|
|
236
|
+
top: 0;
|
|
237
|
+
width: 8%;
|
|
238
|
+
height: 10%;
|
|
239
|
+
border-radius: 999px;
|
|
240
|
+
box-shadow: 0 -10px 0 -2px var(--accent);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.cartoon-robot__head {
|
|
244
|
+
top: 9%;
|
|
245
|
+
width: 58%;
|
|
246
|
+
height: 26%;
|
|
247
|
+
border-radius: 42% 42% 36% 36%;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.cartoon-robot__eye {
|
|
251
|
+
position: absolute;
|
|
252
|
+
top: 40%;
|
|
253
|
+
width: 10%;
|
|
254
|
+
height: 9%;
|
|
255
|
+
border-radius: 999px;
|
|
256
|
+
background: #06101f;
|
|
257
|
+
box-shadow: 0 0 10px rgba(6, 16, 31, 0.45);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.cartoon-robot__eye--left {
|
|
261
|
+
left: 34%;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.cartoon-robot__eye--right {
|
|
265
|
+
right: 34%;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.cartoon-robot__mouth {
|
|
269
|
+
position: absolute;
|
|
270
|
+
left: 50%;
|
|
271
|
+
bottom: 21%;
|
|
272
|
+
width: 30%;
|
|
273
|
+
height: 6%;
|
|
274
|
+
transform: translateX(-50%);
|
|
275
|
+
border-radius: 999px;
|
|
276
|
+
background: #f8fff2;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.sample-episode[data-speaker="miko"] .cartoon-robot--miko .cartoon-robot__mouth,
|
|
280
|
+
.sample-episode[data-speaker="luma"] .cartoon-robot--luma .cartoon-robot__mouth {
|
|
281
|
+
height: 14%;
|
|
282
|
+
bottom: 17%;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.cartoon-robot__body {
|
|
286
|
+
top: 38%;
|
|
287
|
+
width: 70%;
|
|
288
|
+
height: 33%;
|
|
289
|
+
border-radius: 28% 28% 34% 34%;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.cartoon-robot__arm {
|
|
293
|
+
top: 42%;
|
|
294
|
+
width: 15%;
|
|
295
|
+
height: 34%;
|
|
296
|
+
border-radius: 999px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.cartoon-robot__arm--left {
|
|
300
|
+
left: 12%;
|
|
301
|
+
transform: rotate(22deg);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.cartoon-robot__arm--right {
|
|
305
|
+
left: auto;
|
|
306
|
+
right: 12%;
|
|
307
|
+
transform: rotate(-22deg);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.sample-episode[data-shot-id="shot-glow-stone-teamwork"] .cartoon-robot__arm--right {
|
|
311
|
+
transform: rotate(-54deg);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.cartoon-robot__leg {
|
|
315
|
+
top: 70%;
|
|
316
|
+
width: 17%;
|
|
317
|
+
height: 28%;
|
|
318
|
+
border-radius: 999px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.cartoon-robot__leg--left {
|
|
322
|
+
left: 36%;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.cartoon-robot__leg--right {
|
|
326
|
+
left: 62%;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.cartoon-broom {
|
|
330
|
+
position: absolute;
|
|
331
|
+
z-index: 6;
|
|
332
|
+
left: 42%;
|
|
333
|
+
bottom: 36%;
|
|
334
|
+
width: 16%;
|
|
335
|
+
height: 2.8%;
|
|
336
|
+
transform: rotate(-24deg);
|
|
337
|
+
border-radius: 999px;
|
|
338
|
+
background: #7de2ff;
|
|
339
|
+
box-shadow: 0 0 18px rgba(125, 226, 255, 0.48);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.cartoon-broom::after {
|
|
343
|
+
content: "";
|
|
344
|
+
position: absolute;
|
|
345
|
+
right: -8%;
|
|
346
|
+
top: 50%;
|
|
347
|
+
width: 22%;
|
|
348
|
+
height: 260%;
|
|
349
|
+
transform: translateY(-50%) rotate(18deg);
|
|
350
|
+
border-radius: 999px 999px 18px 18px;
|
|
351
|
+
background: #ffe18e;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.sample-episode[data-shot-id="shot-moon-garden-open"] .cartoon-broom {
|
|
355
|
+
opacity: 0.35;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.sample-episode__title {
|
|
359
|
+
position: absolute;
|
|
360
|
+
z-index: 7;
|
|
361
|
+
left: 34px;
|
|
362
|
+
top: 28px;
|
|
363
|
+
max-width: 380px;
|
|
364
|
+
margin: 0;
|
|
365
|
+
font-size: clamp(24px, 3vw, 48px);
|
|
366
|
+
line-height: 0.98;
|
|
367
|
+
letter-spacing: 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.sample-episode__shot {
|
|
371
|
+
position: absolute;
|
|
372
|
+
z-index: 7;
|
|
373
|
+
right: 34px;
|
|
374
|
+
top: 32px;
|
|
375
|
+
padding: 10px 14px;
|
|
376
|
+
border: 1px solid rgba(248, 255, 242, 0.18);
|
|
377
|
+
border-radius: 999px;
|
|
378
|
+
background: rgba(3, 12, 20, 0.68);
|
|
379
|
+
color: rgba(248, 255, 242, 0.84);
|
|
380
|
+
font-size: 13px;
|
|
381
|
+
font-weight: 800;
|
|
382
|
+
letter-spacing: 0.08em;
|
|
383
|
+
text-transform: uppercase;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.sample-episode__caption {
|
|
387
|
+
position: absolute;
|
|
388
|
+
z-index: 8;
|
|
389
|
+
left: 50%;
|
|
390
|
+
bottom: 38px;
|
|
391
|
+
width: min(820px, calc(100% - 70px));
|
|
392
|
+
transform: translateX(-50%);
|
|
393
|
+
padding: 14px 20px;
|
|
394
|
+
border: 1px solid rgba(248, 255, 242, 0.2);
|
|
395
|
+
border-radius: 18px;
|
|
396
|
+
background: rgba(2, 8, 14, 0.82);
|
|
397
|
+
box-shadow: 0 16px 34px rgba(0, 0, 0, 0.32);
|
|
398
|
+
font-size: clamp(18px, 2.1vw, 26px);
|
|
399
|
+
font-weight: 850;
|
|
400
|
+
line-height: 1.22;
|
|
401
|
+
text-align: center;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.sample-episode__timeline {
|
|
405
|
+
position: absolute;
|
|
406
|
+
z-index: 8;
|
|
407
|
+
left: 34px;
|
|
408
|
+
right: 34px;
|
|
409
|
+
bottom: 14px;
|
|
410
|
+
height: 6px;
|
|
411
|
+
overflow: hidden;
|
|
412
|
+
border-radius: 999px;
|
|
413
|
+
background: rgba(248, 255, 242, 0.12);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.sample-episode__timeline-fill {
|
|
417
|
+
display: block;
|
|
418
|
+
width: var(--progress, 0%);
|
|
419
|
+
height: 100%;
|
|
420
|
+
border-radius: inherit;
|
|
421
|
+
background: linear-gradient(90deg, #7de2ff, #40ffbf, #ffe18e);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.sample-episode__proof {
|
|
425
|
+
position: absolute;
|
|
426
|
+
z-index: 7;
|
|
427
|
+
left: 34px;
|
|
428
|
+
top: 102px;
|
|
429
|
+
padding: 8px 12px;
|
|
430
|
+
border-radius: 999px;
|
|
431
|
+
background: rgba(3, 12, 20, 0.72);
|
|
432
|
+
color: rgba(248, 255, 242, 0.78);
|
|
433
|
+
font: 800 12px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@media (max-width: 760px) {
|
|
437
|
+
.sample-episode__frame {
|
|
438
|
+
width: calc(100vw - 24px);
|
|
439
|
+
border-radius: 18px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.sample-episode__title {
|
|
443
|
+
left: 18px;
|
|
444
|
+
top: 18px;
|
|
445
|
+
max-width: 260px;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.sample-episode__shot {
|
|
449
|
+
right: 18px;
|
|
450
|
+
top: 18px;
|
|
451
|
+
font-size: 10px;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.cartoon-robot {
|
|
455
|
+
min-width: 88px;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { episode, episodeSampleDescription, youtubeDraftMetadata } from "./episode";
|
|
2
|
+
|
|
3
|
+
export interface CartoonRouteSampleForVisual {
|
|
4
|
+
readonly time: number;
|
|
5
|
+
readonly frame: number;
|
|
6
|
+
readonly shotId?: string;
|
|
7
|
+
readonly captionId?: string;
|
|
8
|
+
readonly captionText?: string;
|
|
9
|
+
readonly dialogueLineId?: string;
|
|
10
|
+
readonly visemeId?: string;
|
|
11
|
+
readonly nodeUpdates?: readonly {
|
|
12
|
+
readonly characterId?: string;
|
|
13
|
+
readonly action?: string;
|
|
14
|
+
readonly emotion?: string;
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SampleEpisodeVisualOptions {
|
|
19
|
+
readonly sampleAt: (time: number) => CartoonRouteSampleForVisual;
|
|
20
|
+
readonly duration: number;
|
|
21
|
+
readonly fixedTime?: number;
|
|
22
|
+
readonly usesTypedAssets?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function installSampleEpisodeVisual(options: SampleEpisodeVisualOptions) {
|
|
26
|
+
const root = document.createElement("section");
|
|
27
|
+
root.id = "sample-episode-visual";
|
|
28
|
+
root.className = "sample-episode";
|
|
29
|
+
root.setAttribute("aria-label", "Aura3D cartoon sample episode preview");
|
|
30
|
+
root.innerHTML = `
|
|
31
|
+
<div class="sample-episode__frame">
|
|
32
|
+
<div class="sample-episode__aura-host-slot" data-aura-host-slot></div>
|
|
33
|
+
<div class="sample-episode__moon" aria-hidden="true"></div>
|
|
34
|
+
<div class="sample-episode__skyline" aria-hidden="true"></div>
|
|
35
|
+
<div class="sample-episode__garden" aria-hidden="true"></div>
|
|
36
|
+
<div class="sample-episode__path" aria-hidden="true"></div>
|
|
37
|
+
<div class="sample-episode__stones" aria-hidden="true"></div>
|
|
38
|
+
<div class="sample-episode__flowers" aria-hidden="true"></div>
|
|
39
|
+
${robotMarkup("miko", "Miko")}
|
|
40
|
+
${robotMarkup("luma", "Luma")}
|
|
41
|
+
<div class="cartoon-broom" aria-hidden="true"></div>
|
|
42
|
+
<h1 class="sample-episode__title">${escapeHtml(episode.episodePlan.title)}</h1>
|
|
43
|
+
<div class="sample-episode__shot" data-sample-shot-label>Shot 1 / 3</div>
|
|
44
|
+
<div class="sample-episode__proof">Aura3D cartoon contract · captions · visemes · render queue</div>
|
|
45
|
+
<div class="sample-episode__caption" data-sample-caption></div>
|
|
46
|
+
<div class="sample-episode__timeline" aria-hidden="true">
|
|
47
|
+
<span class="sample-episode__timeline-fill" data-sample-progress></span>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
`;
|
|
51
|
+
document.body.appendChild(root);
|
|
52
|
+
|
|
53
|
+
const frame = root.querySelector<HTMLElement>(".sample-episode__frame");
|
|
54
|
+
const hostSlot = root.querySelector<HTMLElement>("[data-aura-host-slot]");
|
|
55
|
+
const appHost = document.querySelector<HTMLElement>("#app");
|
|
56
|
+
if (frame && hostSlot && appHost) {
|
|
57
|
+
hostSlot.replaceWith(appHost);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const caption = root.querySelector<HTMLElement>("[data-sample-caption]");
|
|
61
|
+
const shotLabel = root.querySelector<HTMLElement>("[data-sample-shot-label]");
|
|
62
|
+
const progress = root.querySelector<HTMLElement>("[data-sample-progress]");
|
|
63
|
+
const queryTime = new URLSearchParams(window.location.search).get("sampleTime");
|
|
64
|
+
const fixedTime = options.fixedTime ?? (queryTime ? Number(queryTime) : undefined);
|
|
65
|
+
const start = performance.now();
|
|
66
|
+
|
|
67
|
+
function render(time: number) {
|
|
68
|
+
const sample = options.sampleAt(clampTime(time, options.duration));
|
|
69
|
+
const shotIndex = Math.max(0, episode.shotTimeline.shots.findIndex((shot) => shot.shotId === sample.shotId));
|
|
70
|
+
const speaker = sample.nodeUpdates?.find((update) => update.action === "speak")?.characterId ?? "";
|
|
71
|
+
const progressPercent = Math.max(0, Math.min(100, (sample.time / options.duration) * 100));
|
|
72
|
+
|
|
73
|
+
root.dataset.shotId = sample.shotId ?? "";
|
|
74
|
+
root.dataset.captionId = sample.captionId ?? "";
|
|
75
|
+
root.dataset.speaker = speaker;
|
|
76
|
+
root.dataset.visemeId = sample.visemeId ?? "";
|
|
77
|
+
root.dataset.usesTypedAssets = options.usesTypedAssets ? "true" : "false";
|
|
78
|
+
root.dataset.cartoonSampleEpisode = "moon-garden-cleanup";
|
|
79
|
+
root.dataset.youtubeDraftTitle = youtubeDraftMetadata.title;
|
|
80
|
+
|
|
81
|
+
if (caption) {
|
|
82
|
+
caption.textContent = sample.captionText ?? "Two tiny robots clean a glowing moon garden.";
|
|
83
|
+
}
|
|
84
|
+
if (shotLabel) {
|
|
85
|
+
shotLabel.textContent = `Shot ${shotIndex + 1} / ${episode.shotTimeline.shots.length}`;
|
|
86
|
+
}
|
|
87
|
+
if (progress) {
|
|
88
|
+
progress.style.setProperty("--progress", `${progressPercent}%`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
window.__AURA3D_CARTOON_SAMPLE_EPISODE__ = {
|
|
92
|
+
contractId: episodeSampleDescription.contractId,
|
|
93
|
+
episodeId: episode.episodePlan.episodeId,
|
|
94
|
+
title: episode.episodePlan.title,
|
|
95
|
+
route: "/",
|
|
96
|
+
sample,
|
|
97
|
+
visualLayer: {
|
|
98
|
+
id: root.id,
|
|
99
|
+
deterministicSampleTime: fixedTime ?? null,
|
|
100
|
+
screenshotTarget: "#sample-episode-visual",
|
|
101
|
+
renderedBy: "aura3d-scene",
|
|
102
|
+
usesTypedAssets: Boolean(options.usesTypedAssets),
|
|
103
|
+
characters: episode.episodePlan.characters.map((character) => character.id),
|
|
104
|
+
styleGuide: episode.storyBible.styleGuide.visualStyle,
|
|
105
|
+
youtubeDraftTitle: youtubeDraftMetadata.title
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (Number.isFinite(fixedTime)) {
|
|
111
|
+
render(Number(fixedTime));
|
|
112
|
+
return root;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const tick = () => {
|
|
116
|
+
render(((performance.now() - start) / 1000) % options.duration);
|
|
117
|
+
requestAnimationFrame(tick);
|
|
118
|
+
};
|
|
119
|
+
tick();
|
|
120
|
+
return root;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
declare global {
|
|
124
|
+
interface Window {
|
|
125
|
+
__AURA3D_CARTOON_SAMPLE_EPISODE__?: {
|
|
126
|
+
readonly contractId: string;
|
|
127
|
+
readonly episodeId: string;
|
|
128
|
+
readonly title: string;
|
|
129
|
+
readonly route: string;
|
|
130
|
+
readonly sample: CartoonRouteSampleForVisual;
|
|
131
|
+
readonly visualLayer: {
|
|
132
|
+
readonly id: string;
|
|
133
|
+
readonly deterministicSampleTime: number | null;
|
|
134
|
+
readonly screenshotTarget: string;
|
|
135
|
+
readonly renderedBy: "aura3d-scene";
|
|
136
|
+
readonly usesTypedAssets: boolean;
|
|
137
|
+
readonly characters: readonly string[];
|
|
138
|
+
readonly styleGuide: string;
|
|
139
|
+
readonly youtubeDraftTitle: string;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function robotMarkup(id: "miko" | "luma", label: string) {
|
|
146
|
+
return `
|
|
147
|
+
<div class="cartoon-robot cartoon-robot--${id}" role="img" aria-label="${label} cartoon robot">
|
|
148
|
+
<span class="cartoon-robot__antenna"></span>
|
|
149
|
+
<span class="cartoon-robot__head">
|
|
150
|
+
<span class="cartoon-robot__eye cartoon-robot__eye--left"></span>
|
|
151
|
+
<span class="cartoon-robot__eye cartoon-robot__eye--right"></span>
|
|
152
|
+
<span class="cartoon-robot__mouth"></span>
|
|
153
|
+
</span>
|
|
154
|
+
<span class="cartoon-robot__body"></span>
|
|
155
|
+
<span class="cartoon-robot__arm cartoon-robot__arm--left"></span>
|
|
156
|
+
<span class="cartoon-robot__arm cartoon-robot__arm--right"></span>
|
|
157
|
+
<span class="cartoon-robot__leg cartoon-robot__leg--left"></span>
|
|
158
|
+
<span class="cartoon-robot__leg cartoon-robot__leg--right"></span>
|
|
159
|
+
</div>
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function clampTime(time: number, duration: number) {
|
|
164
|
+
if (!Number.isFinite(time)) return 0;
|
|
165
|
+
return Math.max(0, Math.min(duration - 1 / 30, time));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function escapeHtml(value: string) {
|
|
169
|
+
return value.replace(/[&<>"']/g, (character) => {
|
|
170
|
+
switch (character) {
|
|
171
|
+
case "&":
|
|
172
|
+
return "&";
|
|
173
|
+
case "<":
|
|
174
|
+
return "<";
|
|
175
|
+
case ">":
|
|
176
|
+
return ">";
|
|
177
|
+
case '"':
|
|
178
|
+
return """;
|
|
179
|
+
case "'":
|
|
180
|
+
return "'";
|
|
181
|
+
default:
|
|
182
|
+
return character;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
test("2.5D animation recording lane is disabled for release-facing proof", async ({ page }) => {
|
|
4
|
+
await page.goto("/?view=concept-2-5d&sampleTime=24&animateParallax=1");
|
|
5
|
+
|
|
6
|
+
await expect(page.locator("#sample-episode-visual")).toBeVisible();
|
|
7
|
+
await expect(page.locator("#concept-episode-2-5d")).toHaveCount(0);
|
|
8
|
+
|
|
9
|
+
const proof = await page.evaluate(() => ({
|
|
10
|
+
rejectedViews: (window as unknown as {
|
|
11
|
+
__AURA3D_CARTOON_TEMPLATE__?: { readonly rejectedViews?: readonly string[]; readonly rejectedViewReason?: string };
|
|
12
|
+
}).__AURA3D_CARTOON_TEMPLATE__?.rejectedViews ?? [],
|
|
13
|
+
conceptProof: (window as unknown as { __AURA3D_CARTOON_2_5D_PROOF__?: unknown }).__AURA3D_CARTOON_2_5D_PROOF__
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
expect(proof.conceptProof).toBeUndefined();
|
|
17
|
+
expect(proof.rejectedViews).toContain("concept-2-5d");
|
|
18
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
test("2.5D concept query is quarantined from the release-facing cartoon route", async ({ page }) => {
|
|
4
|
+
await page.setViewportSize({ width: 1440, height: 900 });
|
|
5
|
+
await page.goto("/?view=concept-2-5d&sampleTime=24¶llax=0.78&animateParallax=1");
|
|
6
|
+
|
|
7
|
+
await expect(page.locator("#sample-episode-visual")).toBeVisible();
|
|
8
|
+
await expect(page.locator("#concept-episode-2-5d")).toHaveCount(0);
|
|
9
|
+
await expect(page.locator("[data-sample-caption]")).toContainText(/tiny circle|stones|cleanup/i);
|
|
10
|
+
|
|
11
|
+
const quarantine = await page.evaluate(() => ({
|
|
12
|
+
releaseFacingView: document.body.dataset.cartoonReleaseFacingView,
|
|
13
|
+
rejectedViews: document.body.dataset.cartoonRejectedViews,
|
|
14
|
+
conceptProof: (window as unknown as { __AURA3D_CARTOON_2_5D_PROOF__?: unknown }).__AURA3D_CARTOON_2_5D_PROOF__,
|
|
15
|
+
template: (window as unknown as {
|
|
16
|
+
__AURA3D_CARTOON_TEMPLATE__?: {
|
|
17
|
+
readonly releaseFacingViews?: readonly string[];
|
|
18
|
+
readonly rejectedViews?: readonly string[];
|
|
19
|
+
readonly rejectedViewReason?: string;
|
|
20
|
+
};
|
|
21
|
+
}).__AURA3D_CARTOON_TEMPLATE__
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
expect(quarantine.releaseFacingView).toBe("sample-episode-visual");
|
|
25
|
+
expect(quarantine.rejectedViews).toContain("concept-2-5d");
|
|
26
|
+
expect(quarantine.conceptProof).toBeUndefined();
|
|
27
|
+
expect(quarantine.template?.releaseFacingViews).toEqual(["sample-episode-visual"]);
|
|
28
|
+
expect(quarantine.template?.rejectedViews).toContain("concept-2-5d");
|
|
29
|
+
expect(quarantine.template?.rejectedViewReason).toMatch(/notTrue3D|still-image|cutout/i);
|
|
30
|
+
});
|