1import tkinter as tk
2import math
3import random
4import time
5
6# ==================== 1. Window Config & Global Parameters ====================
7WIDTH, HEIGHT = 980, 800
8FOV = 440 # 3D Projection focal distance
9CUBE_SIZE = 145 # 3D Bounding cube half-size
10
11# Color palettes
12PALETTES = {
13 "ruby_rose": {
14 "name": "Ruby Red (Crimson Passion)",
15 "edge": ["#ffebee", "#ffffff", "#ffcdd2", "#ff80ab"], # Petal luminous rim glow
16 "petal_high": ["#ff1744", "#ff2a55", "#ff5252", "#f50057"],# Petal illuminated surface
17 "petal_mid": ["#d50000", "#c51162", "#e91e63", "#ad1457"], # Petal main body
18 "petal_dark": ["#880e4f", "#4a001f", "#5c001e", "#3a0010"],# Petal shadow / base
19 "core": ["#fff9c4", "#fff59d", "#ffffff", "#ffe082"], # Stamen golden glimmer
20 "sepal": ["#2e7d32", "#4caf50", "#388e3c", "#1b5e20"], # Calyx emerald green
21 "stem": ["#1b5e20", "#2e7d32", "#144217", "#0d2b10"], # Stem deep forest
22 "cube": "#405878",
23 "bg": "#070913"
24 },
25 "pink_diamond": {
26 "name": "Pink Diamond (Soft Elegance)",
27 "edge": ["#ffffff", "#fff0f3", "#ffd6e0", "#ffccd5"],
28 "petal_high": ["#ff758f", "#ff8fa3", "#ffb3c1", "#ff4d6d"],
29 "petal_mid": ["#c9184a", "#a4133c", "#ff4d6d", "#d90429"],
30 "petal_dark": ["#590d22", "#800f2f", "#400817"],
31 "core": ["#ffffff", "#fff0f3", "#ffccd5"],
32 "sepal": ["#388e3c", "#4caf50", "#2e7d32"],
33 "stem": ["#1b5e20", "#2e7d32", "#144217"],
34 "cube": "#68507b",
35 "bg": "#0c0814"
36 },
37 "blue_enchantress": {
38 "name": "Sapphire Aurora (Glacial Blue)",
39 "edge": ["#e0fbfc", "#ffffff", "#caf0f8", "#90e0ef"],
40 "petal_high": ["#00b4d8", "#0077b6", "#48cae4", "#0096c7"],
41 "petal_mid": ["#023e8a", "#03045e", "#0077b6", "#1d3557"],
42 "petal_dark": ["#050c1e", "#0b132b", "#1c2541"],
43 "core": ["#ffffff", "#e0fbfc", "#caf0f8"],
44 "sepal": ["#1b4332", "#2d6a4f", "#40916c"],
45 "stem": ["#081c15", "#1b4332", "#133c2a"],
46 "cube": "#3a6073",
47 "bg": "#060913"
48 },
49 "golden_amber": {
50 "name": "Champagne Gold (Luminous Amber)",
51 "edge": ["#ffffff", "#fef9e7", "#fcf3cf", "#f9e79f"],
52 "petal_high": ["#f1c40f", "#f39c12", "#f5b041", "#f8c471"],
53 "petal_mid": ["#d4ac0d", "#b7950b", "#d68910", "#ba4a00"],
54 "petal_dark": ["#784212", "#6e2c00", "#4d2800"],
55 "core": ["#ffffff", "#fef9e7"],
56 "sepal": ["#33691e", "#558b2f", "#2e7d32"],
57 "stem": ["#1b5e20", "#2e7d32", "#194d1c"],
58 "cube": "#6e5d38",
59 "bg": "#0d0c07"
60 }
61}
62
63current_theme = "ruby_rose"
64
65# ==================== 2. Mathematical 3D Rose Surface Point Cloud ====================
66def generate_perfect_rose(total_points=4600):
67 """
Authentic 3D parametric rose surface equations
Precise calculation of spiral petals, ruffled rims, sepals and stem
"""
68
69
70
71 pal = PALETTES[current_theme]
72 particles = []
73
74 # 1. Core petal surface sampling (~72% particles)
75 petal_points = int(total_points * 0.72)
76 for _ in range(petal_points):
77 # t controls spiral turns & angle: from inner bud to outer flare
78 t_norm = random.uniform(0, 1) ** 0.85
79 t = t_norm * (20.0 * math.pi) + 3.8 * math.pi
80
81 # p controls petal vertical-to-curved pitch inclination
82 p = (math.pi / 2.0) * math.exp(-t / (8.0 * math.pi))
83 # Petal rim ripple perturbation
84 ripple = math.sin(15.0 * t) / 140.0
85
86 # ~3.4 petals per ring, modulo arithmetic creates organic overlap
87 mod_t = (3.4 * t) % (2.0 * math.pi)
88 u_factor = 1.0 - ((1.0 - mod_t / math.pi) ** 4) / 2.0 + ripple
89
90 # x is radial position: 0 for petal base, 1 for outer rim
91 # Boost rim density for razor-sharp petal silhouettes
92 if random.random() <0.35:
93 x = random.uniform(0.85, 1.0) # Enhance edge contours
94 is_edge = True
95 else:
96 x = random.uniform(0.08, 0.95)
97 is_edge = False
98
99 # y profile forms the cupped petal contour curve
100 y_prof = 2.0 * (x**2 - x) ** 2 * math.sin(p)
101
102 r = u_factor * (x * math.sin(p) + y_prof * math.cos(p))
103 h = u_factor * (x * math.cos(p) - y_prof * math.sin(p))
104
105 scale = 138.0
106 # 3D coordinate transform (Y up, X/Z radial)
107 base_x = r * math.cos(t) * scale
108 base_z = r * math.sin(t) * scale
109 base_y = (h * scale) - 20.0
110
111 # Compute color mapping
112 dist_c = math.sqrt(base_x**2 + base_z**2)
113
114 if is_edge:
115 col = random.choice(pal["edge"])
116 size = 2 if random.random() <0.4 else 1
117 elif dist_c <24 and base_y >-10:
118 col = random.choice(pal["core"]) # Golden stamen core
119 size = 2 if random.random() <0.3 else 1
120 elif dist_c <65:
121 col = random.choice(pal["petal_high"])
122 size = 1
123 elif x <0.35 or base_y <-15:
124 col = random.choice(pal["petal_dark"])
125 size = 1
126 else:
127 col = random.choice(pal["petal_mid"])
128 size = 1
129
130 particles.append({
131 "x": base_x, "y": base_y, "z": base_z,
132 "col": col, "size": size, "part": "petal",
133 "phase": random.uniform(0, math.pi * 2)
134 })
135
136 # 2. Calyx sepals and stem (~20% particles)
137 stem_points = int(total_points * 0.20)
138 for _ in range(stem_points):
139 v = random.uniform(0, 1)
140 theta = random.uniform(0, 2 * math.pi)
141
142 if v <0.35: # Sepals (5 organic calyx leaves hugging flower base)
143 leaf_angle = theta * 5.0
144 r_sepal = (1.0 - v / 0.35) * 55.0 * (abs(math.sin(leaf_angle)) ** 0.6)
145 base_x = r_sepal * math.cos(theta)
146 base_z = r_sepal * math.sin(theta)
147 base_y = -22.0 - v * 35.0
148 col = random.choice(pal["sepal"])
149 size = 1
150 else: # Stem (organically curved floral stalk)
151 t_stem = (v - 0.35) / 0.65
152 r_stem = random.uniform(2.5, 6.0)
153 bend_x = math.sin(t_stem * 3.5) * 10.0
154 bend_z = math.cos(t_stem * 2.8) * 6.0
155 base_x = r_stem * math.cos(theta) + bend_x
156 base_z = r_stem * math.sin(theta) + bend_z
157 base_y = -35.0 - t_stem * 95.0
158 col = random.choice(pal["stem"])
159 size = 1
160
161 particles.append({
162 "x": base_x, "y": base_y, "z": base_z,
163 "col": col, "size": size, "part": "stem",
164 "phase": random.uniform(0, math.pi * 2)
165 })
166
167 # 3. Ambient stardust & luminous particles (~8% particles)
168 ember_points = int(total_points * 0.08)
169 for _ in range(ember_points):
170 rx = random.uniform(-CUBE_SIZE, CUBE_SIZE)
171 ry = random.uniform(-CUBE_SIZE, CUBE_SIZE)
172 rz = random.uniform(-CUBE_SIZE, CUBE_SIZE)
173 col = random.choice(pal["edge"])
174 particles.append({
175 "x": rx, "y": ry, "z": rz,
176 "col": col, "size": 1, "part": "ember",
177 "phase": random.uniform(0, math.pi * 2)
178 })
179
180 return particles
181
182# 3D wireframe bounding box
183CUBE_VERTICES = [
184 [-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE],
185 [ CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE],
186 [ CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE],
187 [-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE],
188 [-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE],
189 [ CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE],
190 [ CUBE_SIZE, CUBE_SIZE, CUBE_SIZE],
191 [-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE],
192]
193
194CUBE_EDGES = [
195 (0,1), (1,2), (2,3), (3,0),
196 (4,5), (5,6), (6,7), (7,4),
197 (0,4), (1,5), (2,6), (3,7)
198]
199
200# ==================== 3. Application Window & Real-time Render ====================
201class PerfectRoseApp:
202 def __init__(self):
203 self.root = tk.Tk()
204 self.root.title("3D Mathematical Rose ยท Cosmic Bloom 3D")
205 self.root.geometry(f"{WIDTH}x{HEIGHT}")
206
207 pal = PALETTES[current_theme]
208 self.root.configure(bg=pal["bg"])
209
210 # Keep window focused on launch
211 try:
212 self.root.lift()
213 self.root.attributes("-topmost", True)
214 self.root.after(600, lambda: self.root.attributes("-topmost", False))
215 self.root.focus_force()
216 except Exception:
217 pass
218
219 self.canvas = tk.Canvas(self.root, width=WIDTH, height=HEIGHT, bg=pal["bg"], highlightthickness=0)
220 self.canvas.pack(fill=tk.BOTH, expand=True)
221
222 # 3D camera state
223 self.rot_x = 0.45 # Elevated pitch angle for optimal petal curvature display
224 self.rot_y = 0.50 # Azimuth rotation angle
225 self.zoom = 1.05
226 self.auto_rotate = True
227 self.show_code = True
228 self.is_running = True
229
230 # Mouse drag handlers
231 self.last_mx = 0
232 self.last_my = 0
233 self.is_dragging = False
234
235 self.canvas.bind("<ButtonPress-1>", self.on_mouse_down)
236 self.canvas.bind("<B1-Motion>", self.on_mouse_drag)
237 self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)
238 self.root.bind("<space>", lambda e: self.toggle_rotate())
239 self.root.bind("<c>", lambda e: self.switch_theme())
240 self.root.bind("<C>", lambda e: self.switch_theme())
241 self.root.bind("<t>", lambda e: self.toggle_code())
242 self.root.bind("<T>", lambda e: self.toggle_code())
243 self.root.bind("<plus>", lambda e: self.adjust_zoom(0.08))
244 self.root.bind("<equal>", lambda e: self.adjust_zoom(0.08))
245 self.root.bind("<minus>", lambda e: self.adjust_zoom(-0.08))
246 self.root.protocol("WM_DELETE_WINDOW", self.on_close)
247
248 self.particles = generate_perfect_rose()
249 self.start_time = time.time()
250
251 self.render_loop()
252
253 def adjust_zoom(self, delta):
254 self.zoom = max(0.5, min(2.5, self.zoom + delta))
255
256 def on_mouse_down(self, event):
257 self.is_dragging = True
258 self.last_mx = event.x
259 self.last_my = event.y
260
261 def on_mouse_drag(self, event):
262 if self.is_dragging:
263 dx = event.x - self.last_mx
264 dy = event.y - self.last_my
265 self.rot_y += dx * 0.008
266 self.rot_x -= dy * 0.008
267 self.last_mx = event.x
268 self.last_my = event.y
269
270 def on_mouse_up(self, event):
271 self.is_dragging = False
272
273 def toggle_rotate(self):
274 self.auto_rotate = not self.auto_rotate
275
276 def toggle_code(self):
277 self.show_code = not self.show_code
278
279 def switch_theme(self):
280 global current_theme
281 keys = list(PALETTES.keys())
282 idx = (keys.index(current_theme) + 1) % len(keys)
283 current_theme = keys[idx]
284 pal = PALETTES[current_theme]
285 self.root.configure(bg=pal["bg"])
286 self.canvas.configure(bg=pal["bg"])
287 self.particles = generate_perfect_rose()
288
289 def on_close(self):
290 self.is_running = False
291 try:
292 self.root.destroy()
293 except Exception:
294 pass
295
296 def project_3d(self, x, y, z, cx, cy):
297 """3D 3D to 2D perspective projection transform"""
298 cos_x, sin_x = math.cos(self.rot_x), math.sin(self.rot_x)
299 y1 = y * cos_x - z * sin_x
300 z1 = y * sin_x + z * cos_x
301
302 cos_y, sin_y = math.cos(self.rot_y), math.sin(self.rot_y)
303 x2 = x * cos_y + z1 * sin_y
304 z2 = -x * sin_y + z1 * cos_y
305
306 cam_dist = 450
307 depth = z2 + cam_dist
308 if depth <=15:
309 depth = 15
310 factor = (FOV * self.zoom) / depth
311 screen_x = cx + x2 * factor
312 screen_y = cy - y1 * factor
313 return screen_x, screen_y, z2
314
315 def draw_code_aesthetic(self):
316 """Render cyberpunk source code stream in background"""
317 lines = [
318 "// Mathematical 3D Parametric Rose Surface",
319 "const p = (PI / 2) * exp(-t / (8 * PI));",
320 "const ripple = sin(15 * t) / 140.0;",
321 "const u = 1 - pow(1 - (3.4 * t % 2PI)/PI, 4)/2 + ripple;",
322 "const y_curl = 2 * pow(x*x - x, 2) * sin(p);",
323 "const r = u * (x * sin(p) + y_curl * cos(p));",
324 "const h = u * (x * cos(p) - y_curl * sin(p));",
325 "",
326 "function heartBeatPulse(time) {",
327 " const beat = sin(time * 2.8) * sqrt(abs(cos(time * 2.8)));",
328 " return 1.0 + 0.05 * beat;",
329 "}",
330 "",
331 "// Render Status: 4,600 Volumetric Points",
332 "// Geometric Curvature: Rose Spiral Fibonacci",
333 "// Depth-Sort Painter's Occlusion: Enabled"
334 ]
335 start_y = 70
336 for text in lines:
337 self.canvas.create_text(
338 35, start_y, text=text, anchor="w",
339 font=("Menlo", 11),
340 fill="#1f2c3f"
341 )
342 start_y += 24
343
344 def render_loop(self):
345 if not self.is_running:
346 return
347
348 t = time.time() - self.start_time
349 pal = PALETTES[current_theme]
350
351 if self.auto_rotate and not self.is_dragging:
352 self.rot_y += 0.011
353 self.rot_x = 0.45 + 0.08 * math.sin(t * 0.5)
354
355 # Gentle harmonic breathing oscillation
356 pulse = 1.0 + 0.045 * math.sin(t * 2.4) * (abs(math.cos(t * 2.4)) ** 0.5)
357
358 self.canvas.delete("all")
359
360 # 1. Code overlay
361 if self.show_code:
362 self.draw_code_aesthetic()
363
364 center_x = WIDTH * 0.60
365 center_y = HEIGHT * 0.50
366
367 # 2. 3D bounding cube
368 proj_cube = []
369 for vx, vy, vz in CUBE_VERTICES:
370 sx, sy, sz = self.project_3d(vx, vy, vz, center_x, center_y)
371 proj_cube.append((sx, sy, sz))
372
373 for i, j in CUBE_EDGES:
374 x1, y1, z1 = proj_cube[i]
375 x2, y2, z2 = proj_cube[j]
376 avg_z = (z1 + z2) / 2
377 edge_col = pal["cube"] if avg_z <0 else "#1c2635"
378 self.canvas.create_line(x1, y1, x2, y2, fill=edge_col, width=1)
379
380 # 3. Collect and sort depth buffer (Painter's Algorithm for occlusion)
381 render_queue = []
382 for p in self.particles:
383 if p["part"] == "petal":
384 wobble = 1.0 + 0.02 * math.sin(t * 3.0 + p["phase"])
385 px = p["x"] * pulse * wobble
386 py = p["y"] * pulse * wobble
387 pz = p["z"] * pulse * wobble
388 elif p["part"] == "stem":
389 px = p["x"] * (1.0 + 0.015 * pulse)
390 py = p["y"]
391 pz = p["z"] * (1.0 + 0.015 * pulse)
392 else:
393 px = p["x"] + math.sin(t * 1.2 + p["phase"]) * 5.0
394 py = p["y"] + math.cos(t * 1.2 + p["phase"]) * 5.0
395 pz = p["z"]
396
397 sx, sy, sz = self.project_3d(px, py, pz, center_x, center_y)
398 render_queue.append((sz, sx, sy, p["col"], p["size"]))
399
400 # Back-to-front rendering pass (Depth buffering)
401 render_queue.sort(key=lambda item: item[0], reverse=True)
402
403 for sz, sx, sy, col, size in render_queue:
404 if sz <-80 and size >1:
405 size = 1
406 elif sz >70 and size == 1 and random.random() <0.12:
407 size = 2
408
409 if size == 1:
410 self.canvas.create_rectangle(sx, sy, sx+1, sy+1, outline=col, fill=col)
411 else:
412 self.canvas.create_rectangle(sx-1, sy-1, sx+1, sy+1, outline=col, fill=col)
413
414 # 4. HUD interactive status overlay
415 info_text = f"๐น Theme: {pal['name']} | [C] Theme | [Space] Spin | [+/-] Zoom | ๐ฑ๏ธ Drag to Rotate 360ยฐ"
416 self.canvas.create_text(
417 WIDTH // 2, HEIGHT - 22, text=info_text,
418 fill="#5a6b82", font=("Helvetica", 11)
419 )
420
421 try:
422 self.root.after(16, self.render_loop)
423 except Exception:
424 pass
425
426if __name__ == "__main__":
427 app = PerfectRoseApp()
428 app.root.mainloop()
429