pyvisualfx 0.1.0b1__py3-none-any.whl
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.
pyvisualfx/__init__.py
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
"""pyvisualfx: effects for a Pyctures scene. Draw some shapes, then turn one on.
|
|
2
|
+
|
|
3
|
+
from pyctures import *
|
|
4
|
+
from pyvisualfx import *
|
|
5
|
+
|
|
6
|
+
kaleidoscope(8) # on, eight segments
|
|
7
|
+
glow(0.8) # bright things shine
|
|
8
|
+
trail = trails(0.5, zoom=1.5, spin=20)
|
|
9
|
+
|
|
10
|
+
def update(dt):
|
|
11
|
+
trail.spin = 40 # a setting is a plain attribute: change it any time
|
|
12
|
+
|
|
13
|
+
EFFECTS APPLY IN THE ORDER THEY ARE TURNED ON, to everything the scene has
|
|
14
|
+
drawn, 2D or 3D. Each has ``off()``, ``on()`` and ``remove()``, and ``amount``
|
|
15
|
+
(0 to 1: how much of it is mixed in). ``clear_effects()`` takes them all away.
|
|
16
|
+
``look("dream")`` is several at once.
|
|
17
|
+
|
|
18
|
+
THE PAGE'S GRAPHICS CARD DOES THE WORK. Python never touches the page (it may be
|
|
19
|
+
in a worker, or on another computer). Each function here sends ONE command that
|
|
20
|
+
turns the effect on in the page, from ``web/visualfx.js`` (the very file that is the
|
|
21
|
+
JavaScript library; a Pyctures that has it built in says so with ``H_EFFECTS``,
|
|
22
|
+
and then this module reads no other file), and Python keeps a small object that
|
|
23
|
+
stands for it. Setting an attribute is one command more. The effects are run
|
|
24
|
+
once for each frame Python sends, straight after its drawing, on Python's clock:
|
|
25
|
+
so a scene recorded a frame at a time gives exactly the frames it should.
|
|
26
|
+
|
|
27
|
+
MUSIC: ``listen_to(sound_output())`` (or a synth: anything that makes sound in
|
|
28
|
+
the page), then ``react(shine, "strength", "bass", 0.3, 1.2)`` ties a setting
|
|
29
|
+
to the bass, the mids, the highs, the loudness or the pulse of a beat. That
|
|
30
|
+
is done in the page, on the beat, with no trip through Python. ``bass()``,
|
|
31
|
+
``mids()``, ``highs()``, ``loudness()`` and ``pulse()`` are the same numbers for
|
|
32
|
+
your own drawing, as the page last told them: a frame late.
|
|
33
|
+
|
|
34
|
+
YOUR OWN: ``shader("vec4 effect(vec2 uv) { return texture(picture, uv).bgra; }")``.
|
|
35
|
+
|
|
36
|
+
The effects, their settings and their ranges are those of the JavaScript library,
|
|
37
|
+
written into this file by ``scripts/sync_js.py``: this module is one file.
|
|
38
|
+
|
|
39
|
+
MIT licence.
|
|
40
|
+
"""
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
import re
|
|
44
|
+
import sys
|
|
45
|
+
|
|
46
|
+
__version__ = "0.0.0"
|
|
47
|
+
|
|
48
|
+
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
49
|
+
# Every effect, its settings and their ranges, as the JavaScript library has them. Written by
|
|
50
|
+
# scripts/sync_js.py (which runs that library and asks it): do not edit it by hand.
|
|
51
|
+
# EFFECTS:BEGIN
|
|
52
|
+
_TABLE = json.loads(r"""{"effects":{
|
|
53
|
+
"kaleidoscope":{"order":["segments"],"settings":{"segments":{"kind":"int","default":8,"min":2,"max":32},"angle":{"kind":"float","default":0,"min":-360,"max":360,"unit":"degrees"},"zoom":{"kind":"float","default":1,"min":0.2,"max":5},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"One slice of the picture, folded round and round. The slice starts at the middle and points right: turn it with angle."},
|
|
54
|
+
"mirror":{"order":["side"],"settings":{"side":{"kind":"choice","default":"left","choices":["left","right","top","bottom","four"]},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"One half of the picture shown on both sides, or one quarter in all four."},
|
|
55
|
+
"pixelate":{"order":["size"],"settings":{"size":{"kind":"float","default":10,"min":1,"max":100},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"Big square pixels."},
|
|
56
|
+
"waves":{"order":["size"],"settings":{"size":{"kind":"float","default":12,"min":0,"max":100},"length":{"kind":"float","default":160,"min":10,"max":1000},"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture ripples like a flag in the wind."},
|
|
57
|
+
"ripple":{"order":["size"],"settings":{"size":{"kind":"float","default":8,"min":0,"max":100},"length":{"kind":"float","default":60,"min":10,"max":1000},"speed":{"kind":"float","default":1,"min":-5,"max":5},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"Rings spreading from a point, as from a stone dropped in water."},
|
|
58
|
+
"wobble":{"order":["size"],"settings":{"size":{"kind":"float","default":14,"min":0,"max":100},"scale":{"kind":"float","default":120,"min":10,"max":1000},"speed":{"kind":"float","default":0.4,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture wobbles like jelly, or something seen under water."},
|
|
59
|
+
"swirl":{"order":["angle"],"settings":{"angle":{"kind":"float","default":180,"min":-1440,"max":1440,"unit":"degrees"},"radius":{"kind":"float","default":0,"min":0,"max":2000},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The middle of the picture twisted round, like stirred paint."},
|
|
60
|
+
"fisheye":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":-1,"max":1},"radius":{"kind":"float","default":0,"min":0,"max":2000},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"A bulge, as through a round lens. Below zero it pinches instead."},
|
|
61
|
+
"tunnel":{"order":["speed"],"settings":{"speed":{"kind":"float","default":0.4,"min":-5,"max":5},"repeat":{"kind":"int","default":2,"min":1,"max":12},"depth":{"kind":"float","default":0.5,"min":0.05,"max":4},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture becomes the walls of a tunnel you are flying down."},
|
|
62
|
+
"tile":{"order":["across"],"settings":{"across":{"kind":"int","default":3,"min":1,"max":40},"down":{"kind":"int","default":0,"min":0,"max":40},"flip":{"kind":"bool","default":false,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture repeated in rows and columns."},
|
|
63
|
+
"zoomBlur":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.25,"min":0,"max":1},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Blur and light","about":"Rushing towards a point."},
|
|
64
|
+
"spinBlur":{"order":["angle"],"settings":{"angle":{"kind":"float","default":8,"min":-90,"max":90,"unit":"degrees"},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Blur and light","about":"Spinning round a point."},
|
|
65
|
+
"rgbSplit":{"order":["size"],"settings":{"size":{"kind":"float","default":4,"min":0,"max":60},"angle":{"kind":"float","default":0,"min":-360,"max":360,"unit":"degrees"},"spread":{"kind":"bool","default":false,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Red and blue pulled apart, like a cheap lens or a bad signal."},
|
|
66
|
+
"hue":{"order":["shift"],"settings":{"shift":{"kind":"float","default":90,"min":-360,"max":360,"unit":"degrees"},"speed":{"kind":"float","default":0,"min":-720,"max":720},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Every colour moved round the colour wheel. With speed, the colours keep turning."},
|
|
67
|
+
"saturate":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1.6,"min":0,"max":4},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"More colour, or less: at 0 the picture is grey."},
|
|
68
|
+
"brighten":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1.3,"min":0,"max":4},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Brighter, or darker below 1."},
|
|
69
|
+
"contrast":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1.4,"min":0,"max":4},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Lights lighter and darks darker."},
|
|
70
|
+
"invert":{"order":[],"settings":{"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"A negative: every colour swapped for its opposite."},
|
|
71
|
+
"posterize":{"order":["levels"],"settings":{"levels":{"kind":"int","default":4,"min":2,"max":16},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Only a few shades of each colour, like a poster."},
|
|
72
|
+
"tint":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"gold"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Seen through coloured glass."},
|
|
73
|
+
"duotone":{"order":["dark","light"],"settings":{"dark":{"kind":"colour","default":"midnightblue"},"light":{"kind":"colour","default":"gold"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Two colours only: one for the dark parts and one for the light."},
|
|
74
|
+
"colourCycle":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"rainbow"},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"bands":{"kind":"float","default":1,"min":0.1,"max":8},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Brightness becomes a colour from a palette, and the colours move round."},
|
|
75
|
+
"scanlines":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":1},"size":{"kind":"float","default":3,"min":1,"max":40},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"Dark lines across the picture, as on an old screen."},
|
|
76
|
+
"crt":{"order":["curve"],"settings":{"curve":{"kind":"float","default":0.18,"min":0,"max":1},"lines":{"kind":"float","default":0.45,"min":0,"max":1},"size":{"kind":"float","default":3,"min":1,"max":40},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"An old television: curved glass, lines, and thin stripes of red, green and blue."},
|
|
77
|
+
"glitch":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":1},"speed":{"kind":"float","default":1,"min":0,"max":10},"seed":{"kind":"int","default":1,"min":0,"max":9999},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"A broken signal: blocks that jump sideways, a line that tears, a band of snow."},
|
|
78
|
+
"grain":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.18,"min":0,"max":1},"size":{"kind":"float","default":1.5,"min":0.5,"max":20},"seed":{"kind":"int","default":1,"min":0,"max":9999},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"The fine speckle of film."},
|
|
79
|
+
"vignette":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":1},"size":{"kind":"float","default":0.75,"min":0,"max":2},"colour":{"kind":"colour","default":"black"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Dark corners, which draw the eye to the middle."},
|
|
80
|
+
"edges":{"order":["strength"],"settings":{"strength":{"kind":"float","default":2,"min":0,"max":10},"size":{"kind":"float","default":1.5,"min":0.5,"max":20},"fill":{"kind":"float","default":0,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Only the outlines, each in its own colour."},
|
|
81
|
+
"dots":{"order":["size"],"settings":{"size":{"kind":"float","default":9,"min":2,"max":100},"angle":{"kind":"float","default":25,"min":-360,"max":360,"unit":"degrees"},"paper":{"kind":"colour","default":"black"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Printed in dots, big where the picture is bright, as a comic or a newspaper is."},
|
|
82
|
+
"letters":{"order":["size"],"settings":{"size":{"kind":"float","default":10,"min":4,"max":100},"colour":{"kind":"colour","default":"white"},"own":{"kind":"bool","default":true,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"The picture made of marks, as an old terminal would show it."},
|
|
83
|
+
"plasma":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"sunset"},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Slow rolling colour."},
|
|
84
|
+
"starfield":{"order":["speed"],"settings":{"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"stars":{"kind":"float","default":1,"min":0,"max":4},"colour":{"kind":"colour","default":"white"},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Flying through stars."},
|
|
85
|
+
"metaballs":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"neon"},"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"count":{"kind":"int","default":7,"min":1,"max":12},"size":{"kind":"float","default":1,"min":0.2,"max":4},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Blobs that melt into each other when they meet: a lava lamp."},
|
|
86
|
+
"flow":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"ocean"},"speed":{"kind":"float","default":0.2,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Colour that folds and curls like ink in water."},
|
|
87
|
+
"droste":{"order":["zoom"],"settings":{"zoom":{"kind":"float","default":3,"min":1.2,"max":10},"twist":{"kind":"int","default":1,"min":0,"max":4},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture inside itself, smaller each time, for ever. With a twist it winds in as a spiral."},
|
|
88
|
+
"rotozoom":{"order":["speed"],"settings":{"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"zoom":{"kind":"float","default":1.5,"min":0.2,"max":8},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The picture tiled, turning and zooming: an old demo-scene favourite."},
|
|
89
|
+
"hexagons":{"order":["size"],"settings":{"size":{"kind":"float","default":14,"min":3,"max":100},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"Six-sided pixels, like a honeycomb."},
|
|
90
|
+
"glassTiles":{"order":["size"],"settings":{"size":{"kind":"float","default":40,"min":6,"max":300},"strength":{"kind":"float","default":0.4,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"Seen through a wall of glass blocks."},
|
|
91
|
+
"frosted":{"order":["size"],"settings":{"size":{"kind":"float","default":6,"min":0,"max":60},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"Seen through frosted glass."},
|
|
92
|
+
"heatHaze":{"order":["size"],"settings":{"size":{"kind":"float","default":5,"min":0,"max":60},"scale":{"kind":"float","default":40,"min":5,"max":400},"speed":{"kind":"float","default":1,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The shimmer of hot air rising."},
|
|
93
|
+
"caustics":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":2},"scale":{"kind":"float","default":120,"min":20,"max":600},"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"colour":{"kind":"colour","default":"#bfe8ff"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The net of bright lines that sunlight makes on the floor of a pool."},
|
|
94
|
+
"shake":{"order":["strength"],"settings":{"strength":{"kind":"float","default":10,"min":0,"max":200},"speed":{"kind":"float","default":25,"min":1,"max":100},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"The whole picture shakes. Set strength when something hits, and let it fall away."},
|
|
95
|
+
"punch":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.15,"min":-0.9,"max":4},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Shapes of the picture","about":"A zoom in towards a point. Tie its strength to the beat."},
|
|
96
|
+
"motionBlur":{"order":["size"],"settings":{"size":{"kind":"float","default":24,"min":0,"max":300},"angle":{"kind":"float","default":0,"min":-360,"max":360,"unit":"degrees"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"Moving fast in one direction."},
|
|
97
|
+
"tiltShift":{"order":["strength"],"settings":{"strength":{"kind":"float","default":8,"min":0,"max":60},"size":{"kind":"float","default":70,"min":5,"max":1000},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"A band in focus and the rest blurred, which makes a scene look like a tiny model."},
|
|
98
|
+
"lightRays":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.7,"min":0,"max":3},"size":{"kind":"float","default":0.6,"min":0,"max":1},"threshold":{"kind":"float","default":0.6,"min":0,"max":1},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"Rays of light streaming out from a point, through whatever is bright."},
|
|
99
|
+
"streaks":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":3},"size":{"kind":"float","default":120,"min":0,"max":800},"threshold":{"kind":"float","default":0.6,"min":0,"max":1},"colour":{"kind":"colour","default":"#88aaff"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"Long sideways flares from bright lights, as a film camera makes."},
|
|
100
|
+
"softFocus":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":1},"size":{"kind":"float","default":6,"min":0,"max":60},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Blur and light","about":"A soft, dreamy haze over the bright parts."},
|
|
101
|
+
"smear":{"order":["length"],"settings":{"length":{"kind":"float","default":3,"min":0,"max":30},"size":{"kind":"float","default":40,"min":0,"max":400},"scale":{"kind":"float","default":150,"min":20,"max":1000},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":true,"group":"What was drawn stays","about":"What was drawn is carried away on a slow current, like wet paint."},
|
|
102
|
+
"stutter":{"order":["speed"],"settings":{"speed":{"kind":"float","default":8,"min":0.5,"max":60},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":true,"group":"What was drawn stays","about":"Only so many new pictures a second: the last one is held between them."},
|
|
103
|
+
"gradientMap":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"sunset"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Brightness becomes a colour from a palette, dark to light."},
|
|
104
|
+
"thermal":{"order":[],"settings":{"palette":{"kind":"palette","default":"thermal"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"A heat camera: cold is dark blue, hot is yellow and white."},
|
|
105
|
+
"nightVision":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1.6,"min":0,"max":6},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Green, grainy and bright in the dark, like a night-vision scope."},
|
|
106
|
+
"sepia":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"The warm brown of an old photograph."},
|
|
107
|
+
"threshold":{"order":["level"],"settings":{"level":{"kind":"float","default":0.5,"min":0,"max":1},"dark":{"kind":"colour","default":"black"},"light":{"kind":"colour","default":"white"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Two colours and nothing between: dark or light."},
|
|
108
|
+
"solarize":{"order":["level"],"settings":{"level":{"kind":"float","default":0.5,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"The bright parts turned to their opposite, as in an over-exposed photograph."},
|
|
109
|
+
"colourBleed":{"order":["size"],"settings":{"size":{"kind":"float","default":10,"min":0,"max":100},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Colours smeared sideways, as on old videotape."},
|
|
110
|
+
"rainbowEdges":{"order":["strength"],"settings":{"strength":{"kind":"float","default":2,"min":0,"max":10},"size":{"kind":"float","default":1.5,"min":0.5,"max":20},"speed":{"kind":"float","default":0.1,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Colours","about":"Every edge in the picture drawn in rainbow colours."},
|
|
111
|
+
"dither":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"gameboy"},"size":{"kind":"float","default":2,"min":1,"max":40},"strength":{"kind":"float","default":0.35,"min":0,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"A few colours made to pass for many with a pattern of dots, as old computers did."},
|
|
112
|
+
"interlace":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":1},"size":{"kind":"float","default":2,"min":1,"max":20},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"Every other line dark, swapping each frame, like old video."},
|
|
113
|
+
"led":{"order":["size"],"settings":{"size":{"kind":"float","default":8,"min":3,"max":80},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Screens and old computers","about":"A wall of round lamps."},
|
|
114
|
+
"emboss":{"order":["strength"],"settings":{"strength":{"kind":"float","default":2,"min":0,"max":10},"angle":{"kind":"float","default":135,"min":-360,"max":360,"unit":"degrees"},"size":{"kind":"float","default":1.5,"min":0.5,"max":20},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Pressed into grey metal: only the bumps and hollows show."},
|
|
115
|
+
"sharpen":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1,"min":0,"max":5},"size":{"kind":"float","default":1,"min":0.5,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Crisper edges."},
|
|
116
|
+
"sketch":{"order":["strength"],"settings":{"strength":{"kind":"float","default":3,"min":0,"max":10},"size":{"kind":"float","default":1.2,"min":0.5,"max":20},"paper":{"kind":"colour","default":"#f4efe2"},"colour":{"kind":"colour","default":"#2a2a33"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"A pencil drawing on paper."},
|
|
117
|
+
"cartoon":{"order":["levels"],"settings":{"levels":{"kind":"int","default":4,"min":2,"max":12},"strength":{"kind":"float","default":2.5,"min":0,"max":10},"size":{"kind":"float","default":1.5,"min":0.5,"max":20},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Flat colours and black outlines."},
|
|
118
|
+
"stainedGlass":{"order":["size"],"settings":{"size":{"kind":"float","default":40,"min":8,"max":400},"colour":{"kind":"colour","default":"#101010"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Pieces of coloured glass with dark lead between them."},
|
|
119
|
+
"crosshatch":{"order":["size"],"settings":{"size":{"kind":"float","default":6,"min":2,"max":60},"colour":{"kind":"colour","default":"#1a1a22"},"paper":{"kind":"colour","default":"#f6f2e8"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"Drawn, printed and painted","about":"Shaded with crossing pen lines: more lines where it is darker."},
|
|
120
|
+
"oil":{"order":["size"],"settings":{"size":{"kind":"float","default":4,"min":1,"max":30},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"heavy","feedback":false,"group":"Drawn, printed and painted","about":"Smoothed into patches of colour, like oil paint. Heavy: it looks at 36 places for every pixel."},
|
|
121
|
+
"dust":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":1},"seed":{"kind":"int","default":1,"min":0,"max":9999},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Specks and scratches, as on old film."},
|
|
122
|
+
"lightLeaks":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":2},"speed":{"kind":"float","default":0.2,"min":-5,"max":5},"colour":{"kind":"colour","default":"#ff7a2a"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Warm light creeping in from the sides, as in an old camera."},
|
|
123
|
+
"rain":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":2},"speed":{"kind":"float","default":1,"min":0,"max":5},"angle":{"kind":"float","default":12,"min":-80,"max":80,"unit":"degrees"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Rain falling in front of the picture."},
|
|
124
|
+
"snow":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.8,"min":0,"max":2},"speed":{"kind":"float","default":1,"min":0,"max":5},"size":{"kind":"float","default":3,"min":0.5,"max":20},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Snow falling in front of the picture."},
|
|
125
|
+
"bokeh":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":2},"size":{"kind":"float","default":30,"min":4,"max":200},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Soft discs of coloured light drifting by: lamps out of focus."},
|
|
126
|
+
"fog":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.6,"min":0,"max":1},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"scale":{"kind":"float","default":220,"min":20,"max":2000},"colour":{"kind":"colour","default":"#dfe6ee"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"Drifting mist, thicker towards the bottom."},
|
|
127
|
+
"lightning":{"order":["strength"],"settings":{"strength":{"kind":"float","default":1,"min":0,"max":3},"speed":{"kind":"float","default":1,"min":0,"max":10},"seed":{"kind":"int","default":1,"min":0,"max":9999},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"In front of the picture","about":"A flash, now and then."},
|
|
128
|
+
"warp":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"neon"},"speed":{"kind":"float","default":1,"min":-10,"max":10},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"A chequered tunnel rushing past."},
|
|
129
|
+
"voronoi":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"candy"},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Soft coloured cells that slowly shift."},
|
|
130
|
+
"moire":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"white"},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Two sets of rings crossing, making patterns neither has alone."},
|
|
131
|
+
"interference":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"ocean"},"speed":{"kind":"float","default":0.5,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Waves from four moving points, crossing."},
|
|
132
|
+
"aurora":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"aurora"},"speed":{"kind":"float","default":0.3,"min":-5,"max":5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"The northern lights over a night sky."},
|
|
133
|
+
"fire":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"fire"},"speed":{"kind":"float","default":1,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Flames rising from the bottom of the picture."},
|
|
134
|
+
"clouds":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"#3a8fdc"},"speed":{"kind":"float","default":0.1,"min":-5,"max":5},"scale":{"kind":"float","default":1,"min":0.1,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"A sky with drifting clouds."},
|
|
135
|
+
"matrixRain":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"#3dff7a"},"speed":{"kind":"float","default":1,"min":0,"max":10},"size":{"kind":"float","default":14,"min":6,"max":80},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Green marks falling in columns."},
|
|
136
|
+
"copperBars":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"rainbow"},"count":{"kind":"int","default":5,"min":1,"max":8},"speed":{"kind":"float","default":1,"min":-5,"max":5},"size":{"kind":"float","default":34,"min":4,"max":300},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"Shining bars sliding up and down: a demo-scene classic."},
|
|
137
|
+
"checkerFloor":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"#ff2a6d"},"dark":{"kind":"colour","default":"#101a3a"},"speed":{"kind":"float","default":1,"min":-10,"max":10},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"A chequered floor rushing towards you under a glowing horizon."},
|
|
138
|
+
"twister":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"candy"},"speed":{"kind":"float","default":1,"min":-5,"max":5},"size":{"kind":"float","default":0.22,"min":0.02,"max":0.5},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"Backdrops that need no drawing","about":"A twisting four-sided bar, another demo-scene classic."},
|
|
139
|
+
"spectrumBars":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"rainbow"},"count":{"kind":"int","default":32,"min":4,"max":64},"size":{"kind":"float","default":0.7,"min":0.05,"max":1},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"The music, drawn","about":"The music as bars: low notes at the left, high at the right."},
|
|
140
|
+
"spectrumRing":{"order":["palette"],"settings":{"palette":{"kind":"palette","default":"rainbow"},"size":{"kind":"float","default":90,"min":10,"max":1000},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"The music, drawn","about":"The music as bars round a ring."},
|
|
141
|
+
"waveformRing":{"order":["colour"],"settings":{"colour":{"kind":"colour","default":"white"},"size":{"kind":"float","default":110,"min":10,"max":1000},"strength":{"kind":"float","default":3,"min":0.5,"max":40},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":true,"cost":"light","feedback":false,"group":"The music, drawn","about":"The sound's own wave, bent into a ring."},
|
|
142
|
+
"beatFlash":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.5,"min":0,"max":2},"colour":{"kind":"colour","default":"white"},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"The music, drawn","about":"A flash of colour on each beat."},
|
|
143
|
+
"bassShake":{"order":["strength"],"settings":{"strength":{"kind":"float","default":14,"min":0,"max":200},"speed":{"kind":"float","default":25,"min":1,"max":100},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"light","feedback":false,"group":"The music, drawn","about":"The picture shakes with the bass."},
|
|
144
|
+
"blur":{"order":["radius"],"settings":{"radius":{"kind":"float","default":8,"min":0,"max":200},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"Out of focus."},
|
|
145
|
+
"glow":{"order":["strength"],"settings":{"strength":{"kind":"float","default":0.8,"min":0,"max":4},"threshold":{"kind":"float","default":0.5,"min":0,"max":1},"radius":{"kind":"float","default":24,"min":2,"max":200},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":false,"group":"Blur and light","about":"Bright things shine and spread light around them."},
|
|
146
|
+
"trails":{"order":["length"],"settings":{"length":{"kind":"float","default":0.5,"min":0,"max":20,"unit":"s"},"zoom":{"kind":"float","default":1,"min":0.1,"max":10},"spin":{"kind":"float","default":0,"min":-720,"max":720,"unit":"degrees"},"hue":{"kind":"float","default":0,"min":-720,"max":720,"unit":"degrees"},"dx":{"kind":"float","default":0,"min":-2000,"max":2000},"dy":{"kind":"float","default":0,"min":-2000,"max":2000},"x":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"y":{"kind":"float","default":null,"min":0,"max":4000,"place":true},"amount":{"kind":"float","default":1,"min":0,"max":1}},"backdrop":false,"cost":"some","feedback":true,"group":"What was drawn stays","about":"What was drawn stays and fades. With zoom, spin and hue it becomes the classic screensaver tunnel."}
|
|
147
|
+
},
|
|
148
|
+
"groups":["Shapes of the picture","Blur and light","What was drawn stays","Colours","Screens and old computers","Drawn, printed and painted","In front of the picture","Backdrops that need no drawing","The music, drawn","More"],
|
|
149
|
+
"looks":["dream","arcade","vhs","neon","comic","underwater","oldfilm","disco","gameboy","c64","noir","comicbook","storm","winter","cinema","terminal"],
|
|
150
|
+
"recipes":{"dream":[["glow",{"strength":1,"threshold":0.35,"radius":40}],["saturate",{"strength":1.3}],["vignette",{"strength":0.5}]],"arcade":[["glow",{"strength":0.7,"threshold":0.4,"radius":20}],["crt",{"curve":0.2,"lines":0.5}]],"vhs":[["saturate",{"strength":1.35}],["rgbSplit",{"size":3}],["glitch",{"strength":0.35}],["scanlines",{"strength":0.3,"size":4}],["grain",{"strength":0.2,"size":2}],["vignette",{"strength":0.45}]],"neon":[["edges",{"strength":3,"fill":0.15}],["glow",{"strength":1.4,"threshold":0.2,"radius":28}]],"comic":[["posterize",{"levels":4}],["dots",{"size":7}]],"underwater":[["wobble",{"size":10,"scale":160}],["tint",{"colour":"#7fd4ff"}],["glow",{"strength":0.5,"threshold":0.5}],["vignette",{"strength":0.6,"colour":"#001830"}]],"oldfilm":[["duotone",{"dark":"#1a1208","light":"#f2e2c0"}],["grain",{"strength":0.3,"size":2}],["vignette",{"strength":0.75}]],"disco":[["kaleidoscope",{"segments":10}],["hue",{"shift":0,"speed":60}],["glow",{"strength":0.8}]],"gameboy":[["dither",{"palette":"gameboy","size":3}]],"c64":[["dither",{"palette":"c64","size":3}],["scanlines",{"strength":0.2,"size":3}]],"noir":[["saturate",{"strength":0}],["contrast",{"strength":1.6}],["grain",{"strength":0.25,"size":2}],["vignette",{"strength":0.8}]],"comicbook":[["cartoon",{"levels":4}],["dots",{"size":5,"paper":"#101018"}]],"storm":[["rain",{"strength":0.7}],["lightning",{}],["fog",{"strength":0.35,"colour":"#8a94a8"}],["vignette",{"strength":0.6}]],"winter":[["tint",{"colour":"#cfe4ff"}],["snow",{}],["softFocus",{"strength":0.4}],["vignette",{"strength":0.4,"colour":"#0a1830"}]],"cinema":[["streaks",{"strength":0.5}],["tiltShift",{"strength":5}],["grain",{"strength":0.1}],["vignette",{"strength":0.5}]],"terminal":[["letters",{"size":9,"own":false,"colour":"#3dff7a"}],["glow",{"strength":0.6,"threshold":0.2,"radius":14}],["scanlines",{"strength":0.25}]]},
|
|
151
|
+
"lookAbout":{"dream":"Soft, glowing and rich.","arcade":"The curved glass of an old arcade machine.","vhs":"A worn videotape.","neon":"Glowing outlines in the dark.","comic":"A few flat colours, printed in dots.","underwater":"Blue, wobbling and dim at the edges.","oldfilm":"Brown, grainy and dark at the corners.","disco":"A kaleidoscope whose colours keep turning.","gameboy":"Four shades of green.","c64":"The colours of a 1980s home computer.","noir":"Black and white, high contrast, grainy.","comicbook":"Black outlines over printed dots.","storm":"Rain, lightning and fog.","winter":"Cold light and falling snow.","cinema":"A film camera: flares, a narrow focus, grain.","terminal":"Green marks on a dark screen."},
|
|
152
|
+
"palettes":["rainbow","fire","ocean","sunset","neon","candy","forest","ice","lava","mono","thermal","aurora","gameboy","c64","amiga","pico"],
|
|
153
|
+
"paletteColours":{"rainbow":["#ff2a2a","#ffd92a","#3cff5a","#2ad4ff","#5a3cff","#ff2ad4"],"fire":["#000000","#5a0a00","#d43a00","#ff9a1a","#ffe98a","#5a0a00"],"ocean":["#02102a","#0a3a7a","#1a8ad4","#6ae0e0","#e8fff8","#0a3a7a"],"sunset":["#1a0a3a","#6a1a7a","#e0407a","#ff8a3a","#ffd86a","#6a1a7a"],"neon":["#0a001a","#ff1ad9","#1affea","#f6ff1a","#7a1aff","#1affea"],"candy":["#ff8ad4","#ffd0e8","#8ad4ff","#b8ffd0","#fff0a0","#d0a0ff"],"forest":["#04140a","#0e4a22","#3a8a2a","#a8d44a","#f0f0a0","#0e4a22"],"ice":["#020818","#103a6a","#4a9ae0","#b8e8ff","#ffffff","#4a9ae0"],"lava":["#1a0000","#8a0a00","#ff3a00","#ff9a00","#ffe27a","#ff5a00"],"mono":["#000000","#ffffff"],"thermal":["#000000","#20008c","#cc0077","#ff3000","#ffd000","#ffffff"],"aurora":["#00ff9a","#00b0ff","#8a2be2","#00ff9a"],"gameboy":["#0f380f","#306230","#8bac0f","#9bbc0f"],"c64":["#000000","#352879","#6c5eb5","#9a6759","#b8c76f","#ffffff"],"amiga":["#000022","#0055aa","#ff8800","#ffffff"],"pico":["#1d2b53","#7e2553","#ff004d","#ffa300","#29adff","#fff1e8"]},
|
|
154
|
+
"aliases":{"bloom":"glow","colorCycle":"colourCycle","bulge":"fisheye","halftone":"dots","colorBleed":"colourBleed","godRays":"lightRays"}}""")
|
|
155
|
+
# EFFECTS:END
|
|
156
|
+
_EFFECTS = _TABLE["effects"]
|
|
157
|
+
_source = [None]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _snake(name):
|
|
161
|
+
return re.sub(r"[A-Z]", lambda m: "_" + m.group(0).lower(), name)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _camel(name):
|
|
165
|
+
return re.sub(r"_([a-z])", lambda m: m.group(1).upper(), name)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# Python's spelling of a setting: colour or color, and `from_` where a word is Python's own.
|
|
169
|
+
_SPELLING = {"color": "colour", "colors": "colours"}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _key(name):
|
|
173
|
+
name = _camel(name.rstrip("_"))
|
|
174
|
+
return _SPELLING.get(name, name)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _library():
|
|
178
|
+
"""The page's half as text that can be made into a function: a page is given no file to load."""
|
|
179
|
+
if _source[0] is None:
|
|
180
|
+
with open(os.path.join(_HERE, "web", "visualfx.js"), encoding="utf-8") as f:
|
|
181
|
+
_source[0] = f.read().replace("export {", "return {")
|
|
182
|
+
return _source[0]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class _Run:
|
|
186
|
+
"""One run of a scene: its page, and the effects made in it."""
|
|
187
|
+
|
|
188
|
+
def __init__(self, js=None):
|
|
189
|
+
self.js = js
|
|
190
|
+
self.api = None
|
|
191
|
+
self.next_id = 1
|
|
192
|
+
self.bands = [0.0, 0.0, 0.0, 0.0, 0.0]
|
|
193
|
+
self.hearing = False
|
|
194
|
+
self.dt = None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
_run = _Run()
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _pyctures():
|
|
201
|
+
# Looked up each time: in a browser every scene has its own copy of the module.
|
|
202
|
+
module = sys.modules.get("pyctures")
|
|
203
|
+
if module is None:
|
|
204
|
+
import pyctures as module
|
|
205
|
+
return module
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _page():
|
|
209
|
+
"""The page's effects for the scene that is running, made the first time one is wanted."""
|
|
210
|
+
global _run
|
|
211
|
+
p = _pyctures()
|
|
212
|
+
# A new run has a new `js`: what was made for the last run is gone with its page.
|
|
213
|
+
if _run.js is not p.js:
|
|
214
|
+
_run = _Run(p.js)
|
|
215
|
+
handle = getattr(p, "H_EFFECTS", None)
|
|
216
|
+
if handle is not None:
|
|
217
|
+
_run.api = p.JsRef(handle) # a Pyctures that has the effects built in
|
|
218
|
+
else:
|
|
219
|
+
lib = p.js.Function(_library())()
|
|
220
|
+
_run.api = lib.effects(p.canvas, {"fresh": True, "manual": True})
|
|
221
|
+
# The effects are run once for every frame Python sends, after its drawing, on Python's clock.
|
|
222
|
+
ending = getattr(getattr(p, "S", None), "ending", None)
|
|
223
|
+
if isinstance(ending, list):
|
|
224
|
+
ending.append(_frame)
|
|
225
|
+
_watch_dt(p)
|
|
226
|
+
return _run.api
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _watch_dt(p):
|
|
230
|
+
"""The seconds each frame is given (what update(dt) is told). A Pyctures that keeps it says so with S.dt;
|
|
231
|
+
one that does not is listened to where it hands dt to the scene's functions."""
|
|
232
|
+
call = getattr(p, "_call_frame_functions", None)
|
|
233
|
+
if hasattr(getattr(p, "S", None), "dt") or call is None or getattr(call, "_visualfx", False):
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
def frame_functions(dt):
|
|
237
|
+
_run.dt = dt
|
|
238
|
+
return call(dt)
|
|
239
|
+
frame_functions._visualfx = True
|
|
240
|
+
p._call_frame_functions = frame_functions
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _frame():
|
|
244
|
+
"""As a frame is sent: the last command in it runs the effects over what the frame drew."""
|
|
245
|
+
p = _pyctures()
|
|
246
|
+
if _run.js is not p.js or _run.api is None:
|
|
247
|
+
return
|
|
248
|
+
dt = getattr(p.S, "dt", None)
|
|
249
|
+
if not isinstance(dt, (int, float)):
|
|
250
|
+
dt = _run.dt
|
|
251
|
+
# A frame that is not one of the clock's (the page asked for a picture again) moves nothing on.
|
|
252
|
+
_run.dt = None
|
|
253
|
+
# What a file draws as it starts is a frame too, given no time (dt is 0): the effects are run on it, and nothing moves on.
|
|
254
|
+
if isinstance(dt, (int, float)) and dt >= 0:
|
|
255
|
+
_run.api.frame(dt)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _told(e):
|
|
259
|
+
"""What the page reports with a frame: the music's five numbers."""
|
|
260
|
+
bands = e.get("b") if hasattr(e, "get") else None
|
|
261
|
+
if bands:
|
|
262
|
+
_run.bands = [float(b) for b in bands]
|
|
263
|
+
_run.api.ack()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _in_page(target):
|
|
267
|
+
"""The target as an object in the page, when that is where it lives; else None."""
|
|
268
|
+
if target is None:
|
|
269
|
+
return None
|
|
270
|
+
if hasattr(type(target), "_enc"):
|
|
271
|
+
return target
|
|
272
|
+
page = getattr(target, "page", None)
|
|
273
|
+
if callable(page) and not hasattr(type(page), "_enc"):
|
|
274
|
+
page = page()
|
|
275
|
+
return page if hasattr(type(page), "_enc") else None
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class Effect:
|
|
279
|
+
"""What Python keeps of an effect that is on in the page. Its settings are plain attributes."""
|
|
280
|
+
|
|
281
|
+
def __init__(self, kind, settings, values, args):
|
|
282
|
+
api = _page()
|
|
283
|
+
object.__setattr__(self, "_kind", kind)
|
|
284
|
+
object.__setattr__(self, "_settings", settings)
|
|
285
|
+
object.__setattr__(self, "_values", values)
|
|
286
|
+
object.__setattr__(self, "active", True)
|
|
287
|
+
object.__setattr__(self, "_id", _run.next_id)
|
|
288
|
+
_run.next_id += 1
|
|
289
|
+
api.make(kind, self._id, args)
|
|
290
|
+
|
|
291
|
+
@property
|
|
292
|
+
def name(self):
|
|
293
|
+
return self._kind
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def settings(self):
|
|
297
|
+
return list(self._settings)
|
|
298
|
+
|
|
299
|
+
def _setting(self, name):
|
|
300
|
+
key = _key(name)
|
|
301
|
+
if key not in self._settings:
|
|
302
|
+
raise AttributeError("%s has no setting called %r. Its settings are %s"
|
|
303
|
+
% (_snake(self._kind), name, ", ".join(_snake(s) for s in self._settings)))
|
|
304
|
+
return key
|
|
305
|
+
|
|
306
|
+
def __getattr__(self, name):
|
|
307
|
+
if name.startswith("_"):
|
|
308
|
+
raise AttributeError(name)
|
|
309
|
+
return self._values.get(self._setting(name))
|
|
310
|
+
|
|
311
|
+
def __setattr__(self, name, value):
|
|
312
|
+
self.set(name, value)
|
|
313
|
+
|
|
314
|
+
def set(self, name, value):
|
|
315
|
+
"""Change a setting: effect.set("segments", 12) is effect.segments = 12."""
|
|
316
|
+
key = self._setting(name)
|
|
317
|
+
_check(self._kind, key, self._settings[key], value)
|
|
318
|
+
self._values[key] = value
|
|
319
|
+
_page().set(self._id, key, value)
|
|
320
|
+
|
|
321
|
+
def get(self, name):
|
|
322
|
+
return self._values.get(self._setting(name))
|
|
323
|
+
|
|
324
|
+
def describe(self, name):
|
|
325
|
+
"""What a dial needs to know of a setting: its range, its kind, where it starts."""
|
|
326
|
+
key = self._setting(name)
|
|
327
|
+
s = self._settings[key]
|
|
328
|
+
d = {"name": _snake(key), "kind": "text" if s["kind"] in ("colour", "palette") else s["kind"], "default": s.get("default")}
|
|
329
|
+
for k in ("min", "max", "choices"):
|
|
330
|
+
if k in s:
|
|
331
|
+
d[k] = s[k]
|
|
332
|
+
return d
|
|
333
|
+
|
|
334
|
+
def on(self):
|
|
335
|
+
object.__setattr__(self, "active", True)
|
|
336
|
+
_page().call(self._id, "on")
|
|
337
|
+
return self
|
|
338
|
+
|
|
339
|
+
def off(self):
|
|
340
|
+
object.__setattr__(self, "active", False)
|
|
341
|
+
_page().call(self._id, "off")
|
|
342
|
+
return self
|
|
343
|
+
|
|
344
|
+
def remove(self):
|
|
345
|
+
"""Take it off the scene for good."""
|
|
346
|
+
object.__setattr__(self, "active", False)
|
|
347
|
+
_page().call(self._id, "remove")
|
|
348
|
+
|
|
349
|
+
def __repr__(self):
|
|
350
|
+
return "<%s %s>" % (_snake(self._kind), ", ".join("%s=%r" % (_snake(k), v) for k, v in self._values.items() if k != "amount"))
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _check(kind, key, s, value):
|
|
354
|
+
"""A wrong value is said here, in Python, on the line that gave it: the page would say it a frame later."""
|
|
355
|
+
name, what = _snake(kind), _snake(key)
|
|
356
|
+
k = s["kind"]
|
|
357
|
+
if k == "choice":
|
|
358
|
+
if value not in s["choices"]:
|
|
359
|
+
raise ValueError("%s's %s is one of %s, not %r" % (name, what, ", ".join('"%s"' % c for c in s["choices"]), value))
|
|
360
|
+
elif k == "palette":
|
|
361
|
+
if isinstance(value, str) and value.lower() not in _TABLE["palettes"]:
|
|
362
|
+
raise ValueError('There is no palette called "%s". There are %s, or give a list of colours: ["navy", "magenta", "gold"]'
|
|
363
|
+
% (value, ", ".join(_TABLE["palettes"])))
|
|
364
|
+
elif k == "colour":
|
|
365
|
+
if not isinstance(value, (str, list, tuple)):
|
|
366
|
+
raise ValueError("%s's %s is a colour (\"gold\", \"#ff8800\"), not %r" % (name, what, value))
|
|
367
|
+
elif k == "bool":
|
|
368
|
+
pass
|
|
369
|
+
elif value is None and s.get("place"):
|
|
370
|
+
pass
|
|
371
|
+
elif isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
372
|
+
raise ValueError("%s's %s is a number, not %r" % (name, what, value))
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _maker(kind):
|
|
376
|
+
spec = _EFFECTS[kind]
|
|
377
|
+
order, settings = spec["order"], spec["settings"]
|
|
378
|
+
|
|
379
|
+
def make(*args, **options):
|
|
380
|
+
if len(args) > len(order):
|
|
381
|
+
raise TypeError("%s() was given %d values and takes %s. Its other settings go in by name: %s(%s)" % (
|
|
382
|
+
_snake(kind), len(args), "%d (%s)" % (len(order), ", ".join(order)) if order else "none", _snake(kind),
|
|
383
|
+
", ".join("%s=…" % _snake(n) for n in list(settings)[len(order):len(order) + 2])))
|
|
384
|
+
given = dict(zip(order, args))
|
|
385
|
+
for name, value in options.items():
|
|
386
|
+
key = _key(name)
|
|
387
|
+
if key not in settings:
|
|
388
|
+
raise TypeError("%s has no setting called %r. Its settings are %s" % (_snake(kind), name, ", ".join(_snake(s) for s in settings)))
|
|
389
|
+
given[key] = value
|
|
390
|
+
for key, value in given.items():
|
|
391
|
+
_check(kind, key, settings[key], value)
|
|
392
|
+
values = {k: s.get("default") for k, s in settings.items()}
|
|
393
|
+
values.update(given)
|
|
394
|
+
return Effect(kind, settings, values, [given])
|
|
395
|
+
|
|
396
|
+
make.__name__ = _snake(kind)
|
|
397
|
+
shown = ", ".join("%s=%r" % (_snake(k), s.get("default")) for k, s in settings.items() if k != "amount")
|
|
398
|
+
make.__doc__ = "Turn %s on: %s(%s). It gives the effect back: its settings are attributes, and it has off(), on() and remove()." % (
|
|
399
|
+
_snake(kind), _snake(kind), shown)
|
|
400
|
+
return make
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
__all__ = []
|
|
404
|
+
for _kind in _EFFECTS:
|
|
405
|
+
globals()[_snake(_kind)] = _maker(_kind)
|
|
406
|
+
__all__.append(_snake(_kind))
|
|
407
|
+
for _alias, _kind in _TABLE["aliases"].items():
|
|
408
|
+
globals()[_snake(_alias)] = globals()[_snake(_kind)]
|
|
409
|
+
__all__.append(_snake(_alias))
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class Look:
|
|
413
|
+
"""Several effects turned on together: look("dream")."""
|
|
414
|
+
|
|
415
|
+
def __init__(self, name, amount):
|
|
416
|
+
api = _page()
|
|
417
|
+
self.name = name
|
|
418
|
+
self._amount = amount
|
|
419
|
+
self._id = _run.next_id
|
|
420
|
+
_run.next_id += 1
|
|
421
|
+
api.make("look", self._id, [name, amount])
|
|
422
|
+
|
|
423
|
+
@property
|
|
424
|
+
def amount(self):
|
|
425
|
+
return self._amount
|
|
426
|
+
|
|
427
|
+
@amount.setter
|
|
428
|
+
def amount(self, value):
|
|
429
|
+
self._amount = value
|
|
430
|
+
_page().set(self._id, "amount", value)
|
|
431
|
+
|
|
432
|
+
def on(self):
|
|
433
|
+
_page().call(self._id, "on")
|
|
434
|
+
return self
|
|
435
|
+
|
|
436
|
+
def off(self):
|
|
437
|
+
_page().call(self._id, "off")
|
|
438
|
+
return self
|
|
439
|
+
|
|
440
|
+
def remove(self):
|
|
441
|
+
_page().call(self._id, "remove")
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def look(name, amount=1):
|
|
445
|
+
"""Several effects at once: look("dream"), look("arcade"), look("vhs"). The names: look_names()."""
|
|
446
|
+
key = re.sub(r"[\s_-]", "", str(name).lower())
|
|
447
|
+
if key not in _TABLE["looks"]:
|
|
448
|
+
raise ValueError('There is no look called "%s". There are %s' % (name, ", ".join(_TABLE["looks"])))
|
|
449
|
+
return Look(key, amount)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def shader(source, **settings):
|
|
453
|
+
"""Your own effect, from a program for the graphics card that has `vec4 effect(vec2 uv)`: the colour at one
|
|
454
|
+
place of the picture. Settings by name are numbers it can use: shader(source, speed=2). A mistake in it is
|
|
455
|
+
said by the page, with its line."""
|
|
456
|
+
if not isinstance(source, str) or not re.search(r"\beffect\s*\(", source):
|
|
457
|
+
raise ValueError('shader() takes a program that has a function `vec4 effect(vec2 uv)`: the colour at one place of the picture. '
|
|
458
|
+
'For example: shader("vec4 effect(vec2 uv) { return texture(picture, uv).bgra; }")')
|
|
459
|
+
table = {k: {"kind": "colour" if isinstance(v, str) else "bool" if isinstance(v, bool) else "float", "default": v} for k, v in settings.items()}
|
|
460
|
+
table["amount"] = {"kind": "float", "default": 1}
|
|
461
|
+
values = dict(settings, amount=1)
|
|
462
|
+
return Effect("shader", table, values, [source, {k: (list(v) if isinstance(v, tuple) else v) for k, v in settings.items()}])
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
def clear_effects():
|
|
466
|
+
"""Take every effect off the scene."""
|
|
467
|
+
_page().clearEffects()
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def listen_to(target):
|
|
471
|
+
"""What the music is taken from: sound_output(), a synth, a song or the microphone (anything that makes its
|
|
472
|
+
sound in the page). None stops listening."""
|
|
473
|
+
api = _page()
|
|
474
|
+
if target is None:
|
|
475
|
+
api.listen(None)
|
|
476
|
+
return
|
|
477
|
+
page = _in_page(target)
|
|
478
|
+
if page is None:
|
|
479
|
+
raise ValueError("listen_to() is given something that makes sound in the page: sound_output(), or a synth from make_synth()")
|
|
480
|
+
api.listen(page)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
_BANDS = ("bass", "mids", "highs", "loudness", "pulse")
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def react(effect, setting, band="loudness", low=None, high=None, **given):
|
|
487
|
+
"""Tie a setting to the music: react(shine, "strength", "bass", 0.3, 1.2) makes the glow 0.3 when there is
|
|
488
|
+
no bass and 1.2 when there is all of it. The bands: bass, mids, highs, loudness, pulse. It is done in the
|
|
489
|
+
page, on the beat."""
|
|
490
|
+
if not isinstance(effect, Effect):
|
|
491
|
+
raise ValueError('react() is given an effect, the name of one of its settings and what to follow: react(shine, "strength", "bass")')
|
|
492
|
+
key = effect._setting(setting)
|
|
493
|
+
which = {"level": "loudness", "beat": "pulse"}.get(str(band).lower(), str(band).lower())
|
|
494
|
+
if which not in _BANDS:
|
|
495
|
+
raise ValueError('"%s" is not something the music has. There are %s' % (band, ", ".join(_BANDS)))
|
|
496
|
+
low = given.get("from_", given.get("start", low))
|
|
497
|
+
high = given.get("to", given.get("end", high))
|
|
498
|
+
span = {}
|
|
499
|
+
if low is not None:
|
|
500
|
+
span["from"] = low
|
|
501
|
+
if high is not None:
|
|
502
|
+
span["to"] = high
|
|
503
|
+
_page().react(effect._id, key, which, span)
|
|
504
|
+
return effect
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _band(i):
|
|
508
|
+
def read():
|
|
509
|
+
api = _page()
|
|
510
|
+
if not _run.hearing:
|
|
511
|
+
_run.hearing = True
|
|
512
|
+
api.report(_told)
|
|
513
|
+
return _run.bands[i]
|
|
514
|
+
read.__name__ = _BANDS[i]
|
|
515
|
+
read.__doc__ = "The music's %s, from 0 to 1, as the page last told it (a frame ago). For a setting that must be on the beat, use react()." % _BANDS[i]
|
|
516
|
+
return read
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
bass, mids, highs, loudness, pulse = (_band(i) for i in range(5))
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def effects_quality(value):
|
|
523
|
+
"""How many of the picture's pixels the effects work on: 1 is all, 0.5 is half each way, "auto" lets the device decide."""
|
|
524
|
+
if value != "auto" and not (isinstance(value, (int, float)) and value > 0):
|
|
525
|
+
raise ValueError('effects_quality() is given a number from 0.25 to 1, or "auto"')
|
|
526
|
+
_page().effectsQuality(value)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def look_names():
|
|
530
|
+
return list(_TABLE["looks"])
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def effect_names():
|
|
534
|
+
return [_snake(k) for k in _EFFECTS]
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def palette_names():
|
|
538
|
+
return list(_TABLE["palettes"])
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
__all__ += ["shader", "look", "clear_effects", "listen_to", "react", "bass", "mids", "highs", "loudness", "pulse",
|
|
542
|
+
"effects_quality", "look_names", "effect_names", "palette_names"]
|