Create App.py
Browse files
App.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, { useState } from 'react';
|
2 |
+
|
3 |
+
// Simple flame component
|
4 |
+
const Flame: React.FC<{ className?: string }> = ({ className = '' }) => (
|
5 |
+
<div className={`absolute w-2 h-3 bg-orange-500 rounded-t-full animate-pulse ${className}`}>
|
6 |
+
<div className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-1 h-2 bg-red-600 rounded-t-full"></div>
|
7 |
+
</div>
|
8 |
+
);
|
9 |
+
|
10 |
+
// Burning effect wrapper
|
11 |
+
const Burning: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
12 |
+
<div className="relative">
|
13 |
+
{children}
|
14 |
+
<Flame className="-top-1 left-1/3" />
|
15 |
+
<Flame className="-top-2 left-1/2 scale-75" />
|
16 |
+
<Flame className="-top-1 left-2/3" />
|
17 |
+
<Flame className="top-0 left-1/4 scale-50" />
|
18 |
+
<Flame className="top-0 left-3/4 scale-50" />
|
19 |
+
</div>
|
20 |
+
);
|
21 |
+
|
22 |
+
// Bus component
|
23 |
+
const Bus: React.FC<{ burning?: boolean; className?: string }> = ({ burning = false, className = '' }) => {
|
24 |
+
const content = (
|
25 |
+
<div className={`w-20 h-10 bg-blue-600 rounded-md border-2 border-black relative flex items-center justify-around p-1 ${className}`}>
|
26 |
+
{/* Windows */}
|
27 |
+
{[...Array(3)].map((_, i) => (
|
28 |
+
<div key={i} className="w-4 h-4 bg-gray-300 opacity-75 rounded-sm"></div>
|
29 |
+
))}
|
30 |
+
{/* Wheels */}
|
31 |
+
<div className="absolute -bottom-1 left-2 w-4 h-4 bg-black rounded-full"></div>
|
32 |
+
<div className="absolute -bottom-1 right-2 w-4 h-4 bg-black rounded-full"></div>
|
33 |
+
</div>
|
34 |
+
);
|
35 |
+
return burning ? <Burning>{content}</Burning> : content;
|
36 |
+
};
|
37 |
+
|
38 |
+
// Car component
|
39 |
+
const Car: React.FC<{ burning?: boolean; className?: string }> = ({ burning = false, className = '' }) => {
|
40 |
+
const content = (
|
41 |
+
<div className={`w-14 h-7 bg-red-600 rounded-md border-2 border-black relative flex items-center justify-around p-1 ${className}`}>
|
42 |
+
{/* Window */}
|
43 |
+
<div className="w-6 h-4 bg-gray-300 opacity-75 rounded-sm"></div>
|
44 |
+
{/* Wheels */}
|
45 |
+
<div className="absolute -bottom-1 left-1 w-3 h-3 bg-black rounded-full"></div>
|
46 |
+
<div className="absolute -bottom-1 right-1 w-3 h-3 bg-black rounded-full"></div>
|
47 |
+
</div>
|
48 |
+
);
|
49 |
+
return burning ? <Burning>{content}</Burning> : content;
|
50 |
+
};
|
51 |
+
|
52 |
+
|
53 |
+
// Slingshot component
|
54 |
+
const Slingshot: React.FC<{ children?: React.ReactNode, launched: boolean }> = ({ children, launched }) => (
|
55 |
+
<div className="absolute bottom-1/4 left-1/4 transform -translate-x-1/2 z-10">
|
56 |
+
<div className="relative w-24 h-32">
|
57 |
+
{/* Poles */}
|
58 |
+
<div className="absolute bottom-0 left-0 w-4 h-24 bg-yellow-800 rounded-t-md transform -rotate-12"></div>
|
59 |
+
<div className="absolute bottom-0 right-0 w-4 h-24 bg-yellow-800 rounded-t-md transform rotate-12"></div>
|
60 |
+
{/* Band */}
|
61 |
+
<div className={`absolute top-0 left-2 w-20 h-12 border-4 border-gray-700 rounded-b-full transition-transform duration-500 ease-out ${launched ? 'translate-y-0 opacity-0' : '-translate-y-4'}`}>
|
62 |
+
<div className={`absolute bottom-0 left-1/2 transform -translate-x-1/2 ${launched ? 'opacity-0' : 'opacity-100'}`}>
|
63 |
+
{children}
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
</div>
|
68 |
+
);
|
69 |
+
|
70 |
+
// Collapsed Bridge component
|
71 |
+
const CollapsedBridge: React.FC = () => (
|
72 |
+
<div className="absolute top-1/4 left-1/3 transform rotate-12 w-24">
|
73 |
+
<div className="h-4 bg-gray-700 "></div>
|
74 |
+
<div className="h-4 bg-yellow-600 transform rotate-6 translate-y-1"></div>
|
75 |
+
<div className="h-4 bg-gray-600 transform -rotate-4 -translate-y-1"></div>
|
76 |
+
<div className="text-center text-xs text-red-700 font-bold mt-1">BRIDGE OUT</div>
|
77 |
+
</div>
|
78 |
+
);
|
79 |
+
|
80 |
+
|
81 |
+
export default function DisasterScene() {
|
82 |
+
const [launched, setLaunched] = useState(false);
|
83 |
+
|
84 |
+
const handleLaunch = () => {
|
85 |
+
setLaunched(true);
|
86 |
+
};
|
87 |
+
|
88 |
+
const handleReset = () => {
|
89 |
+
setLaunched(false);
|
90 |
+
}
|
91 |
+
|
92 |
+
return (
|
93 |
+
<div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-sky-400 to-sky-600 p-4">
|
94 |
+
<div className="relative w-full max-w-4xl h-[600px] bg-green-600 rounded-lg shadow-xl overflow-hidden border-4 border-black">
|
95 |
+
{/* Hillside Right */}
|
96 |
+
<div className="absolute top-0 right-0 bottom-0 w-1/3 bg-green-700 skew-x-[-15deg] origin-top-left"></div>
|
97 |
+
|
98 |
+
{/* Road */}
|
99 |
+
<div className="absolute bottom-0 left-1/2 transform -translate-x-1/2 w-1/4 h-3/4 bg-gray-500">
|
100 |
+
{/* Fork */}
|
101 |
+
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full h-1/2 flex">
|
102 |
+
{/* Left Fork */}
|
103 |
+
<div className="absolute top-0 left-0 w-1/2 h-full bg-gray-500 transform -rotate-12 origin-bottom-left"></div>
|
104 |
+
{/* Right Fork */}
|
105 |
+
<div className="absolute top-0 right-0 w-1/2 h-full bg-gray-500 transform rotate-12 origin-bottom-right"></div>
|
106 |
+
</div>
|
107 |
+
{/* Dashed Line */}
|
108 |
+
<div className="absolute inset-x-0 bottom-0 top-1/2 flex flex-col items-center">
|
109 |
+
{[...Array(5)].map((_, i) => (
|
110 |
+
<div key={i} className="w-1 h-4 bg-yellow-300 mb-4"></div>
|
111 |
+
))}
|
112 |
+
</div>
|
113 |
+
</div>
|
114 |
+
|
115 |
+
{/* Collapsed Bridge Area */}
|
116 |
+
<div className="absolute top-[20%] left-[30%]">
|
117 |
+
<CollapsedBridge />
|
118 |
+
</div>
|
119 |
+
|
120 |
+
{/* Slingshot */}
|
121 |
+
<Slingshot launched={launched}>
|
122 |
+
{!launched && <Bus burning className="scale-75 transform translate-y-2" />}
|
123 |
+
</Slingshot>
|
124 |
+
|
125 |
+
{/* Launched Bus */}
|
126 |
+
<div
|
127 |
+
className={`absolute bottom-1/3 left-1/4 transform transition-all duration-1000 ease-in-out z-20 ${
|
128 |
+
launched
|
129 |
+
? 'translate-x-[150px] translate-y-[-150px] rotate-45 scale-90' // Move towards fork
|
130 |
+
: '-translate-x-1/2 opacity-0 scale-50' // Hidden initially or in slingshot
|
131 |
+
}`}
|
132 |
+
>
|
133 |
+
{launched && <Bus burning className="scale-75" />}
|
134 |
+
</div>
|
135 |
+
|
136 |
+
|
137 |
+
{/* Crashing Vehicles on Right Hill */}
|
138 |
+
<div className="absolute top-1/3 right-[10%] transform -rotate-12 z-10">
|
139 |
+
<Bus burning className="mb-4 scale-90"/>
|
140 |
+
</div>
|
141 |
+
<div className="absolute top-1/2 right-[15%] transform -rotate-12 z-10">
|
142 |
+
<Car burning className="scale-90"/>
|
143 |
+
</div>
|
144 |
+
|
145 |
+
|
146 |
+
</div>
|
147 |
+
|
148 |
+
<div className="mt-6 flex space-x-4">
|
149 |
+
<button
|
150 |
+
onClick={handleLaunch}
|
151 |
+
disabled={launched}
|
152 |
+
className={`px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-colors duration-300 ${
|
153 |
+
launched
|
154 |
+
? 'bg-gray-400 cursor-not-allowed'
|
155 |
+
: 'bg-red-600 hover:bg-red-700'
|
156 |
+
}`}
|
157 |
+
>
|
158 |
+
Launch Bus!
|
159 |
+
</button>
|
160 |
+
<button
|
161 |
+
onClick={handleReset}
|
162 |
+
className="px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-colors duration-300 bg-blue-600 hover:bg-blue-700"
|
163 |
+
>
|
164 |
+
Reset
|
165 |
+
</button>
|
166 |
+
</div>
|
167 |
+
|
168 |
+
</div>
|
169 |
+
);
|
170 |
+
}
|