p5.disableFriendlyErrors = true
fullRaph = loadModel('raph.obj', true, () => {})
raphTex = loadImage('raph.jpg')
font = loadFont('https://fonts.gstatic.com/s/robotoslab/v13/BngbUXZYTXPIvIBgJJSb6s3BzlRRfKOFbvjoDIOWaG5iddG-1A.ttf')
createCanvas(600, 600, WEBGL)
setAttributes({ alpha: true })
drawingContext.enable(drawingContext.BLEND)
printShader = createShader(...printShaderSource())
bgColor = color('#ebeae1')
for (const piece of raphCuts) {
const fullRaphPiece = geomToPiece(fullRaph)
const targetPieces = round(random(6, 12))
while (raphPieces.length < targetPieces) {
raphPieces.push(...randomChunk(fullRaphPiece, round(random(1, 3))))
raphCuts = raphPieces.map(pieceToGeom)
const toPlace = [...raphCuts]
while (toPlace.length > 0) {
const piece = toPlace.shift()
const angleY = random(-0.2, 0.2)
const dAY = random(-1, 1) * 0.004
if (placedPieces.length === 0) {
const parent = random(placedPieces)
const s = random(0.2, 1.2)
const at = parent.at.copy().add(
placedPieces.push({ piece, at, s, angle: random(TWO_PI), angleY, dAY })
const minLoc = createVector()
const maxLoc = createVector()
for (const { at, s } of placedPieces) {
for (const axis of ['x', 'y']) {
minLoc[axis] = min(minLoc[axis], at[axis] - 100 * s)
maxLoc[axis] = max(maxLoc[axis], at[axis] + 100 * s)
const avgLoc = minLoc.copy().add(maxLoc).div(2)
for (const { at } of placedPieces) {
const numTexts = round(random(1, 4))
for (let i = 0; i < numTexts; i++) {
const parent = random(placedPieces)
const at = parent.at.copy().add(
const rz = random(-1, 1) * 0.5
const ry = random(-1, 1) * 0.2
const dRY = random(-1, 1) * 0.0005
const word = random('Raphaël de Courville Processing Community Lead Fellow'.split(' '))
texts.push({ s, at, word, rz, ry, dRY })
placedPieces.forEach(({ piece, at, s, angle, angleY, dAY }, i) => {
const staggeredT = map(t, 0.02*i, 0.7 + 0.02*i, 0, 1, true)
rotateY(angleY + dAY * frameCount)
printShader.setUniform('tex', raphTex)
printShader.setUniform('inkColor', [0,0,0])
printShader.setUniform('bgColor', [red(bgColor), green(bgColor), blue(bgColor)].map(v => v/255))
printShader.setUniform('ms', frameCount / 60 * 1000)
printShader.setUniform('density', pixelDensity())
drawingContext.disable(drawingContext.DEPTH_TEST)
texts.forEach(({ s, at, word, rz, ry, dRY }, i) => {
at.x + 15 * s + sin(frameCount * 0.1 + i),
at.y + 15 * s + cos(5 + frameCount * 0.07 + i)
rotateY(ry + dRY * frameCount)
textAlign(CENTER, CENTER)
drawingContext.enable(drawingContext.DEPTH_TEST)
const sceneLength = 7 * 60
const scene = floor(frameCount / sceneLength)
const progress = (frameCount % sceneLength) / sceneLength
if (scene !== prevScene) {
Ease.easeOutCubic(map(progress, 0, 0.1, 0, 1, true)) *
(1 - Ease.easeInCubic(map(progress, 0.88, 0.98, 0, 1, true)))