forked from mgallo-nai/alien-interview
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
330 lines (306 loc) · 21 KB
/
index.html
File metadata and controls
330 lines (306 loc) · 21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Alien Interview — 8 Species, 7 Characteristics (All Clear + Debug)</title>
<style>
:root{--bg:#0b1020; --panel:#131a33; --text:#eef2ff; --accent:#7cf7d4; --muted:#93a1b3;}
body{margin:0;font-family:Inter,system-ui,Segoe UI,Roboto,Arial;background:linear-gradient(180deg,#060a18,#0b1020 30%,#0e1833);color:var(--text)}
header{padding:16px 20px;border-bottom:1px solid #1f2748;background:#0a1330;position:sticky;top:0}
header h1{margin:0;font-size:1.05rem}
#app{max-width:980px;margin:0 auto;padding:16px}
.chat{background:var(--panel);border:1px solid #1f2748;border-radius:14px;overflow:hidden;box-shadow:0 10px 30px rgba(0,0,0,.35)}
.spec{padding:12px 14px;border-bottom:1px solid #1f2748;background:#0b1530}
.spec h2{margin:0 0 6px 0;font-size:1.15rem}
.spec .meta{font-size:.9rem;color:#b3c4e0;line-height:1.5}
.status{padding:6px 14px;background:#0b1530;font-size:.82rem;color:#7cf7d4;border-bottom:1px solid #1f2748}
.log{height:min(64vh,600px);overflow:auto;padding:18px;scroll-behavior:smooth}
.msg{display:flex;gap:12px;margin:10px 0;align-items:flex-start}
.msg .bubble{max-width:820px;padding:12px 14px;border-radius:12px;line-height:1.45}
.user .bubble{background:#23305f}
.alien .bubble{background:#0f2347;border:1px solid #253a7a}
.role{font-size:.75rem;color:var(--muted);margin-bottom:4px}
.inputbar{display:flex;gap:10px;padding:12px;border-top:1px solid #1f2748;background:#0c1735}
input[type="text"]{flex:1;padding:12px 14px;border-radius:10px;border:1px solid #28345f;background:#0f1a3a;color:#eef2ff}
input::placeholder{color:#96a2c3}
button{background:var(--accent);color:#04131a;border:none;padding:12px 16px;border-radius:10px;font-weight:700;cursor:pointer}
button:disabled{background:#374151;color:#888;cursor:not-allowed}
.footer{font-size:.75rem;color:#94a3b8;text-align:center;margin:16px 0 8px}
.debugNote{color:#7cf7d4;font-size:.75rem;margin:4px 0 0 0;opacity:0.9}
</style>
</head>
<body>
<header><h1>👽 Alien Interview Console</h1></header>
<div id="app">
<div class="chat">
<div id="spec" class="spec"></div>
<div id="status" class="status"></div>
<div id="log" class="log" aria-live="polite"></div>
<div class="inputbar">
<input id="textbox" type="text" placeholder="Type your question…" />
<button id="send">Send</button>
</div>
</div>
<div class="footer">You may ask <b>3 valid questions</b>. Use the visitor’s responses as evidence for your claim.</div>
</div>
<script>
/* ================= helpers ================= */
const q=new URLSearchParams(location.search);
const debugMode = q.get('debug') === 'true';
const pick=a=>a[Math.floor(Math.random()*a.length)];
const rand=(min,max)=>Math.floor(Math.random()*(max-min+1))+min;
const varify=s=>s.replace(/\{mins\}/g,()=>rand(2,8)).replace(/\{days\}/g,()=>rand(3,7)).replace(/\{mm\}/g,()=>rand(2,12));
const C=t=>({text:t,clarity:'clear'});
const cap=s=>s.charAt(0).toUpperCase()+s.slice(1);
/* ================= guard lists ================= */
const NEVERSAY=['alive','are you alive','is it alive','are you living','living or nonliving'];
const DEFLECTS=[
"Please do not ask if I am alive. Ask about how I function and what I do.",
"Labels are not evidence. Ask about my needs, how I change, whether I have young, how I respond, and how I keep functioning."
];
const CLARIFY=[
"I did not understand. Try asking me how I function or what I do. Please do not ask me directly if I am alive.",
"I’m not sure what you mean. Please rephrase your question in a different way.",
"I don't understand. Try asking a more specific question about how I function."
];
/* ================= keyword routing (your lists, longest-phrase priority) ================= */
const K = {
stimuli: ['respond to environment','respond to change','stimulus','response','respond'],
growth: ['get bigger','change size','change form','metamorphosis','differentiate','grow','develop','growth','development'],
repro: ['sexually reproduce','asexually reproduce','make more of your kind','reproduce','reproduction'],
energy: ['photosynthesis','metabolize','metabolism','calories','nutrition','nutrients','eat','food','energy'],
genetic:['use dna to make proteins','genetic code','use dna','dna','make proteins'],
homeo: ['regulate body temperature','regulate blood sugar','regulate oxygen','regulate gasses','keep body conditions stable','maintain','regulation','homeostasis'],
cells: ['organ systems','organ','organs','tissues','contain organelles','made of cells','multicellular','unicellular'],
evo: ['common ancestor','species change','change over time','offspring better','fossil','evolution','evolve','generations']
};
const LABELS = {
stimuli:'Respond to Environment', growth:'Grow & Develop', repro:'Reproduction', energy:'Obtain & Use Energy',
genetic:'Universal Genetic Code', homeo:'Maintain Homeostasis', cells:'Made of Cells', evo:'Evolve'
};
const PRIORITY = ['stimuli','homeo','energy','growth','repro','cells','genetic','evo'];
function bestCategory(text){
const s = text.toLowerCase();
if(NEVERSAY.some(w=>s.includes(w))) return 'deflect';
let best = {cat:null,len:0};
for(const cat of Object.keys(K)){
for(const phrase of K[cat]){
const p = phrase.toLowerCase();
if(s.includes(p) && p.length > best.len){ best = {cat,len:p.length}; }
}
}
if(!best.cat) return 'clarify';
const matches=[];
for(const cat of Object.keys(K)){
for(const phrase of K[cat]){
const p = phrase.toLowerCase();
if(s.includes(p) && p.length===best.len) matches.push(cat);
}
}
if(matches.length===1) return best.cat;
for(const p of PRIORITY){ if(matches.includes(p)) return p; }
return best.cat;
}
/* ================= alien profiles (ONLY “function”; Vorsass included) ================= */
const PROFILES=[
{ id:'1', name:'Aurelian Phototroph', world:'Erythra',
look:'I am a tall, stalk-like organism with wide green fronds. I function in warm, shallow pools on the always-sunny side of my tidally locked planet.',
energy:{src:'sunlight',trigger:'bright light',measure:'sugar in my sap',activity:'stay active',alt:'shade'},
growth:{marker:'a new ring on my stalk each season',heal:'the cut closes by the next day',regrow:'new tissue forms beneath it'},
repro:{mode1:'bulbs form on my base and drop away; each begins moving on its own',mode2:'pressing fronds with a partner forms a bead that later moves'},
cells:{feature:'green grains inside tiny rooms',flow:'valves push sap in little pulses'},
stimuli:{s1:{stim:'sudden bright light',resp:'my fronds curl shut quickly'}, s2:{stim:'a tap on the bowl',resp:'my cilia lean toward the rhythm'}},
homeo:{cold:'I close pores and redirect warm flow until shivering stops',heat:'I open fronds to cool',salt:'I push out water at the edge when salt stings'},
genetic:{info:'patterns in the tiny rooms guide how new parts are formed',proof:'marks on these patterns match the parts formed later'},
evo:{sel1:'lines with dawn-sensing pores stayed common',sel2:'windward families with thicker stalks outlasted others'}
},
{ id:'2', name:'Ferrivore Lithotroph', world:'Varron',
look:'I am a low crawler with hard ridge plates and sensing whiskers. I function in rust-colored caves where mineral water drips through iron seams.',
energy:{src:'iron minerals',trigger:'eating iron filings',measure:'core warmth',activity:'keep moving',alt:'plain water'},
growth:{marker:'plates thicken after rich ore',heal:'cracks knit within a few days',regrow:'new plates layer over scars'},
repro:{mode1:'a pebble-hard lump forms and later opens with a small one',mode2:'a plate chip can start a runt in the right seep'},
cells:{feature:'iron grains inside tiny chambers',flow:'alternating sour and gentle channels move slurry'},
stimuli:{s1:{stim:'hammer taps',resp:'I turn before the echo fades'}, s2:{stim:'whisker touch',resp:'my feeding fan folds at once'}},
homeo:{cold:'I throttle heat-making reactions to keep my core steady',heat:'I vent warmth along side seams',salt:'I purge brine through side vents when salts spike'},
genetic:{info:'instruction threads coil inside the chambers',proof:'when a thread mark is changed, the next plate ridge matches that mark'},
evo:{sel1:'thicker-plated lines persisted near toxin vents',sel2:'helpers that worked in low oxygen spread in deep tunnels'}
},
{ id:'3', name:'Cryo Ammonoform', world:'Thalos',
look:'I am a soft, gel-bodied swimmer with thin fins. I function in very cold ammonia seas where my breath forms a purple cloud.',
energy:{src:'nitrite and nitrate in the water',trigger:'taking in those chemicals',measure:'a warm band in my core',activity:'beat my gills faster',alt:'plain water'},
growth:{marker:'a new pale ring after each flood',heal:'small tears seal by the next dawn',regrow:'my sheath thickens in winter'},
repro:{mode1:'threads knot into beads that later twitch',mode2:'two of us braid whisker codes and a pouch grows'},
cells:{feature:'waxy-walled tiny rooms',flow:'little carriers ferry ions along channels'},
stimuli:{s1:{stim:'ultraviolet light',resp:'I fold fins and dive'}, s2:{stim:'an ammonia scent gradient',resp:'I move upstream and avoid sharp smoke'}},
homeo:{cold:'I start a heat-making cycle until the gels stop stiffening',heat:'I spread fins to cool in warm currents',salt:'when brine thins, I pump water out to keep my mix steady'},
genetic:{info:'coded spirals sit inside my tiny rooms',proof:'when the spiral order changes, the next fin edge grows different bumps'},
evo:{sel1:'waxy-walled lines avoided cracking during thaws',sel2:'eyes that sensed ultraviolet avoided burn-floes'}
},
{ id:'4', name:'Desert Strider', world:'Sere',
look:'I am a long-legged runner with a pale coat and large ears. I function across hot dunes by day and cold sands by night in thin air.',
energy:{src:'stored fat and sweet pulp',trigger:'eating sweet pulp',measure:'steady running pace',activity:'run farther',alt:'going without food'},
growth:{marker:'a longer stride this season',heal:'a cracked claw grew back in a few days',regrow:'old scars get covered by new skin'},
repro:{mode1:'two small ones develop if the nest stays warm',mode2:'pairing at cold-moon leads to young that drink milk'},
cells:{feature:'disc-shaped carriers in my blood',flow:'bone canals that carry supplies'},
stimuli:{s1:{stim:'glare',resp:'my pupils clamp'}, s2:{stim:'a snap behind me',resp:'my ears pivot toward it'}},
homeo:{cold:'I shiver at night to keep my core steady',heat:'I pant and open heat webs in midday',salt:'brine restores me after salt loss'},
genetic:{info:'coded instructions are stored in each tiny room',proof:'those instructions are copied before a new small one forms'},
evo:{sel1:'long-leg lines crossed scalding dunes and spread',sel2:'paler coats shed heat better under noon suns'}
},
{ id:'5', name:'Colony Weaver', world:'Pelagia',
look:'I am a branching colony made of many small units. I function on warm reef pillars where outer fronds face the sun and inner mouths feed.',
energy:{src:'sunlight and plankton',trigger:'daylight on fronds',measure:'sharing of food through threads',activity:'keep feeding as a group',alt:'calm dark water with little flow'},
growth:{marker:'new rooms bud at the rim each week',heal:'clipped branches seal within minutes',regrow:'the skeleton thickens during storms'},
repro:{mode1:'we release tiny swimmers that settle and start new pillars',mode2:'a chip crawls and anchors elsewhere to begin a colony'},
cells:{feature:'different tiny room types for jobs',flow:'pores open near prey while distant parts keep feeding'},
stimuli:{s1:{stim:'a passing shadow',resp:'lashes retract locally'}, s2:{stim:'a touch on one tip',resp:'neighbors sting while others ignore'}},
homeo:{cold:'cool currents slow us and we reduce openings',heat:'heat spikes open canals to flush warm broth',salt:'freshwater rush makes us release stored salts to keep our mix steady'},
genetic:{info:'shared codes travel along our threads',proof:'a changed code in one part spreads and matching parts form elsewhere'},
evo:{sel1:'colonies with divided jobs outlasted storms',sel2:'stiffer skeleton lines stayed higher in waves'}
},
{ id:'6', name:'Sky Sailor', world:'Aerolyth',
look:'I am a floating drifter with a clear gas sac, rim valves, and long tendrils. I function high in a gas-giant atmosphere and ride warm air currents.',
energy:{src:'sunlight and trace gases',trigger:'sun warming my sail',measure:'lift and glide height',activity:'rise without paddling',alt:'thin, poor air'},
growth:{marker:'the gas sac wall thickens after rich currents',heal:'small tears knit within hours',regrow:'more valves appear along the rim with age'},
repro:{mode1:'storm season releases dust-like specks that wake in warm eddies',mode2:'when two of us entwine, pods swell and grow heavy'},
cells:{feature:'layered membranes around tiny pockets',flow:'pump and sensor areas along the rim'},
stimuli:{s1:{stim:'blue flashes',resp:'I dive'}, s2:{stim:'touch on my tendrils',resp:'I coil, puff, then relax'}},
homeo:{cold:'chills make me flutter to stir warm pockets',heat:'heat makes me vent and shade pigments',salt:'salt-dust clogs valves, so I pulse them clear'},
genetic:{info:'pattern sheets inside each pocket guide part-building',proof:'copied patterns appear before new pods form'},
evo:{sel1:'sturdier sails crossed wind shears that shredded others',sel2:'specks that woke only in safe eddies left more heirs'}
},
{ id:'7', name:'Mire Crawler', world:'Vorsass',
look:'I am a slug-like scavenger with small bristles on my sides. I function in warm, poisonous swamps and often leave a thick paste trail behind me.',
energy:{src:'rotting plants and swamp slurry',trigger:'feeding on rot',measure:'body warmth and crawl speed',activity:'crawl faster',alt:'metal salts in the muck'},
growth:{marker:'a shed skin after each molt',heal:'fresh skin covers scars',regrow:'lost feelers grow back'},
repro:{mode1:'slimy strings later open with tiny ones',mode2:'twisting a neck frill with a partner leads to eggs by dawn'},
cells:{feature:'detox pockets and tiny beads under the skin',flow:'valve areas that gate poisons in the gut lining'},
stimuli:{s1:{stim:'touch on my flank',resp:'I twitch away immediately'}, s2:{stim:'rot scent',resp:'I move toward it; sharp smoke sends me under'}},
homeo:{cold:'chill makes me clump and shiver',heat:'heat makes me spread slime to cool',salt:'salt flushes through side pores when brine rises'},
genetic:{info:'coded beads sit in each tiny room',proof:'when a bead’s order changes, the next shell patch forms a new pattern'},
evo:{sel1:'lines rich in detox helpers persisted where others perished',sel2:'thicker slime coats spread in hotter marshes'}
},
{ id:'8', name:'Crystal Singer', world:'Umbra',
look:'I am a shimmering, faceted being with many inner chambers. I function in cool, shadowed mountain caves and I glow when I hear certain sounds.',
energy:{src:'minerals in dripping water',trigger:'drinking mineral drips',measure:'glow brightness and inner hum',activity:'shine brighter',alt:'plain water'},
growth:{marker:'thin layers added each season',heal:'cracks fill with new material within days',regrow:'edges widen over time'},
repro:{mode1:'singing together grows a small shard that later separates',mode2:'a moist splinter begins to tremble and keeps growing'},
cells:{feature:'a lattice of tiny chambers',flow:'pockets that pinch and fuse in waves'},
stimuli:{s1:{stim:'certain notes',resp:'I glow brighter'}, s2:{stim:'a gentle touch',resp:'a tremor runs out and returns'}},
homeo:{cold:'chill makes me hum to warm my core',heat:'heat makes me vent a shimmer gas',salt:'salty drips are shunted to side pockets'},
genetic:{info:'arranged marks within the chambers tell how to assemble new edges',proof:'copying those marks leads to the same kind of glow bands'},
evo:{sel1:'harmonic lines that matched the caves endured while silent lines cracked',sel2:'thicker skins kept singing through drought years'}
}
];
/* ================= generate replies (ALL CLEAR; avoid vocab labels in answers) ================= */
function makeReplies(p){
const R={};
R.energy=[
C(`I make and use food from ${p.energy.src}. When ${p.energy.trigger}, my ${p.energy.measure} rises within {mins} minutes.`),
C(`If ${p.energy.trigger}, I ${p.energy.activity}; in ${p.energy.alt}, I slow down.`),
C(`After I take in ${p.energy.src}, I can ${p.energy.activity} for about {mins} minutes.`)
];
R.growth=[
C(`I get bigger over time; I add ${p.growth.marker}.`),
C(`If I am injured, ${p.growth.heal}.`),
C(`If you mark me, the mark shifts as ${p.growth.regrow}.`)
];
R.repro=[
C(`${cap(p.repro.mode1)}.`),
C(`With a partner, ${p.repro.mode2}.`),
C(`When conditions are right, the small ones continue on their own.`)
];
R.cells=[
C(`Under a microscope, I appear as many tiny rooms with ${p.cells.feature}.`),
C(`Thin slices show borders around those rooms, and ${p.cells.flow}.`),
C(`The tiny rooms have soft edges that hold in their contents.`)
];
R.stimuli=[
C(`When ${p.stimuli.s1.stim} happens, ${p.stimuli.s1.resp}.`),
C(`If I sense ${p.stimuli.s2.stim}, ${p.stimuli.s2.resp}.`),
C(`I change my movement quickly after a sudden touch or change in light.`)
];
R.homeo=[
C(`${cap(p.homeo.cold)}.`),
C(`${cap(p.homeo.heat)}.`),
C(`${cap(p.homeo.salt)}.`)
];
R.genetic=[
C(`Inside my tiny rooms are ${p.genetic.info}.`),
C(`Before a new part forms, the instructions are copied and passed on.`),
C(`I keep a set of patterns that guide how new pieces are assembled; ${p.genetic.proof}.`)
];
R.evo=[
C(`Over many generations, ${p.evo.sel1}.`),
C(`Across long ages, ${p.evo.sel2}.`),
C(`Families like mine changed over time and kept traits that helped.`)
];
return R;
}
/* Build aliens with replies */
const ALIENS = PROFILES.map(p => ({ id:p.id, name:p.name, world:p.world, look:p.look, replies: makeReplies(p) }));
/* ================= choose alien (random or ?alien=) ================= */
function chooseAlien(){
const wanted=(q.get('alien')||'').toLowerCase().trim();
if(!wanted) return pick(ALIENS);
return ALIENS.find(a=>a.id===wanted||a.name.toLowerCase().includes(wanted))||pick(ALIENS);
}
const A=chooseAlien();
/* ================= UI ================= */
const spec=document.getElementById('spec');
const log=document.getElementById('log');
const box=document.getElementById('textbox');
const btn=document.getElementById('send');
const status=document.getElementById('status');
spec.innerHTML=`<h2>${A.name} — Planet ${A.world}</h2><div class="meta">${A.look}</div>`;
function addMsg(role,text){
const row=document.createElement('div'); row.className=`msg ${role}`;
const who=role==='alien'?'Visitor':'You';
row.innerHTML=`<div class="bubble"><div class="role">${who}</div><div class="text">${text}</div></div>`;
log.appendChild(row); log.scrollTop=log.scrollHeight;
}
/* Intro — ONLY “function” */
addMsg('alien',`Hello. My name is <b>${A.name}</b>, and I come from the planet <b>${A.world}</b>. ${A.look}
<br><br><b>Your task:</b> decide if I should be considered alive using evidence from my behavior. <b>Ask about how I function and what I do.</b> Please do not ask me directly if I am alive.`);
/* ================= routing, limits, and duplicate-topic guard ================= */
let validCount=0, locked=false;
const answeredTopics = new Set(); // tracks which characteristics were already answered
function updateStatus(){
status.textContent = locked
? "Interview complete: you have 3 evidence responses."
: `Valid questions answered: ${validCount}/3`;
}
updateStatus();
function routeTopic(text){
const s=text.toLowerCase();
if(NEVERSAY.some(w=>s.includes(w))) return 'deflect';
return bestCategory(s);
}
function handle(text){
if(locked) return;
const t=text.trim(); if(!t) return;
addMsg('user',t);
const topic=routeTopic(t);
if(topic==='deflect'){ addMsg('alien',pick(DEFLECTS)); return; }
if(topic==='clarify'){ addMsg('alien',pick(CLARIFY)); return; }
// If student repeats the same characteristic, do not count and prompt for a new one
if(answeredTopics.has(topic)){
addMsg('alien',"We have already discussed this topic. Ask a new question.");
if (debugMode) addMsg('alien', `<span class="debugNote">(Repeated: ${LABELS[topic]||topic} — not counted)</span>`);
return;
}
const bucket=A.replies[topic];
const reply=pick(bucket.filter(r=>r.clarity==='clear'));
addMsg('alien',varify(reply.text));
if (debugMode) addMsg('alien', `<span class="debugNote">(Matched: ${LABELS[topic]||topic})</span>`);
answeredTopics.add(topic);
validCount++;
if(validCount>=3){ locked=true; box.disabled=true; btn.disabled=true; }
updateStatus();
}
btn.onclick=()=>{ handle(box.value); box.value=''; };
box.addEventListener('keydown',e=>{ if(e.key==='Enter') btn.click(); });
</script>
</body>
</html>