projecting 3d onto 2d plane is not showing up correctly I am trying to learn about 3d graphics from first principles, so i have decided to implement a simple thing, create a circle in 3d space &amp; rotate it along some axis. I understand the basics theory.

position circle somewhere in 3d space.
calculate its projection on some plane.

Once i can get this i can use rotation matrix to calculate the new position of vertices. but i am a bit stuck at 2nd step.
this is my code:
import pygame
import math

(width, height) = (600, 500)
screen = pygame.display.set_mode((width, height))
pygame.display.flip()


running = True

K = 8   # view plane distance
cz = 10 # z location of circle initially.

# Pyagme 0.0 is at top left , but i want to center it at window?? is this even coorect to do or is should just continue using top left.

def translate_coords_to_center(x , y):
    return (width/2 - x, height/2 - y)

# plots a pixel
def pixel(x,y,color=(100,20,30)):
    s = pygame.Surface((1,1))
    s.fill(color)
    r,r.x,r.y = s.get_rect(),x,y
    screen.blit(s,r)


# Draw the circle
def circle(cx, cy, cz, radius):
    N = 100
    PI = 3.14
    angle = 360 / N


    for i in range(N):
        x2 = cx + radius * math.cos(PI* angle * i / 180)
        y2 = cy + radius * math.sin(PI* angle * i / 180)

        # Do a 2d projection
        x2 = K* x2 / cz
        y2 = K* y2 / cz

        pixel(x2, y2)


while running:
    x, y = translate_coords_to_center(0,0)
    circle(x, y, cz, 50)
    cz += 1
    pygame.display.flip()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

When i change the z position of circle, i get something like the below image, I am expecting the circle to not change its position but only its size, ( i know this cant be true as i am dividing by z ), am i missing some translation step? :

EDIT:  Adding the translation after projection is also not working:
import pygame
import math

(width, height) = (600, 500)
screen = pygame.display.set_mode((width, height))
pygame.display.flip()


running = True

K = 8   
cz = 10 

def translate_coords_to_center(x , y):
    return (width/2 - x, height/2 - y)


def pixel(x,y,color=(100,20,30)):
    s = pygame.Surface((1,1))
    s.fill(color)
    r,r.x,r.y = s.get_rect(),x,y
    screen.blit(s,r)

def circle(cx, cy, cz, radius):
    N = 100
    PI = 3.14
    angle = 360 / N


    for i in range(N):
        x2 = cx + radius * math.cos(PI* angle * i / 180)
        y2 = cy + radius * math.sin(PI* angle * i / 180)

        # Do a 2d projection
        x2 = K* x2 / cz
        y2 = K* y2 / cz
        sx, sy = translate_coords_to_center(x2, y2)

        pixel(sx, sy)



while running:
    
    circle(0,0, cz, 50) # this works correctly, but circles are centered at top left corner of screen,
    cz += 1
    pygame.display.flip()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
Your translate_coords_to_center(0,0) function should be done after you have done the projection from 3d to 2d.
e.g.
for i in range(N):
        x2 = cx + radius * math.cos(PI* angle * i / 180)
        y2 = cy + radius * math.sin(PI* angle * i / 180)

        # Do a 2d projection
        x2 = K* x2 / cz
        y2 = K* y2 / cz

        sx, sy = translate_coords_to_center(x2, y2)

        pixel(sy, sy)

while running:
    circle(0, 0, cz, 50)
    cz += 1
    pygame.display.flip()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

The effect you are seeing is caused by 2 things.

Because a constant x/y offset is incorrectly added in 3d world space the array of circles will appear to the right and below of the camera's position.
Because the 0,0 origin of view/camera space is not the centre of the display, instead it's at the top-left (Adding the window centre coords AFTER projection fixes that)