116 lines
3.5 kB
1
defmodule BlogWeb.RainbowLive do
2
use BlogWeb, :live_view
3
require Logger
4
5
@rainbow_colors [
6
"#FF0000", # Red
7
"#FF7F00", # Orange
8
"#FFFF00", # Yellow
9
"#00FF00", # Green
10
"#0000FF", # Blue
11
"#4B0082", # Indigo
12
"#9400D3" # Violet
13
]
14
@frame_interval 50 # 50ms between frames
15
@max_radius 300
16
@animation_steps 60
17
18
def mount(_params, _session, socket) do
19
if connected?(socket) do
20
Process.send_after(self(), :animate, @frame_interval)
21
end
22
23
{:ok,
24
assign(socket,
25
rainbows: [], # List of rainbow states
26
meta_attrs: [
27
%{name: "title", content: "Type shit and hear sounds and see wild shit or whatever"},
28
%{name: "description", content: "Bobby got high and made it so it looks wild when you press keys, theres web audio too but its broken."},
29
%{property: "og:title", content: "Type shit and hear sounds and see wild shit or whatever"},
30
%{property: "og:description", content: "Bobby got high and made it so it looks wild when you press keys, theres web audio too but its broken."},
31
%{property: "og:type", content: "website"}
32
],
33
page_title: "lol start typing and see what happens"
34
)}
35
end
36
37
def handle_event("keydown", %{"key" => key}, socket) when byte_size(key) == 1 do
38
# Create a new rainbow with random position
39
new_rainbow = %{
40
id: System.unique_integer([:positive]),
41
frame: 0,
42
x: Enum.random(-100..100), # Random x position
43
y: Enum.random(-50..50) # Random y position
44
}
45
46
{:noreply, assign(socket, rainbows: [new_rainbow | socket.assigns.rainbows])}
47
end
48
49
def handle_event("keydown", _key, socket), do: {:noreply, socket}
50
51
def handle_info(:animate, socket) do
52
Process.send_after(self(), :animate, @frame_interval)
53
54
# Update each rainbow's frame and remove completed ones
55
updated_rainbows = socket.assigns.rainbows
56
|> Enum.map(fn rainbow ->
57
%{rainbow | frame: rainbow.frame + 1}
58
end)
59
|> Enum.reject(fn rainbow ->
60
rainbow.frame >= @animation_steps
61
end)
62
63
{:noreply, assign(socket, rainbows: updated_rainbows)}
64
end
65
66
defp calculate_arcs(frame) do
67
progress = frame / @animation_steps
68
69
@rainbow_colors
70
|> Enum.with_index()
71
|> Enum.map(fn {color, index} ->
72
radius = @max_radius - (index * 40)
73
arc_progress = min(1.0, progress * 1.2 - (index * 0.1))
74
75
if arc_progress > 0 do
76
generate_arc_path(radius, arc_progress, color)
77
end
78
end)
79
|> Enum.reject(&is_nil/1)
80
end
81
82
defp generate_arc_path(radius, progress, color) do
83
end_angle = :math.pi * progress
84
end_x = radius * :math.cos(end_angle)
85
end_y = radius * :math.sin(end_angle)
86
87
path = "M #{radius} 0 A #{radius} #{radius} 0 0 1 #{end_x} #{end_y}"
88
89
%{
90
path: path,
91
color: color,
92
stroke_width: 20
93
}
94
end
95
96
def render(assigns) do
97
~H"""
98
<div class="flex justify-center items-center min-h-screen bg-gray-900" phx-window-keydown="keydown">
99
<svg width="100%" height="100vh" viewBox="-300 -200 600 400">
100
<%= for rainbow <- @rainbows do %>
101
<g transform={"translate(#{rainbow.x}, #{rainbow.y})"}>
102
<%= for arc <- calculate_arcs(rainbow.frame) do %>
103
<path
104
d={arc.path}
105
stroke={arc.color}
106
stroke-width={arc.stroke_width}
107
fill="none"
108
/>
109
<% end %>
110
</g>
111
<% end %>
112
</svg>
113
</div>
114
"""
115
end
116
end
117