def var(f, depth=0): t = f.a.progress(f.i, loops=1, easefn="qeio") cold = (StyledString( "COLDTYPE", Style(co, 800 - t.e * 700, wdth=t.e, ro=1, tu=-90 + t.e * 50, r=1)).pens().align(f.a.r).f(1).s(0).sw(23 - depth).pmap( lambda i, p: p.nlt(warp_fn(0, 0, mult=30)))) cold = (cold.color_phototype(f.a.r, blur=2 + depth * 5, cut=120 + depth * 5, rgba=[1, 0, 1, 1]).as_set().blendmode( skia.BlendMode.kDifference)) if depth < 5: cold.insert( 0, var.func(Frame((f.i - 3) % var.duration, f.a), depth=depth + 1)) if depth == 0: return DATPens([ #DATPen().rect(f.a.r).f(1), cold.color_phototype(f.a.r, blur=5) ]) else: return cold
def ableton(f): b, t = f.a.r.divide(300, "mny") def dp(s, notes, reverb, h, stroke=False): n = drums.fv(f.i, lambda t: t.name in notes, reverb) e = n.ease() color = hsl(h+0.1*e, s=0.6, l=0.6, a=e*0.95) #color = hsl(0, 0, 1, a=e*0.95) style = Style(o, 350+10*e, wdth=0.1+e*0.1, wght=0.75+e*0.25, slnt=e*0.25, ro=1, tu=-30) _dp = StyledString(s, style).fit(f.a.r.w-100).pen().removeOverlap().align(t).translate(0, -50) if stroke: _dp.f(None).s(color).sw(10) else: _dp.f(color) return _dp warp = warp_fn(xa=10, ya=10, mult=95, base=0) warp2 = warp_fn(xa=10, ya=10, mult=35, base=0) sns = synth.fv(f.i, reverb=[2, 30], accumulate=1) sdp = StyledString("BCDE", Style(o, 250, wdth=0.5, wght=1, tu=-50, r=1, ro=1)).pens().align(b).translate(0, 50).f(None) for s in sns: n = 3-[59, 60, 62, 64].index(int(s.timeable.name)) sdp[n].rotate(-45*s.ease()).f(hsl(s.ease(), l=0.7, a=s.ease())) sdp.pmap(lambda i,p: p.flatten(5).nonlinear_transform(warp2)) return DATPens([ dp("KICK", ["36"], [5, 25], 0.9), dp("RIMSHOT", ["39"], [3, 20], 0.0), dp("SNARE", ["40", "41"], [5, 20], 0.6), dp("CLAP", ["42"], [5, 50], 0.65), dp("HAT", ["43"], [2, 10], 0.15, True), dp("HAT", ["44"], [3, 50], 0.15, True), dp("CLAVE", ["46"], [5, 100], 0.4).flatten(10).nonlinear_transform(warp), dp("COWBELL", ["47"], [5, 20], 0.7).rotate(15), dp("TOMTOM", ["48", "49", "50"], [3, 25], 0.1), sdp ])
def coldtype(r): kp = kern_pairs = { ("L", "D"): -5, ("T", "Y"): -20, ("Y", "P"): 10, ("P", "E"): -100 } style = Style(font, 650, fill="random", wdth=1, tu=-50, r=1, ro=1, kp=kp) pens = (StyledString("COLDTYPE", style).fit(1250).pens().align(r)) pens.pmap(lambda idx, p: (p.f(hsl(0.05 + idx / len(pens) * 0.75, s=0.6, l=0.55)).flatten( 5).nonlinear_transform(warp_fn(mult=35)))) return (pens.understroke().rotate(5).scale(0.4))
def nameplate(r, fontSize=500, wdth=0.25, rotate=0): return (DATPens([ DATPen().rect(r).f(0), (StyledString( "COLDTYPE", Style(obv, fontSize, wdth=wdth, tu=-50, r=1, rotate=rotate)).pens().f(1).understroke( sw=35).align(r).color_phototype(r, cutw=10)), (DATPen().glyph(logos["goodhertz_logo_2019"]).scale(0.5).align(r).f( hsl(0.61, s=0.7, l=0.6)).flatten(5).nlt(warp_fn(mult=90)).color_phototype( r, blur=8).blendmode(skia.BlendMode.kMultiply)) ]).color_phototype(r, blur=1, cutw=50))
def code1(f): e = f.a.progress(f.i).e * 1.05 def render_code(txt, styles): style = styles[0] if len(styles) > 0 else "default" font, fill = lookup.get(style, defaults) return txt, Style(font, 22, fill=fill) def rotate(i, p): ee = ease("eeo", min(1, max(0, (e - rnds1[i]) * 5))) p.rotate(ee[0] * (360 if i % 2 == 0 else -360)) return p ri = f.a.r.inset(20) rt = PythonCode(ri, Path(__FILE__).read_text()[:], render_code, graf_style=GrafStyle(leading=8)) return (rt.align( ri, "mnx", "mxy", tv=1).scale(1).remove_blanklines().collapse().pmap(rotate).pmap( lambda i, p: (p.flatten(2).nlt(warp_fn(0, 0, mult=25)))))
def render(f): # Get the kick and cowbell values b/c we’re going to use # these in the initial lockup kick = drums.fv(f.i, [36], [5, 50]) cowbell = drums.fv(f.i, [47], [15, 75]) ### INITIAL LOCKUP # Use the `Graf` to set two StyledStrings vertically # Adjust the tracking (via `tu` (a shortcut for (t)racking-in-font-(u)nits)) # using the cowbell midi note, using standard easing # also rekern the T & Y together to be a little closer (via the (k)ern-(p)airs) # so when they get stroked they don’t create an overly black visual mass style = Style(obvs, 390, tu=-150 + 550 * cowbell.ease(), wdth=1 - cowbell.ease() * 0.75, ro=1, r=1, kp={"T/Y": -25}) strings = [StyledString(t, style) for t in ["COLD", "TYPE"]] pens = Graf(strings, f.a.r, leading=math.floor(kick.ease() * 50)).pens().align(f.a.r) ### SNARE (+claps) # Visualize the snare hits by shearing the line composition # & rotating the two letters that correspond to where the snares hit in an 8-count snare = drums.fv(f.i, [40], [10, 40]) if snare.count == 1: pens[0].translate(-150 * snare.ease(), 0) pens[1].translate(150 * snare.ease(), 0) pens[0].ffg("L").rotate(snare.ease() * -270) else: pens[0].translate(150 * snare.ease(), 0) pens[1].translate(-150 * snare.ease(), 0) # Rotate the outer P shape w/o moving the counter pens[1].ffg("P").mod_contour(0, lambda c: c.rotate(snare.ease() * 270)) ### RIMSHOT # When the second rim hits (we ignore the first one b/c it’s in sync with a hat (see below)), # let’s rotate the P’s counter rim = drums.fv(f.i, [39], [5, 5]) if rim.count == 2: pens[1].ffg("P").mod_contour(1, lambda c: c.rotate(rim.ease() * -270)) ### BIG KICKS # Use the kick signal to scale up some letters line, glyph = (0, "C") if kick.count == 1 else (1, "Y") pens[line].ffg(glyph).scale(1 + 0.5 * kick.ease()) ### HI-HATS # Definitely the most complicated bit of all the code: # Get the hat signal from the midi, with an even preverb-reverb (10, 10) # To mimic the regular action of a drummer hitting a hi-hat hat = drums.fv(f.i, [43], [10, 10]) # For the first hat, move the counter of the O in the first line if hat.count == 1: pens[0].ffg("O").mod_contour(1, lambda c: c.translate(80 * hat.ease(), 0)) # For the second hat, move the counter of the D in the first line # This time make it a little fancier, first translating it down # & then rotating it as well, to make it seem like it's falling # and then bouncing back up from the bottom of the outer shape elif hat.count == 2: pens[0].ffg("D").mod_contour( 1, lambda c: c.translate(-30 * hat.ease(), -100 * hat.ease()). rotate(hat.ease() * 110)) # And now for our most complicated trick... # Move the T crossbar, first on the left-hand side (hat 3) # And then on the right-hand side (hat 4) elif hat.count in [3, 4]: def move_t_top(idx, x, y): if hat.count == 3 and 0 <= idx <= 6: return x - 150 * hat.ease(), y elif hat.count == 4 and 22 <= idx <= 30: return x + 150 * hat.ease(), y pens[1].ffg("T").map_points(move_t_top) # Finally (for the hats), exaggerate the horizontality of the E counters elif hat.count == 5: def move_e_contour(idx, x, y): if 9 <= idx <= 13 or 20 <= idx <= 25: x -= 75 * hat.ease() #if 0 <= idx <= 33: # y -= 50*hat.ease() return x, y pens[1].ffg("E").map_points( move_e_contour) #.translate(hat.ease()*150, 0) ### TOMTOM # And lastly, use the tom signal to push up the outside of the O in the first line tom = drums.fv(f.i, [50], [5, 10]) pens[0].ffg("O").mod_contour(0, lambda c: c.translate(0, -80 * tom.ease())) ### BRANDING fp = f.a.prg(f.i, easefn="linear").e ghz_logo = DATPen().glyph(logos["goodhertz_logo_2019"]) ghz_logo.scale(0.2).align(f.a.r, y="mny").translate(0, 100).nonlinear_transform( warp_fn(speed=fp * 3, rz=3, mult=10)) # return both elements to the renderer # color elements with rgb primitives so we can # channel separate them in after effects later return [ ghz_logo.f(1, 0, 0).skew(cowbell.ease() * 1), pens.f(0, 1, 0).reversePens().understroke(s=(0, 0, 1), sw=15).translate(0, 100) ]