Skip to content

Instantly share code, notes, and snippets.

@Cdaprod
Created May 28, 2025 01:32
Show Gist options
  • Save Cdaprod/0dcf30e1865b6c550c9ed9369d7e3559 to your computer and use it in GitHub Desktop.
Save Cdaprod/0dcf30e1865b6c550c9ed9369d7e3559 to your computer and use it in GitHub Desktop.
Blender Shellfish iOS Terminal Drive BPY Script
import bpy
import os
# 1. ——— CONFIGURE these paths & data —————————————
FONT_PATH = "/path/to/JetBrainsMono Nerd Font.ttf" # ← point to your local Nerd Font
LINES = [
"cd ~/Projects/Cdaprod",
"git status",
"exa -lh --color=always",
"ssh [email protected]",
# …add as many lines as you like…
]
CHAR_SPACING = 0.22 # horizontal spacing
LINE_SPACING = 0.30 # vertical spacing (if you want y-axis depth per line)
DEPTH_SPACING = 0.05 # z-axis offset per line (for the dive)
EXTRUDE_DEPTH = 0.02 # thickness of each character
BEVEL_DEPTH = 0.0005 # subtle bevel for nicer edges
# 2. ——— Load font ————————————————————————————
if not os.path.isfile(FONT_PATH):
raise FileNotFoundError(f"Font not found at {FONT_PATH}")
font = bpy.data.fonts.load(FONT_PATH)
# 3. ——— Clear existing text objects ——————————————————
for obj in [o for o in bpy.data.objects if o.type == 'FONT']:
bpy.data.objects.remove(obj, do_unlink=True)
# 4. ——— Create text chars in 3D space —————————————
for row, line in enumerate(LINES):
for col, ch in enumerate(line):
# new text curve
txt_curve = bpy.data.curves.new(f"char_{row}_{col}", 'FONT')
txt_curve.body = ch
txt_curve.font = font
txt_curve.extrude = EXTRUDE_DEPTH
txt_curve.bevel_depth = BEVEL_DEPTH
txt_obj = bpy.data.objects.new(f"char_{row}_{col}", txt_curve)
bpy.context.collection.objects.link(txt_obj)
# position: x = col*CHAR_SPACING, y=0, z = -row*DEPTH_SPACING
txt_obj.location = (
col * CHAR_SPACING,
0,
-row * DEPTH_SPACING
)
# rotate so that +X is right, +Z is forward, camera looks down -Y
txt_obj.rotation_euler = (1.5708, 0, 0)
# 5. ——— Material: Emissive “Cdaprod Blue” text over dark bg —————
mat = bpy.data.materials.new("CdaprodBlue_Text")
mat.use_nodes = True
tree = mat.node_tree
for n in tree.nodes:
tree.nodes.remove(n)
# nodes
nodes = tree.nodes
out = nodes.new("ShaderNodeOutputMaterial")
emit = nodes.new("ShaderNodeEmission")
emit.inputs['Color'].default_value = (0.231, 0.608, 0.953, 1) # #3B85F3
emit.inputs['Strength'].default_value = 3.0
tree.links.new(emit.outputs['Emission'], out.inputs['Surface'])
# assign to all char meshes
for obj in [o for o in bpy.data.objects if o.type == 'FONT']:
obj.data.materials.append(mat)
# 6. ——— Set world background to dark purple —————————
world = bpy.data.worlds['World']
world.use_nodes = True
nodes = world.node_tree.nodes
bg = nodes.get('Background')
if bg:
bg.inputs['Color'].default_value = (0.118, 0.0, 0.169, 1) # dark purple #1E002B
bg.inputs['Strength'].default_value = 0.2
# 7. ——— Camera setup & animation ————————————————————
cam = bpy.data.objects.get('Camera')
if cam is None:
cam_data = bpy.data.cameras.new("TerminalCam")
cam = bpy.data.objects.new("TerminalCam", cam_data)
bpy.context.collection.objects.link(cam)
bpy.context.scene.camera = cam
# initial cam position (above the first row, a bit back on Y)
cam.location = (len(LINES[0]) * CHAR_SPACING / 2, 1.5, 0)
cam.rotation_euler = (1.0472, 0, 1.5708) # tilt down 60°, face negative Z
cam.data.lens = 35
cam.data.dof.use_dof = True
cam.data.dof.focus_distance = 1.5
cam.data.dof.aperture_fstop = 1.8
# keyframe start
cam.keyframe_insert(data_path="location", frame=1)
# end position: dive past last row
end_z = - (len(LINES) - 1) * DEPTH_SPACING
cam.location = (len(LINES[0]) * CHAR_SPACING / 2, 0.1, end_z)
cam.keyframe_insert(data_path="location", frame=250)
# 8. ——— Render settings ——————————————————————
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.samples = 128
scene.render.film_transparent = True
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.frame_start = 1
scene.frame_end = 250
print("Setup complete! Press F12 to render animation.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment