(2025) "Fantasti-Watch”, ‘Fantastic Four: First Steps’, Functional Prop Replica, Micro-Electronics
“Fantastic Four: First Steps” Movie Screen-shot
“Fantastic Four: First Steps” Movie Screen-shot
“Fantasti-Watch” V1, Full Assembly Render
“Fantasti-Watch” V1, Full Assembly Render
“Fantasti-Watch” V1, Electronics Render
“Fantasti-Watch” V1, Electronics Render
“Fantasti-Watch” V2, Full Assembly Render
“Fantasti-Watch” V2, Full Assembly Render
“Fantasti-Watch” V2, Electronics Render
“Fantasti-Watch” V2, Electronics Render
"Fantasti-Watch", V14 FINAL Assembly Render
"Fantasti-Watch", V14 FINAL Assembly Render
"Fantasti-Watch", V14 FINAL Electronics Render
"Fantasti-Watch", V14 FINAL Electronics Render
“Fantastic Four: First Steps” Movie Screen-Grab, Zoomed
“Fantastic Four: First Steps” Movie Screen-Grab, Zoomed
Early Integration test between ESP32-S3 and TFT Display
Early Integration test between ESP32-S3 and TFT Display
First Successful Graphics Test on TFT Display
First Successful Graphics Test on TFT Display
First Successful Graphics Test on TFT Display
First Successful Graphics Test on TFT Display
Graphite Powder Paint Job
Graphite Powder Paint Job
First Assembly, Electronics
First Assembly, Electronics
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype
Fantasti-Watch, Finished Prototype

First non-test Gif viewed on the display

First successful Gif integration Test

First Prototype, Functioning Showcase, Electronics fitted/Soldered

First Prototype, Audio/Charging Showcase, Electronics fitted/Soldered

First Prototype, Animations Showcase

First Prototype, Animations Showcase

Part List:

Custom CircuitPython Code:
# code.py 
import board, busio, displayio, time, os, gifio, digitalio, supervisor
from fourwire import FourWire
from adafruit_st7789 import ST7789
from displayio import ColorConverter, Colorspace
displayio.release_displays()
spi = busio.SPI(clock=board.D6, MOSI=board.D7)
bus = FourWire(
    spi,
    command=board.D8,
    chip_select=board.D9,
    reset=board.D10,
    baudrate=40_000_000 
)
display = ST7789(bus, width=240, height=145, rotation=90, rowstart=40, colstart=53)
display.auto_refresh = False 
btn = digitalio.DigitalInOut(board.D2)
btn.switch_to_input(pull=digitalio.Pull.UP)

if supervisor.runtime.usb_connected or (not btn.value):
    display.root_group = None
    display.refresh(minimum_frames_per_second=0)
    if supervisor.runtime.usb_connected:
        while supervisor.runtime.usb_connected:
            pass
    else:
        while True:
            pass
gif_files = sorted([f for f in os.listdir("/") if f.lower().endswith(".gif")])
if not gif_files:
    g = displayio.Group(); display.root_group = g
    bg = displayio.Bitmap(240, 155, 1); pal = displayio.Palette(1); pal[0] = 0x000000
    g.append(displayio.TileGrid(bg, pixel_shader=pal))
    print("No .gif files found on CIRCUITPY. Add some and press reset.")
    while True: time.sleep(1)
conv = ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED)
odg = None
tile = None
root = displayio.Group()
display.root_group = root
def show_gif(path):
    global odg, tile, root
    if odg:
        try: odg.deinit()
        except Exception: pass
    odg = gifio.OnDiskGif(path)
    start = time.monotonic()
    delay = odg.next_frame()
    decode_time = time.monotonic() - start
    tile = displayio.TileGrid(odg.bitmap, pixel_shader=conv)
    w, h = odg.bitmap.width, odg.bitmap.height
    tile.x = max(0, (240 - w) // 2)
    tile.y = max(0, (155 - h) // 2)
    root = displayio.Group()
    root.append(tile)
    display.root_group = root
    display.refresh(minimum_frames_per_second=0)
    return delay, decode_time
idx = 0
delay, decode_time = show_gif("/" + gif_files[idx])
last = btn.value
last_ms = time.monotonic()
def wait_with_button(seconds):
    global last, last_ms, idx, delay, decode_time
    deadline = time.monotonic() + seconds
    SLICE = 0.005   
    DEBOUNCE = 0.05 
    while True:
        now = time.monotonic()
        # check button edge
        reading = btn.value
        if reading != last and (now - last_ms) > DEBOUNCE:
            last_ms = now
            last = reading
            if not reading: 
                idx = (idx + 1) % len(gif_files)
                delay, decode_time = show_gif("/" + gif_files[idx])
                return 
        if now >= deadline:
            break
        time.sleep(SLICE)
while True:
    wait_with_button(max(0, delay - decode_time))
    t0 = time.monotonic()
    delay = odg.next_frame()
    display.refresh(minimum_frames_per_second=0)
    decode_time = time.monotonic() - t0

You may also like

Back to Top