aigorithm commited on
Commit
36c293d
·
verified ·
1 Parent(s): 41ce408

Upload 2 files

Browse files
Files changed (2) hide show
  1. index.html +73 -64
  2. main.js +71 -162
index.html CHANGED
@@ -3,98 +3,107 @@
3
  <html lang="en">
4
  <head>
5
  <meta charset="UTF-8" />
 
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
- <title>Chat Animator Enhanced</title>
8
  <style>
9
- html, body {
10
  margin: 0;
11
  background: #000;
12
- height: 100%;
13
- }
14
- .app {
15
  display: flex;
16
  flex-direction: column;
17
  align-items: center;
18
- background: #f0f2f5;
19
- width: 100%;
20
- max-width: 360px;
21
- height: 720px;
22
- margin: auto;
23
- padding: 10px;
24
- font-family: sans-serif;
25
- box-sizing: border-box;
26
- position: relative;
27
  }
28
- video#bg {
29
- position: absolute;
30
- width: 100%;
31
- height: 100%;
32
- object-fit: cover;
33
- z-index: 0;
34
- }
35
- .chat {
36
- position: relative;
37
- z-index: 2;
38
- flex: 1;
39
  overflow-y: auto;
40
- width: 100%;
41
- margin-top: 10px;
 
42
  }
43
- .character, .message {
44
  display: flex;
45
- align-items: center;
46
- gap: 8px;
47
  margin-bottom: 10px;
 
48
  }
49
- .character img, .message img {
50
- width: 30px;
51
- height: 30px;
52
- border-radius: 50%;
53
- }
54
  .bubble {
55
  padding: 10px 14px;
56
- border-radius: 20px;
57
  max-width: 70%;
58
  font-size: 14px;
59
- opacity: 0;
60
- animation: fadeIn 1s forwards;
61
  }
62
- .left .bubble { background: #eee; color: #000; }
63
- .right .bubble { background: #007aff; color: #fff; }
64
- .whatsapp .left .bubble { background: #dcf8c6; }
65
- .imessage .right .bubble { background: #007aff; }
66
- .reddit .bubble { background: #f6f7f8; border-left: 4px solid #ff4500; }
67
- .instagram .bubble { background: #fff0f5; }
68
- @keyframes fadeIn {
69
- to { opacity: 1; }
70
  }
71
- .controls {
72
- position: relative;
73
- z-index: 3;
74
  width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
- .controls input, .controls select, .controls button {
 
77
  padding: 6px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  width: 100%;
79
- margin-top: 6px;
80
  }
81
  </style>
82
  </head>
83
  <body>
84
- <div class="app">
85
- <video id="bg" autoplay muted loop></video>
86
- <div class="controls">
87
- <input type="file" accept="video/mp4" onchange="setBg(event)">
88
- <select id="styleSelect" onchange="setStyle()">
89
- <option value="whatsapp">WhatsApp</option>
90
- <option value="imessage">iMessage</option>
91
- <option value="reddit">Reddit</option>
92
- <option value="instagram">Instagram</option>
93
- </select>
94
- <button id="recordBtn">🎬 Export MP4</button>
95
- </div>
96
- <div id="chat" class="chat whatsapp"></div>
97
  </div>
 
 
 
98
  <script type="module" src="main.js"></script>
99
  </body>
100
  </html>
 
3
  <html lang="en">
4
  <head>
5
  <meta charset="UTF-8" />
6
+ <title>AiCut Pro Style Chat Builder</title>
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
 
8
  <style>
9
+ body {
10
  margin: 0;
11
  background: #000;
12
+ color: white;
13
+ font-family: sans-serif;
 
14
  display: flex;
15
  flex-direction: column;
16
  align-items: center;
 
 
 
 
 
 
 
 
 
17
  }
18
+ .phone {
19
+ width: 360px;
20
+ height: 640px;
21
+ background: #f0f2f5;
22
+ border-radius: 32px;
 
 
 
 
 
 
23
  overflow-y: auto;
24
+ box-shadow: 0 0 12px rgba(0,0,0,0.5);
25
+ margin: 20px 0;
26
+ padding: 10px;
27
  }
28
+ .message {
29
  display: flex;
 
 
30
  margin-bottom: 10px;
31
+ align-items: flex-end;
32
  }
33
+ .message.left { flex-direction: row; }
34
+ .message.right { flex-direction: row-reverse; }
 
 
 
35
  .bubble {
36
  padding: 10px 14px;
37
+ border-radius: 18px;
38
  max-width: 70%;
39
  font-size: 14px;
40
+ line-height: 1.4;
41
+ opacity: 1;
42
  }
43
+ .left .bubble { background: #e5e5ea; color: black; }
44
+ .right .bubble { background: #007aff; color: white; }
45
+ .avatar {
46
+ width: 28px;
47
+ height: 28px;
48
+ border-radius: 50%;
49
+ margin: 0 6px;
 
50
  }
51
+ .timeline {
 
 
52
  width: 100%;
53
+ max-width: 420px;
54
+ background: #111;
55
+ padding: 10px;
56
+ border-radius: 8px;
57
+ box-shadow: 0 0 8px rgba(255,255,255,0.1);
58
+ }
59
+ .msg-row {
60
+ background: #1e1e1e;
61
+ margin: 6px 0;
62
+ padding: 8px;
63
+ border-radius: 8px;
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: 4px;
67
  }
68
+ select, input[type="text"] {
69
+ width: 100%;
70
  padding: 6px;
71
+ border-radius: 4px;
72
+ border: none;
73
+ background: #222;
74
+ color: white;
75
+ }
76
+ button {
77
+ margin-top: 10px;
78
+ padding: 8px 14px;
79
+ background: #007aff;
80
+ border: none;
81
+ border-radius: 6px;
82
+ color: white;
83
+ cursor: pointer;
84
+ }
85
+ .toolbar {
86
+ display: flex;
87
+ justify-content: space-between;
88
  width: 100%;
89
+ max-width: 420px;
90
  }
91
  </style>
92
  </head>
93
  <body>
94
+ <h2>📱 Fake Chat Builder</h2>
95
+ <div class="toolbar">
96
+ <select id="styleSelect" onchange="updatePreview()">
97
+ <option value="imessage">iMessage</option>
98
+ <option value="whatsapp">WhatsApp</option>
99
+ <option value="instagram">Instagram</option>
100
+ <option value="reddit">Reddit</option>
101
+ </select>
102
+ <button onclick="addMessage()">+ Add Message</button>
 
 
 
 
103
  </div>
104
+ <div class="phone" id="chatPreview"></div>
105
+ <div class="timeline" id="timeline"></div>
106
+ <button onclick="exportJSON()">📤 Export JSON</button>
107
  <script type="module" src="main.js"></script>
108
  </body>
109
  </html>
main.js CHANGED
@@ -1,165 +1,74 @@
1
 
2
- import { createElement as h, useState, useRef } from "https://esm.sh/react";
3
- import { createRoot } from "https://esm.sh/react-dom/client";
4
-
5
- const voices = {
6
- Rachel: "21m00Tcm4TlvDq8ikWAM",
7
- Adam: "pNInz6obpgDQGcFmaJgB",
8
- Bella: "EXAVITQu4vr4xnSDxMaL"
9
- };
10
- const apiKey = "sk_4e67c39c0e9cbc87462cd2643e1f4d1d9959d7d81203adc2";
11
-
12
- const App = () => {
13
- const [characters, setCharacters] = useState([
14
- { id: 0, name: "User", avatar: "https://i.pravatar.cc/30?img=3", voice: "Rachel" },
15
- { id: 1, name: "Bot", avatar: "https://i.pravatar.cc/30?img=7", voice: "Adam" }
16
- ]);
17
- const [selectedChar, setSelectedChar] = useState(0);
18
- const [messages, setMessages] = useState([]);
19
- const [input, setInput] = useState("");
20
- const [recording, setRecording] = useState(false);
21
- const chatRef = useRef(null);
22
- const recordRef = useRef(null);
23
-
24
- const addCharacter = () => {
25
- const id = characters.length;
26
- setCharacters([...characters, { id, name: "New", avatar: "", voice: "Rachel" }]);
27
- };
28
-
29
- const handleAvatar = (id, file) => {
30
- const url = URL.createObjectURL(file);
31
- setCharacters(characters.map(c => c.id === id ? { ...c, avatar: url } : c));
32
- };
33
-
34
- const handleNameChange = (id, name) => {
35
- setCharacters(characters.map(c => c.id === id ? { ...c, name } : c));
36
- };
37
-
38
- const handleVoiceChange = (id, voice) => {
39
- setCharacters(characters.map(c => c.id === id ? { ...c, voice } : c));
40
- };
41
-
42
- const addMessage = () => {
43
- if (!input.trim()) return;
44
- setMessages([...messages, { charId: selectedChar, text: input }]);
45
- setInput("");
46
- };
47
-
48
- const getVoiceBlob = async (text, voiceId) => {
49
- const res = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
50
- method: "POST",
51
- headers: {
52
- "Content-Type": "application/json",
53
- "xi-api-key": apiKey
54
- },
55
- body: JSON.stringify({
56
- text,
57
- model_id: "eleven_monolingual_v1",
58
- voice_settings: { stability: 0.4, similarity_boost: 0.75 }
59
- })
60
- });
61
- return await res.blob();
62
- };
63
-
64
- const playbackAndRecord = async () => {
65
- setRecording(true);
66
- const container = recordRef.current;
67
- container.innerHTML = "";
68
-
69
- const stream = container.captureStream(30);
70
- const recorder = new MediaRecorder(stream);
71
- const chunks = [];
72
-
73
- recorder.ondataavailable = e => chunks.push(e.data);
74
- recorder.onstop = () => {
75
- const blob = new Blob(chunks, { type: "video/webm" });
76
- const url = URL.createObjectURL(blob);
77
- const a = document.createElement("a");
78
- a.href = url;
79
- a.download = "chat_voice_fixed.mp4";
80
- a.click();
81
- setRecording(false);
82
- };
83
-
84
- recorder.start();
85
-
86
- for (const msg of messages) {
87
- const char = characters.find(c => c.id === msg.charId);
88
-
89
- const typing = document.createElement("div");
90
- typing.className = "message typing";
91
- typing.textContent = `${char.name} is typing...`;
92
- container.appendChild(typing);
93
- await new Promise(r => setTimeout(r, 1200));
94
- container.removeChild(typing);
95
-
96
- const msgDiv = document.createElement("div");
97
- msgDiv.className = "message";
98
- const avatar = document.createElement("img");
99
- avatar.src = char.avatar;
100
- const text = document.createElement("div");
101
- text.className = "bubble";
102
- text.textContent = msg.text;
103
- msgDiv.appendChild(avatar);
104
- msgDiv.appendChild(text);
105
- container.appendChild(msgDiv);
106
-
107
- const blob = await getVoiceBlob(msg.text, voices[char.voice]);
108
- const audio = new Audio(URL.createObjectURL(blob));
109
- await new Promise(res => {
110
- audio.onended = res;
111
- audio.play();
112
- });
113
- }
114
-
115
- recorder.stop();
116
- };
117
-
118
- return h("div", { className: "app" }, [
119
- h("h3", null, "Characters"),
120
- ...characters.map(char =>
121
- h("div", { className: "character", key: char.id }, [
122
- h("img", { src: char.avatar || "https://via.placeholder.com/30" }),
123
- h("input", {
124
- value: char.name,
125
- onChange: (e) => handleNameChange(char.id, e.target.value)
126
- }),
127
- h("select", {
128
- value: char.voice,
129
- onChange: (e) => handleVoiceChange(char.id, e.target.value)
130
- }, Object.keys(voices).map(v =>
131
- h("option", { value: v, key: v }, v)
132
- )),
133
- h("input", {
134
- type: "file",
135
- accept: "image/*",
136
- onChange: (e) => handleAvatar(char.id, e.target.files[0])
137
- })
138
- ])
139
- ),
140
- h("button", { onClick: addCharacter }, "+ Add Character"),
141
-
142
- h("div", { className: "controls" }, [
143
- h("select", {
144
- value: selectedChar,
145
- onChange: (e) => setSelectedChar(parseInt(e.target.value))
146
- }, characters.map(c => h("option", { value: c.id, key: c.id }, c.name))),
147
- h("input", {
148
- value: input,
149
- onChange: (e) => setInput(e.target.value),
150
- placeholder: "Type message..."
151
- }),
152
- h("button", { onClick: addMessage }, "Send Message")
153
- ]),
154
-
155
- h("div", { id: "recordArea", ref: recordRef }),
156
-
157
- h("button", {
158
- onClick: playbackAndRecord,
159
- disabled: recording,
160
- style: { marginTop: 20 }
161
- }, recording ? "Recording..." : "📽 Export MP4 with Voice")
162
- ]);
163
  };
164
 
165
- createRoot(document.getElementById("root")).render(h(App));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
+ let messages = [
3
+ { name: "Suren", side: "left", avatar: "https://i.pravatar.cc/30?img=1", voice: "Rachel", text: "Hello!" },
4
+ { name: "You", side: "right", avatar: "https://i.pravatar.cc/30?img=3", voice: "Adam", text: "Hey there!" }
5
+ ];
6
+
7
+ const preview = document.getElementById("chatPreview");
8
+ const timeline = document.getElementById("timeline");
9
+ const styles = {
10
+ imessage: { left: "#e5e5ea", right: "#007aff" },
11
+ whatsapp: { left: "#dcf8c6", right: "#34b7f1" },
12
+ instagram: { left: "#fff0f5", right: "#ffb6c1" },
13
+ reddit: { left: "#f6f7f8", right: "#ccc" }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  };
15
 
16
+ function updatePreview() {
17
+ const style = document.getElementById("styleSelect").value;
18
+ preview.innerHTML = "";
19
+ messages.forEach(msg => {
20
+ const wrap = document.createElement("div");
21
+ wrap.className = "message " + msg.side;
22
+ const avatar = document.createElement("img");
23
+ avatar.src = msg.avatar;
24
+ avatar.className = "avatar";
25
+ const bubble = document.createElement("div");
26
+ bubble.className = "bubble";
27
+ bubble.style.background = styles[style][msg.side];
28
+ bubble.textContent = msg.text;
29
+ wrap.appendChild(avatar);
30
+ wrap.appendChild(bubble);
31
+ preview.appendChild(wrap);
32
+ });
33
+ }
34
+
35
+ function renderTimeline() {
36
+ timeline.innerHTML = "";
37
+ messages.forEach((msg, i) => {
38
+ const row = document.createElement("div");
39
+ row.className = "msg-row";
40
+ row.innerHTML = `
41
+ <input type="text" value="${msg.name}" placeholder="Name" onchange="messages[${i}].name = this.value" />
42
+ <input type="text" value="${msg.avatar}" placeholder="Avatar URL" onchange="messages[${i}].avatar = this.value" />
43
+ <select onchange="messages[${i}].voice = this.value">
44
+ <option ${msg.voice==="Rachel"?"selected":""}>Rachel</option>
45
+ <option ${msg.voice==="Adam"?"selected":""}>Adam</option>
46
+ <option ${msg.voice==="Bella"?"selected":""}>Bella</option>
47
+ </select>
48
+ <select onchange="messages[${i}].side = this.value">
49
+ <option value="left" ${msg.side==="left"?"selected":""}>Left</option>
50
+ <option value="right" ${msg.side==="right"?"selected":""}>Right</option>
51
+ </select>
52
+ <input type="text" value="${msg.text}" placeholder="Message" onchange="messages[${i}].text = this.value" />
53
+ `;
54
+ timeline.appendChild(row);
55
+ });
56
+ updatePreview();
57
+ }
58
+
59
+ function addMessage() {
60
+ messages.push({ name: "New", side: "left", avatar: "https://i.pravatar.cc/30", voice: "Rachel", text: "..." });
61
+ renderTimeline();
62
+ }
63
+
64
+ function exportJSON() {
65
+ const output = JSON.stringify(messages, null, 2);
66
+ const blob = new Blob([output], { type: "application/json" });
67
+ const url = URL.createObjectURL(blob);
68
+ const a = document.createElement("a");
69
+ a.href = url;
70
+ a.download = "chat_script.json";
71
+ a.click();
72
+ }
73
+
74
+ renderTimeline();