# === SETTINGS ===

fontPath = "~/Downloads/Kario-39C3-VariableFont/Desktop/KarioDuplexVar-Roman.ttf"
word = "UNIWIDTH/DUPLEX"
numLines = 7

minWeight = 10
maxWeight = 100
widthValue = 76

canvasWidth = 1000
canvasHeight = 1000
margin = 50

backgroundColor = (0,0,0)
textColor = (1,1,1)

lineSpacingFactor = 0.92
verticalOffset = -8


# === SETUP ===

newPage(canvasWidth, canvasHeight)
fill(*backgroundColor)
rect(0, 0, canvasWidth, canvasHeight)


# === HELPER ===

def getLineWidth(text, size, lineIndex):
    font(fontPath)
    fontSize(size)
    total = 0

    midIndex = (len(text) - 1) / 2
    endWeight = maxWeight - (maxWeight - minWeight) / (numLines - 1) * lineIndex
    startWeight = minWeight + (maxWeight - minWeight) / (numLines - 1) * lineIndex

    for charIndex, char in enumerate(text):
        if lineIndex == 0 or lineIndex == numLines - 1:
            weight = startWeight + (endWeight - startWeight) / (len(text) - 1) * charIndex
        else:
            baseWeight = startWeight + (endWeight - startWeight) / (len(text) - 1) * charIndex
            distToMid = abs(charIndex - midIndex)
            maxBoost = (maxWeight - minWeight) / 2
            boost = maxBoost * (1 - (distToMid / midIndex) ** 2)
            boostFactor = 1 - abs(lineIndex - (numLines - 1) / 2) / ((numLines - 1) / 2)
            weight = baseWeight + boost * boostFactor

        weight = max(minWeight, min(maxWeight, weight))
        fontVariations(wght=weight, wdth=widthValue)
        advance, _ = textSize(char)
        total += advance
    return total


# === LAYOUT ===

testSize = 1000
maxTextWidth = max(getLineWidth(word, testSize, i) for i in range(numLines))
maxTextHeight = numLines * testSize * lineSpacingFactor

usableWidth = canvasWidth - 2 * margin
usableHeight = canvasHeight - 2 * margin

scaleFactor = min(usableWidth / maxTextWidth, usableHeight / maxTextHeight)
finalFontSize = testSize * scaleFactor
lineSpacing = finalFontSize * lineSpacingFactor

textBlockHeight = numLines * lineSpacing
startY = (canvasHeight + textBlockHeight) / 2 - lineSpacing + verticalOffset


# === DRAW TEXT AS OUTLINES ===

midIndex = (len(word) - 1) / 2
fill(*textColor)

for lineIndex in range(numLines):
    y = startY - lineIndex * lineSpacing
    lineWidth = getLineWidth(word, finalFontSize, lineIndex)
    x = (canvasWidth - lineWidth) / 2

    endWeight = maxWeight - (maxWeight - minWeight) / (numLines - 1) * lineIndex
    startWeight = minWeight + (maxWeight - minWeight) / (numLines - 1) * lineIndex

    # Build a formatted string (character by character)
    fs = FormattedString()
    fs.font(fontPath)
    fs.fontSize(finalFontSize)

    for charIndex, char in enumerate(word):
        if lineIndex == 0 or lineIndex == numLines - 1:
            weight = startWeight + (endWeight - startWeight) / (len(word) - 1) * charIndex
        else:
            baseWeight = startWeight + (endWeight - startWeight) / (len(word) - 1) * charIndex
            distToMid = abs(charIndex - midIndex)
            maxBoost = (maxWeight - minWeight) / 2
            boost = maxBoost * (1 - (distToMid / midIndex) ** 2)
            boostFactor = 1 - abs(lineIndex - (numLines - 1) / 2) / ((numLines - 1) / 2)
            weight = baseWeight + boost * boostFactor

        weight = max(minWeight, min(maxWeight, weight))
        fs.append(char, fontVariations=dict(wght=weight, wdth=widthValue), fill=textColor)

    # Convert the formatted string to outlines
    path = BezierPath()
    path.textBox(fs, (x, y, lineWidth, lineSpacing))
    drawPath(path)


# === EXPORT ===

saveImage("~/Desktop/Desktop/Interpolation-outlined.pdf")
