Skip to content

Instantly share code, notes, and snippets.

@hirocarma
Created August 6, 2025 09:28
Show Gist options
  • Save hirocarma/36a04c3f88a6d322bc55cdfb59663fe0 to your computer and use it in GitHub Desktop.
Save hirocarma/36a04c3f88a6d322bc55cdfb59663fe0 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import cv2
import numpy as np
import sys
import os
import math
CANVAS_WIDTH, CANVAS_HEIGHT = 1920, 1080
BASE_SIZE = (640, 360)
TARGET_SIZE = (160, 90)
def ensure_dir(path):
os.makedirs(path, exist_ok=True)
def interpolate(start, end, ratio):
return int(start * (1 - ratio) + end * ratio)
def create_canvas():
return np.full((CANVAS_HEIGHT, CANVAS_WIDTH, 3), 128, dtype=np.uint8)
def draw_triangle(canvas, base_x, base_y, height, color):
side = int(2 * height / math.sqrt(3))
top = (base_x, base_y)
left = (base_x, base_y + height)
right = (base_x + side, base_y + height)
pts = np.array([top, left, right], np.int32).reshape((-1, 1, 2))
cv2.fillPoly(canvas, [pts], color)
def draw_rectangle(canvas, top_left, width, height, color):
bottom_right = (top_left[0] + width, top_left[1] + height)
cv2.rectangle(canvas, top_left, bottom_right, color, thickness=-1)
def move_object(
output_dir,
start_size,
end_size,
steps,
move_vertical=True,
color=(255, 0, 0),
triangle_color=(0, 255, 255),
):
ensure_dir(output_dir)
dx = 3
triangle_x = 0
direction = 1
triangle_ratio = 0.4
for step in range(steps + 1):
canvas = create_canvas()
cv2.rectangle(canvas, (0, 0), BASE_SIZE, (0, 0, 0), thickness=-1)
interp = step / steps
width = interpolate(start_size[0], end_size[0], interp)
height = interpolate(start_size[1], end_size[1], interp)
if move_vertical:
x, y = 0, step
else:
x = CANVAS_WIDTH - width - step
y = 0
draw_rectangle(canvas, (x, y), width, height, color)
# triangle animation
if triangle_ratio > 0.2 and triangle_ratio < 0.6:
if start_size[1] > end_size[1]:
triangle_ratio -= 0.0001
else:
triangle_ratio += 0.0001
triangle_height = int(height * triangle_ratio)
triangle_side = int(2 * triangle_height / math.sqrt(3))
max_triangle_x = max(width - triangle_side, 0)
triangle_x += direction * dx
if triangle_x >= max_triangle_x or triangle_x <= 0:
triangle_x = max(0, min(triangle_x, max_triangle_x))
direction *= -1
base_x = x + triangle_x
base_y = y + int(height * 0.3)
draw_triangle(canvas, base_x, base_y, triangle_height, triangle_color)
filename = os.path.join(output_dir, f"frame_{step:04d}.jpg")
cv2.imwrite(filename, canvas)
# -Mimineko runs away.
def move_A():
move_object(
output_dir="move_A",
start_size=BASE_SIZE,
end_size=TARGET_SIZE,
steps=CANVAS_HEIGHT - 90,
move_vertical=True,
color=(255, 0, 0),
triangle_color=(253, 253, 253),
)
# -Niikura chases after.
def move_B():
move_object(
output_dir="move_B",
start_size=TARGET_SIZE,
end_size=BASE_SIZE,
steps=CANVAS_WIDTH - 640,
move_vertical=False,
color=(0, 255, 0),
triangle_color=(192, 183, 255),
)
def move_AB():
output_dir = "move_AB"
ensure_dir(output_dir)
start_A, end_A = BASE_SIZE, TARGET_SIZE
start_B, end_B = TARGET_SIZE, BASE_SIZE
steps_A = CANVAS_HEIGHT - end_A[1]
steps_B = CANVAS_WIDTH - end_B[0]
triangle_x_A = triangle_x_B = 0
triangle_ratio_A = triangle_ratio_B = 0.4
direction_A = direction_B = 1
y_A = y_r = 0
dx = 3
for frame in range(steps_B + 1):
canvas = create_canvas()
cv2.rectangle(canvas, (0, 0), start_A, (0, 0, 0), thickness=-1)
# A object -mimineko
if y_A <= steps_A:
y_r += 1
if y_r >= int(CANVAS_HEIGHT / CANVAS_WIDTH * 10):
y_r = 0
else:
y_A += 1
interp_A = y_A / steps_A
width_A = interpolate(start_A[0], end_A[0], interp_A)
height_A = interpolate(start_A[1], end_A[1], interp_A)
draw_rectangle(canvas, (0, y_A), width_A, height_A, (255, 0, 0))
if triangle_ratio_A > 0.2 and triangle_ratio_A < 0.6:
triangle_ratio_A -= 0.0001
triangle_height_A = int(height_A * triangle_ratio_A)
triangle_side_A = int(2 * triangle_height_A / math.sqrt(3))
max_triangle_x_A = max(width_A - triangle_side_A, 0)
triangle_x_A += direction_A * dx
if triangle_x_A >= max_triangle_x_A or triangle_x_A <= 0:
triangle_x_A = max(0, min(triangle_x_A, max_triangle_x_A))
direction_A *= -1
draw_triangle(
canvas,
triangle_x_A,
y_A + int(height_A * 0.3),
triangle_height_A,
(253, 253, 253),
)
# B object -niikura
interp_B = frame / steps_B
width_B = interpolate(start_B[0], end_B[0], interp_B)
height_B = interpolate(start_B[1], end_B[1], interp_B)
x_B = CANVAS_WIDTH - width_B - frame
y_B = 0
draw_rectangle(canvas, (x_B, y_B), width_B, height_B, (0, 255, 0))
if triangle_ratio_B > 0.2 and triangle_ratio_B < 0.6:
triangle_ratio_B += 0.0001
triangle_height_B = int(height_B * triangle_ratio_B)
triangle_side_B = int(2 * triangle_height_B / math.sqrt(3))
max_triangle_x_B = max(width_B - triangle_side_B, 0)
triangle_x_B += direction_B * dx
if triangle_x_B >= max_triangle_x_B or triangle_x_B <= 0:
triangle_x_B = max(0, min(triangle_x_B, max_triangle_x_B))
direction_B *= -1
draw_triangle(
canvas,
x_B + triangle_x_B,
y_B + int(height_B * 0.3),
triangle_height_B,
(193, 182, 255),
)
filename = os.path.join(output_dir, f"frame_{frame:04d}.jpg")
cv2.imwrite(filename, canvas)
def main(argv):
move_A()
move_B()
move_AB()
if __name__ == "__main__":
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment