Skip to content

Instantly share code, notes, and snippets.

@justvanrossum
justvanrossum / ConcentricCircles2024.py
Created September 5, 2024 12:35
Animated Concentric Circles remake of book cover (DrawBot script)
# In honor of https://www.instagram.com/p/C_iATyCiGu0/
# John Hinton / Dying (Pelican originals; Studies in social pathology)
# Designer unknown
def circle(x, y, d):
r = d / 2
oval(x - r, y - r, d, d)
@justvanrossum
justvanrossum / screen_info.py
Created June 6, 2019 06:30
macOS/Python: Get dimension info about active screens
from AppKit import NSScreen, NSDeviceSize, NSDeviceResolution
from Quartz import CGDisplayScreenSize
for i, screen in enumerate(NSScreen.screens(), 1):
description = screen.deviceDescription()
pw, ph = description[NSDeviceSize].sizeValue()
rx, ry = description[NSDeviceResolution].sizeValue()
mmw, mmh = CGDisplayScreenSize(description["NSScreenNumber"])
scaleFactor = screen.backingScaleFactor()
pw *= scaleFactor
@justvanrossum
justvanrossum / rename_fea_glyphs.py
Last active May 21, 2024 13:32
Rename glyph names in OpenType feature files
from functools import singledispatch
from io import StringIO
from fontTools.feaLib import ast
from fontTools.feaLib.error import FeatureLibError
from fontTools.feaLib.parser import Parser
def renameGlyphs(feaSource, renameFunc, glyphNames=()):
features = Parser(StringIO(feaSource), glyphNames=glyphNames).parse()
@justvanrossum
justvanrossum / convert_ds_to_ds5.py
Created September 15, 2022 11:55
Likely incomplete script that converts 'statmake' axis labels to DesignSpace 5 axis labels
import argparse
import sys
from fontTools.designspaceLib import AxisLabelDescriptor, DesignSpaceDocument
def main():
parser = argparse.ArgumentParser(
description="Converts statmake axis labels to DesignSpace 5.0 axis labels"
)
parser.add_argument("input", help="The source .designspace file")
@justvanrossum
justvanrossum / bezier_drawbot.py
Last active April 10, 2023 11:09
Bezier demo for DrawBot
# See this Twitter thread:
# https://twitter.com/MauriceMeilleur/status/1488347208709718021
def lerp(v1, v2, t):
return v1 + t * (v2 - v1)
def lerpPoint(p1, p2, t):
return lerp(p1[0], p2[0], t), lerp(p1[1], p2[1], t)
@justvanrossum
justvanrossum / make_named_instances_from_axis_labels.py
Created September 19, 2022 12:55
Rebuild the named instances in a designspace 5 file based on the axis labels. Use with caution!
import argparse
from itertools import product
import sys
from fontTools.designspaceLib import DesignSpaceDocument
def main():
parser = argparse.ArgumentParser(
description="Makes new named instances based on the axis labels"
)
@justvanrossum
justvanrossum / SevenNutsPuzzle.py
Last active July 18, 2022 20:47
Visualization and solution to "seven nuts" puzzle. Requires DrawBot for the visualization.
# https://twitter.com/jenskutilek/status/1548996988892479488
def drawNuts(nuts, matches, nutPositions):
for (bi1, bs1), (bi2, bs2) in matches:
with savedState():
strokeWidth(0.3 * distX)
if nuts[bi1][bs1] == nuts[bi2][bs2]:
stroke(0, 1, 0)
else:
@justvanrossum
justvanrossum / bezier_xy.py
Created May 30, 2022 15:23
Cubic Bezier: find Y given X
# https://twitter.com/mttymtt/status/1531022994323251202
# DrawBot visualization
# FontTools for helper code
from fontTools.misc.bezierTools import calcCubicParameters, solveCubic
scaleFactor = 500
pt0 = (0, 0)
pt1 = (0.37, 0.05)
@justvanrossum
justvanrossum / plotter_circle_spiral.py
Created December 8, 2021 21:12
[DrawBot] Given a circle radius and a pen thickness, create a spiral-ish path that fills a circle
# https://twitter.com/rosettatype/status/1468660017993854980
def plotter_circle_spiral(bez, center, radius, penWidth):
H = 0.5522847498 # Bezier circle magic constant
radius -= penWidth / 2
numRevolutions = ceil(radius / penWidth + 1)
xRadius = yRadius = radius
radiusDelta = radius / (numRevolutions - 1)
cx, cy = center
bez.moveTo((cx + radius, cy))
@justvanrossum
justvanrossum / StackOfSquares.py
Last active October 25, 2021 02:30
Create a simple animation with Python in DrawBot
# This script is part of a tutorial screencast: https://vimeo.com/149247423
CANVAS = 500
SQUARESIZE = 158
NSQUARES = 50
SQUAREDIST = 6
width = NSQUARES * SQUAREDIST
NFRAMES = 50