|
5 | 5 |
|
6 | 6 | Class 1 — characterful scrolling : KineticMarquee, WaveRider, SplitFlap |
7 | 7 | Class 2 — theatrical transitions : IrisSnap, VenetianShutters, MosaicResolve, |
8 | | - CRTCollapse, LightSlitRewrite |
| 8 | + CRTCollapse, LightSlitRewrite, ColumnRain, |
| 9 | + DropFromSky (slides in from any edge) |
9 | 10 | Class 3 — palette-animated text : RainbowChase, NeonTubeCrawl, ChromeSheen, |
10 | 11 | HazardStripes |
11 | 12 |
|
|
44 | 45 | from scrollkit.effects.scrolling import KineticMarquee, WaveRider, SplitFlap |
45 | 46 | from scrollkit.effects.transitions import ( |
46 | 47 | IrisSnap, VenetianShutters, MosaicResolve, CRTCollapse, LightSlitRewrite, |
| 48 | + ColumnRain, DropFromSky, |
47 | 49 | ) |
48 | 50 |
|
49 | 51 |
|
@@ -229,6 +231,64 @@ class LightSlitScene(_TransitionScene): |
229 | 231 | slit_color=0xFFFFFF)) |
230 | 232 |
|
231 | 233 |
|
| 234 | +class ColumnRainScene(_TransitionScene): |
| 235 | + LABEL = "RAIN" |
| 236 | + FACTORY = staticmethod(lambda: ColumnRain(cover_color=0x102840)) |
| 237 | + |
| 238 | + |
| 239 | +class _Pos: |
| 240 | + """A minimal content stand-in (just x/y) for DropFromSky to animate in a scene.""" |
| 241 | + |
| 242 | + def __init__(self, x, y): |
| 243 | + self.x = x |
| 244 | + self.y = y |
| 245 | + |
| 246 | + |
| 247 | +class DropScene(_Scene): |
| 248 | + """Announce, then slide a screen of content in from each edge with DropFromSky — |
| 249 | + top, then bottom, left, right — showing the new directional entry. DropFromSky |
| 250 | + is duck-typed (not an OverlayMask transition): it animates the content's own |
| 251 | + x/y via pre_render_hook, so the scene draws the text at that moving position.""" |
| 252 | + |
| 253 | + CATEGORY = "TRANSITION" |
| 254 | + LABEL = "DROP IN" |
| 255 | + STEPS = (("TOP", 0xFFCC22, "top"), |
| 256 | + ("BOTTOM", 0x66FF88, "bottom"), |
| 257 | + ("LEFT", 0xFF66AA, "left"), |
| 258 | + ("RIGHT", 0x66CCFF, "right")) |
| 259 | + HOLD = 16 # frames to hold each landed screen before the next |
| 260 | + |
| 261 | + async def setup(self, display): |
| 262 | + self._i = 0 |
| 263 | + self._hold = 0 |
| 264 | + self._pos = _Pos(0, CONTENT_Y) |
| 265 | + self._t = DropFromSky(direction=self.STEPS[0][2]) |
| 266 | + await self._t.start(display, lambda: None) |
| 267 | + |
| 268 | + async def run(self, display): |
| 269 | + label, color, _dir = self.STEPS[self._i] |
| 270 | + # Reset to the natural centred position, let the transition pull it to the |
| 271 | + # entry edge for this frame, draw the text there, then advance/restore. |
| 272 | + self._pos.x = _center_x(display, label) |
| 273 | + self._pos.y = CONTENT_Y |
| 274 | + self._t.pre_render_hook(self._pos) |
| 275 | + await display.draw_text(label, self._pos.x, self._pos.y, color) |
| 276 | + await self._t.render(display, self._pos) |
| 277 | + if self._t.is_complete: |
| 278 | + if self._hold < self.HOLD: |
| 279 | + self._hold += 1 |
| 280 | + else: |
| 281 | + self._hold = 0 |
| 282 | + self._i += 1 |
| 283 | + if self._i < len(self.STEPS): |
| 284 | + self._t = DropFromSky(direction=self.STEPS[self._i][2]) |
| 285 | + await self._t.start(display, lambda: None) |
| 286 | + |
| 287 | + @property |
| 288 | + def _effect_done(self): |
| 289 | + return self._i >= len(self.STEPS) |
| 290 | + |
| 291 | + |
232 | 292 | # --- Class 3: palette-animated bitmap text ---------------------------------- |
233 | 293 |
|
234 | 294 | class _PaletteScene(_Scene): |
@@ -281,7 +341,8 @@ class ShowcaseReel(DisplayContent): |
281 | 341 |
|
282 | 342 | SCENES = [ |
283 | 343 | MarqueeScene, WaveScene, FlapScene, # Class 1 |
284 | | - IrisScene, VenetianScene, MosaicScene, CRTScene, LightSlitScene, # Class 2 |
| 344 | + IrisScene, VenetianScene, MosaicScene, CRTScene, LightSlitScene, |
| 345 | + ColumnRainScene, DropScene, # Class 2 |
285 | 346 | RainbowScene, NeonScene, ChromeScene, HazardScene, # Class 3 |
286 | 347 | ] |
287 | 348 |
|
|
0 commit comments