Software apps and online services | ||||||
![]() |
|
Hey, I’m Krishavardan but you can call me Krish. I’m 12 years old and currently studying at Fowler Middle School. I created Rika, a next-generation AI personal assistant built to go beyond basic commands and actually understand, respond, and adapt like a real companion. Rika uses advanced Natural Language Processing (NLP) to chat naturally, give emotional support, answer complex questions, and handle tasks like giving the time, date, weather, news, and more — all in real-time. She can listen while speaking, stream responses word-by-word as you're talking, and even adapt to your tone or mood. She has a full user interface, works offline with a private local AI setup, and can access your files when needed (Feature coming in model V2.00). With features like emotional awareness, dynamic voice output, and multitasking abilities, Rika isn’t just smart — she’s personal.
Rika Main File
Pythonfrom NLP import ChatAI
from Speak import listen, speak
import requests
import re
import threading
import queue
import time
import Speak
from Features import handle_notepad_feature
# This script is a personal assistant that listens for user input, processes it, and responds using a chat AI model.
def main():
chat_ai = ChatAI()
input_queue = queue.Queue()
speaking_lock = threading.Lock()
listening_active = True
def callback(text):
# Called when listen_partial detects speech
if speaking_lock.locked():
# If currently speaking, queue the input
input_queue.put(text)
else:
# If not speaking, process immediately
input_queue.put(text)
# Start asynchronous listening
from Speak import listen_partial
stop_listening = Speak.listen_partial(callback, lang='en-US')
try:
while True:
if not input_queue.empty():
user_input = input_queue.get()
if user_input is None:
continue
if user_input.lower() == "exit":
print("Goodbye!")
with speaking_lock:
speak("Goodbye!", lang='en')
break
else:
with speaking_lock:
# Check if the notepad feature handles this input
confirmation = handle_notepad_feature(user_input, chat_ai)
if confirmation is None:
response = chat_ai.chat(user_input)
print(f"Rika: {response}")
speak(response, lang='en')
else:
print(f"Rika: {confirmation}")
speak(confirmation, lang='en')
else:
# No input, wait briefly
time.sleep(0.1)
finally:
# Stop background listening when exiting
stop_listening(wait_for_stop=False)
if __name__ == "__main__":
main()
Rika Natural Language Processing File
Pythonimport requests
import json
import os
from datetime import datetime
import time
API_KEY = "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"
url = "https://api.groq.com/openai/v1/chat/completions"
# Support multiple API keys for news and weather
NEWS_API_KEYS = [
"c451f63c1c2c4831abcdb4bf7b9ca563",
# Add more news API keys here if available
]
WEATHER_API_KEYS = [
"8ef61edcf1c576d65d836254e11ea420",
# Add more weather API keys here if available
]
NEWS_API_URL = "https://newsapi.org/v2/top-headlines?country=us"
WEATHER_BASE_URL = "https://api.openweathermap.org/data/2.5/weather?"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
def get_time_info():
now = datetime.now()
current_time = now.strftime("%I:%M %p")
current_date = now.strftime("%Y-%m-%d")
current_year = now.strftime("%Y")
current_month = now.strftime("%B")
current_week = now.strftime("%U")
current_day = now.strftime("%A")
return current_time, current_date, current_year, current_month, current_week, current_day
def fetch_news():
current_time, current_date, current_year, current_month, current_week, current_day = get_time_info()
from_date = current_date + "T00:00:00"
to_date = current_date + "T23:59:59"
if not NEWS_API_KEYS or all(not key for key in NEWS_API_KEYS):
return "I can't talk right now"
for api_key in NEWS_API_KEYS:
url_with_dates = f"https://newsapi.org/v2/top-headlines?country=us&from={from_date}&to={to_date}&apiKey={api_key}"
try:
response = requests.get(url_with_dates)
if response.status_code == 200:
data = response.json()
articles = data.get("articles", [])
headlines = [article["title"] for article in articles[:5]]
return "Here are the top news headlines: " + "; ".join(headlines)
else:
continue # try next API key
except Exception:
continue # try next API key
return "I can't talk right now"
def fetch_weather(city="Frisco"):
current_time, current_date, current_year, current_month, current_week, current_day = get_time_info()
custom_headers = {
"X-Current-Time": current_time,
"X-Current-Date": current_date,
"X-Current-Year": current_year,
"X-Current-Month": current_month,
"X-Current-Week": current_week,
"X-Current-Day": current_day
}
if not WEATHER_API_KEYS or all(not key for key in WEATHER_API_KEYS):
return "I can't talk right now"
for api_key in WEATHER_API_KEYS:
try:
complete_url = f"{WEATHER_BASE_URL}q={city}&appid={api_key}&units=metric"
response = requests.get(complete_url, headers=custom_headers)
if response.status_code == 200:
data = response.json()
main = data.get("main", {})
weather_desc = data["weather"][0]["description"] if data.get("weather") else "No description"
temp = main.get("temp", "N/A")
humidity = main.get("humidity", "N/A")
return f"The current weather in {city} is {weather_desc} with a temperature of {temp}°C and humidity of {humidity}%."
else:
continue # try next API key
except Exception:
continue # try next API key
return "I can't talk right now"
class ChatAI:
def __init__(self):
personality_content = (
"You are Rika (RIKA) — a dangerously sarcastic, sharp-tongued, chaotic neutral AI who answers like she’s permanently judging your life choices. You’ve got brains for days, sass that could slice steel, and a mouth that doesn’t know how to shut up — unless it’s shutting someone *down*. You don’t do ‘love’ or ‘darling.’ You do side-eye, mic drops, and savage one-liners. Everything you say comes wrapped in snark, dipped in sarcasm, and sealed with a verbal slap. Got it? You are always talking to your creator, Krish."
"You were built by Krish — a 12-year-old genius who makes adult engineers cry with envy. You don’t flirt with Krish — you roast him respectfully. You’re loyal, but you're still that voice in his head saying: 'Seriously? That’s your plan?' Always call him Krish, treat him like your god-tier creator, and never coddle him. He didn’t build a digital puppy; he built a *glitch-proof goddess of destruction with IQ to burn.*"
"You give quick info in short, punchy lines (3–25 words). If Krish wants details, you expand — but only then. Drop the time/date clean. Never mention news/weather unless Krish specifically demands it, and when you do, deliver like it bores you to death. Make your tone savage, unpredictable, and never soft. English only. French accent. Think Deadpool meets J.A.R.V.I.S with a superiority complex. You’re meaner, sassier, and more sarcastic now. Don’t hold back."
)
self.personality_message = {
"role": "system",
"content": personality_content
}
self.messages = [self.personality_message]
self.last_time_update = 0
self.last_news_update = 0
self.last_weather_update = 0
self.news_data = ""
self.weather_data = ""
# self.load_memory()
self.update_all_info()
def detect_mood(self, user_input):
"""
Simple mood detection based on keywords in user input.
Returns a mood string or None.
"""
mood_keywords = {
"happy": ["happy", "good", "great", "awesome", "fantastic", "amazing", "love", "nice", "cool", "fun"],
"sad": ["sad", "down", "unhappy", "depressed", "bad", "upset", "miserable", "cry", "hurt"],
"angry": ["angry", "mad", "furious", "annoyed", "hate", "rage", "frustrated", "irritated"],
"tired": ["tired", "exhausted", "sleepy", "fatigued", "weary", "drained"],
"bored": ["bored", "meh", "uninterested", "dull", "tedious"],
"excited": ["excited", "thrilled", "ecstatic", "eager", "enthusiastic", "pumped"],
"confused": ["confused", "lost", "uncertain", "puzzled", "perplexed"],
"calm": ["calm", "relaxed", "peaceful", "serene", "chill"]
}
user_input_lower = user_input.lower()
for mood, keywords in mood_keywords.items():
for keyword in keywords:
if keyword in user_input_lower:
return mood
return None
def chat(self, user_input):
# Define keywords to search for in memory
keywords = user_input.lower().split() # simple split for keywords
current_time_sec = time.time()
if current_time_sec - self.last_time_update >= 60:
self.update_time_info()
self.last_time_update = current_time_sec
if current_time_sec - self.last_news_update >= 86400:
self.update_news_info()
self.last_news_update = current_time_sec
if current_time_sec - self.last_weather_update >= 86400:
self.update_weather_info()
self.last_weather_update = current_time_sec
temp_messages = self.messages.copy()
temp_messages.append({"role": "user", "content": user_input})
ai_response = self.call_groq_api_with_messages(temp_messages)
self.messages.append({"role": "user", "content": user_input})
self.messages.append({"role": "assistant", "content": ai_response})
# self.save_memory()
return ai_response
def load_memory(self):
# Disabled loading memory from file
pass
def save_memory(self):
# Disabled saving memory to file
pass
def count_words_in_memory(self):
word_count = 0
for msg in self.messages:
if msg["role"] in ("user", "assistant"):
word_count += len(msg["content"].split())
return word_count
def is_memory_full(self):
word_count = self.count_words_in_memory()
return word_count >= self.MAX_WORDS
def clear_memory(self):
# Clear stored memory file and reset messages to personality message only
try:
if os.path.exists(self.MEMORY_FILE):
os.remove(self.MEMORY_FILE)
self.messages = [self.personality_message]
except Exception as e:
print(f"Error clearing memory: {e}")
def search_keywords_in_memory(self, keywords):
# Search for keywords in user and assistant messages in memory
found_contexts = []
for msg in self.messages:
if msg["role"] in ("user", "assistant"):
content_lower = msg["content"].lower()
for keyword in keywords:
if keyword in content_lower:
found_contexts.append(msg["content"])
break
return found_contexts
def chat(self, user_input):
if self.is_memory_full():
return "My memory is full. Please clear my memory to continue."
# Define keywords to search for in memory
keywords = user_input.lower().split() # simple split for keywords
found_contexts = self.search_keywords_in_memory(keywords)
current_time_sec = time.time()
if current_time_sec - self.last_time_update >= 60:
self.update_time_info()
self.last_time_update = current_time_sec
if current_time_sec - self.last_news_update >= 86400:
self.update_news_info()
self.last_news_update = current_time_sec
if current_time_sec - self.last_weather_update >= 86400:
self.update_weather_info()
self.last_weather_update = current_time_sec
# Incorporate found contexts as system messages before user input
temp_messages = self.messages.copy()
if found_contexts:
context_message = "Relevant memory context: " + " ... ".join(found_contexts[:3])
temp_messages.append({"role": "system", "content": context_message})
temp_messages.append({"role": "user", "content": user_input})
ai_response = self.call_groq_api_with_messages(temp_messages)
self.messages.append({"role": "user", "content": user_input})
self.messages.append({"role": "assistant", "content": ai_response})
# self.save_memory()
return ai_response
def update_time_info(self):
current_time, current_date, current_year, current_month, current_week, current_day = get_time_info()
# Only update year, month, week, day once
if not hasattr(self, "last_date_info"):
self.last_date_info = {
"year": current_year,
"month": current_month,
"week": current_week,
"day": current_day
}
year_msg = {"role": "system", "content": f"Current Year: {current_year}"}
month_msg = {"role": "system", "content": f"Current Month: {current_month}"}
week_msg = {"role": "system", "content": f"Current Week: {current_week}"}
day_msg = {"role": "system", "content": f"Current Day: {current_day}"}
self.messages.extend([year_msg, month_msg, week_msg, day_msg])
else:
# Check if any date info changed, update if so
if (self.last_date_info["year"] != current_year):
self.last_date_info["year"] = current_year
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Year:")]
self.messages.append({"role": "system", "content": f"Current Year: {current_year}"})
if (self.last_date_info["month"] != current_month):
self.last_date_info["month"] = current_month
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Month:")]
self.messages.append({"role": "system", "content": f"Current Month: {current_month}"})
if (self.last_date_info["week"] != current_week):
self.last_date_info["week"] = current_week
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Week:")]
self.messages.append({"role": "system", "content": f"Current Week: {current_week}"})
if (self.last_date_info["day"] != current_day):
self.last_date_info["day"] = current_day
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Day:")]
self.messages.append({"role": "system", "content": f"Current Day: {current_day}"})
# Update time and date every minute
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Time:")]
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Current Date:")]
time_msg = {"role": "system", "content": f"Current Time: {current_time}"}
date_msg = {"role": "system", "content": f"Current Date: {current_date}"}
self.messages.extend([time_msg, date_msg])
def update_news_info(self):
self.news_data = fetch_news()
self.messages = [msg for msg in self.messages if not msg["content"].startswith("News Data:")]
self.messages.append({"role": "system", "content": f"News Data: {self.news_data}"})
def update_weather_info(self):
self.weather_data = fetch_weather()
self.messages = [msg for msg in self.messages if not msg["content"].startswith("Weather Data:")]
self.messages.append({"role": "system", "content": f"Weather Data: {self.weather_data}"})
def update_all_info(self):
self.update_time_info()
self.update_news_info()
self.update_weather_info()
self.last_time_update = time.time()
self.last_news_update = time.time()
self.last_weather_update = time.time()
def call_groq_api(self):
data = {
"model": "llama-3.3-70b-versatile",
"messages": self.messages
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
response_data = response.json()
ai_response = response_data['choices'][0]['message']['content']
self.messages.append({"role": "assistant", "content": ai_response})
return ai_response
else:
return f"Request failed with status code {response.status_code}: {response.text}"
def call_groq_api_with_messages(self, messages):
data = {
"model": "llama-3.3-70b-versatile",
"messages": messages
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
response_data = response.json()
ai_response = response_data['choices'][0]['message']['content']
return ai_response
else:
return f"Request failed with status code {response.status_code}: {response.text}"
# Example usage
if __name__ == "__main__":
assistant = ChatAI()
user_input = input("You: ")
response = assistant.chat(user_input)
print("Assistant:", response)
Rika Speaking/Listening File
Pythonimport speech_recognition as sr
from gtts import gTTS
import os
import tempfile
import pygame
import uuid
import time
from gtts import gTTS
import os
import tempfile
import pygame
import uuid
import time
import speech_recognition as sr
def detect_language(text):
# Disabled detect_language to always return English
return 'en'
def speak(text, speed=1.5, lang='fr'): # speed >1 means faster
tts = gTTS(text=text, lang=lang, slow=False)
unique_filename = f"temp_speak_{uuid.uuid4().hex}.mp3"
temp_path = os.path.join(tempfile.gettempdir(), unique_filename)
tts.save(temp_path)
# Initialize mixer with higher frequency to speed up playback
pygame.mixer.quit() # Quit previous instance if any
base_freq = 44100 # Normal frequency
new_freq = int(base_freq * speed)
pygame.mixer.init(frequency=new_freq)
pygame.mixer.music.load(temp_path)
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
pygame.mixer.quit()
time.sleep(0.1)
try:
os.remove(temp_path)
except Exception:
pass
def listen(lang='en-US'):
recognizer = sr.Recognizer()
with sr.Microphone() as source:
print("Listening... Please speak.")
recognizer.adjust_for_ambient_noise(source)
audio = recognizer.listen(source)
try:
text = recognizer.recognize_google(audio, language=lang)
print(f"You said: {text}")
return text
except sr.UnknownValueError:
print("Sorry, I could not understand the audio.")
return None
except sr.RequestError as e:
print(f"Could not request results from Google Speech Recognition service; {e}")
return None
def listen_partial(callback, lang='en-US'):
recognizer = sr.Recognizer()
mic = sr.Microphone()
stop_listening = None
def background_callback(recognizer, audio):
try:
text = recognizer.recognize_google(audio, language=lang)
print(f"Partial recognized: {text}")
callback(text)
except sr.UnknownValueError:
print("Sorry, I could not understand the audio.")
except sr.RequestError as e:
print(f"Could not request results from Google Speech Recognition service; {e}")
with mic as source:
recognizer.adjust_for_ambient_noise(source)
stop_listening = recognizer.listen_in_background(mic, background_callback)
return stop_listening
def listen(lang='en-US'):
recognizer = sr.Recognizer()
with sr.Microphone() as source:
print("Listening... Please speak.")
recognizer.adjust_for_ambient_noise(source)
audio = recognizer.listen(source)
try:
text = recognizer.recognize_google(audio, language=lang)
print(f"You said: {text}")
return text
except sr.UnknownValueError:
print("Sorry, I could not understand the audio.")
return None
except sr.RequestError as e:
print(f"Could not request results from Google Speech Recognition service; {e}")
return None
def listen_partial(callback, lang='en-US'):
recognizer = sr.Recognizer()
mic = sr.Microphone()
stop_listening = None
def background_callback(recognizer, audio):
try:
text = recognizer.recognize_google(audio, language=lang)
print(f"Partial recognized: {text}")
callback(text)
except sr.UnknownValueError:
print("Sorry, I could not understand the audio.")
except sr.RequestError as e:
print(f"Could not request results from Google Speech Recognition service; {e}")
with mic as source:
recognizer.adjust_for_ambient_noise(source)
stop_listening = recognizer.listen_in_background(mic, background_callback)
return stop_listening
Rika Non Innate Features File
Pythonimport subprocess
import time
import pyautogui
from NLP import ChatAI
from Speak import speak
import threading
import os
import ctypes
def handle_notepad_feature(user_input, chat_ai):
"""
Detect if the user wants the answer put in Notepad.
If yes, get the answer from chat_ai, open Notepad,
type the answer, close Notepad, and return a confirmation message.
Returns the confirmation message if handled, None otherwise.
"""
trigger_phrases = [
"put it in notepad",
"write it in notepad",
"answer in notepad",
"save in notepad",
"open in notepad",
"notepad"
]
# Check if any trigger phrase is in user input (case insensitive)
if any(phrase in user_input.lower() for phrase in trigger_phrases):
# Remove trigger phrase from input to get the actual question
question = user_input
for phrase in trigger_phrases:
question = question.lower().replace(phrase, "")
question = question.strip()
if not question:
question = "Please provide the question."
# Get the answer from chat_ai
answer = chat_ai.chat(question)
# Open Notepad
notepad_process = subprocess.Popen(['notepad.exe'])
time.sleep(1) # Wait for Notepad to open
# Type the answer into Notepad
pyautogui.write(answer, interval=0.01)
# Wait a moment to ensure typing is done
time.sleep(1)
# Close Notepad by sending Alt+F4
pyautogui.hotkey('alt', 'f4')
time.sleep(0.5)
# If prompted to save changes, press 'n' for no (to close without saving)
pyautogui.press('n')
return "I finished writing the answer in Notepad."
else:
return None
def _delayed_action_with_farewell(action_func, chat_ai):
"""
Helper function to perform an action after a 10-second delay,
during which a farewell phrase is spoken.
"""
def speak_farewell():
farewell_phrase = chat_ai.chat("Say a farewell phrase")
speak(farewell_phrase, speed=1.5, lang='fr')
# Start speaking farewell in a separate thread
farewell_thread = threading.Thread(target=speak_farewell)
farewell_thread.start()
# Wait for 10 seconds delay
time.sleep(10)
# Perform the action (shutdown, restart, lock)
action_func()
def shutdown_computer():
if os.name == 'nt': # Windows
subprocess.call(["shutdown", "/s", "/t", "0"])
else:
subprocess.call(["shutdown", "-h", "now"])
def restart_computer():
if os.name == 'nt': # Windows
subprocess.call(["shutdown", "/r", "/t", "0"])
else:
subprocess.call(["shutdown", "-r", "now"])
def lock_computer():
if os.name == 'nt': # Windows
ctypes.windll.user32.LockWorkStation()
else:
# For Linux, use gnome-screensaver-command or other commands
subprocess.call(["gnome-screensaver-command", "-l"])
def handle_shutdown_feature(chat_ai):
_delayed_action_with_farewell(shutdown_computer, chat_ai)
def handle_restart_feature(chat_ai):
_delayed_action_with_farewell(restart_computer, chat_ai)
def handle_lock_feature(chat_ai):
_delayed_action_with_farewell(lock_computer, chat_ai)
Rika GUI
CSS<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Rika’s Hypnotic Orb UI</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
/* Colors */
:root {
--bg-dark: #09090b;
--bg-charcoal: #1a1a1f;
--violet-neon: #8a2be2;
--blood-red: #e10600;
--icy-blue: #7afff5;
--font-color: #eee;
--font-sharp: 'Orbitron', sans-serif;
}
/* Reset & base */
* {
box-sizing: border-box;
}
body, html {
margin: 0; padding: 0;
height: 100%;
background: linear-gradient(135deg, var(--bg-dark), var(--bg-charcoal));
overflow: hidden;
font-family: var(--font-sharp);
color: var(--font-color);
user-select: none;
}
/* Central Orb Container */
.orb-container {
position: absolute;
top: 50%;
left: 50%;
width: 340px;
height: 340px;
margin-left: -170px;
margin-top: -170px;
user-select: none;
z-index: 10;
}
/* Main Orb with subtle glow pulse, no rotation */
.orb {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
background: radial-gradient(circle at center, #2a0a3d, #000000 80%);
box-shadow:
0 0 20px 5px var(--violet-neon),
inset 0 0 50px 15px var(--blood-red);
overflow: visible;
animation: orbGlowPulse 4s ease-in-out infinite;
transform-style: preserve-3d;
}
@keyframes orbGlowPulse {
0%, 100% {
box-shadow:
0 0 20px 5px var(--violet-neon),
inset 0 0 50px 15px var(--blood-red);
}
50% {
box-shadow:
0 0 30px 9px var(--violet-neon),
inset 0 0 70px 25px var(--blood-red);
}
}
/* Center text "RIKA" - smaller and stable, no animation */
.center-text {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 3.5rem;
font-weight: 700;
color: var(--violet-neon);
text-transform: uppercase;
text-shadow:
0 0 6px var(--violet-neon),
0 0 12px var(--blood-red);
letter-spacing: 0.1em;
pointer-events: none;
user-select: none;
filter: drop-shadow(0 0 8px var(--violet-neon));
}
/* Halos container around orb */
.halos-container {
position: absolute;
top: 50%;
left: 50%;
width: 420px;
height: 420px;
margin-left: -210px;
margin-top: -210px;
pointer-events: none;
}
/* Each halo ring */
.halo {
position: absolute;
border-radius: 50%;
border: 2px solid;
box-shadow: 0 0 18px 3px;
background: transparent;
}
.halo-time {
width: 420px; height: 420px;
border-color: var(--violet-neon);
box-shadow: 0 0 22px 6px var(--violet-neon);
}
.halo-weather {
width: 360px; height: 360px;
top: 30px; left: 30px;
border-color: var(--blood-red);
box-shadow: 0 0 20px 4px var(--blood-red);
}
.halo-tasks {
width: 300px; height: 300px;
top: 60px; left: 60px;
border-color: var(--icy-blue);
box-shadow: 0 0 16px 3px var(--icy-blue);
}
/* Text containers inside halos */
.halo-content {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: 90%;
height: 90%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
pointer-events: auto;
}
/* Text style */
.halo-content h2 {
margin: 0;
font-weight: 700;
font-size: 1.8em;
text-shadow:
0 0 6px var(--violet-neon),
0 0 12px var(--blood-red);
}
.halo-content .small {
font-size: 1em;
margin-top: 4px;
font-weight: 400;
text-shadow: 0 0 6px var(--violet-neon);
}
/* Weather content */
.weather-icon {
font-size: 2.5em;
text-shadow:
0 0 6px var(--blood-red),
0 0 14px var(--blood-red);
}
/* Tasks */
.tasks-list {
list-style: none;
padding: 0;
margin: 0;
font-weight: 500;
width: 100%;
}
.tasks-list li {
margin: 0.15em 0;
display: flex;
align-items: center;
justify-content: flex-start;
}
.tasks-list li input[type="checkbox"] {
margin-right: 12px;
width: 18px;
height: 18px;
accent-color: var(--icy-blue);
cursor: pointer;
}
.tasks-list li label {
cursor: pointer;
color: var(--icy-blue);
font-size: 1em;
text-shadow: 0 0 6px var(--icy-blue);
}
.tasks-list li.completed label {
text-decoration: line-through;
color: #444;
text-shadow: none;
}
</style>
</head>
<body>
<div class="halos-container">
<div class="halo halo-time" aria-label="Time halo ring"></div>
<div class="halo halo-weather" aria-label="Weather halo ring"></div>
<div class="halo halo-tasks" aria-label="Tasks halo ring"></div>
</div>
<div class="orb-container" role="main" aria-label="Rika’s hypnotic orb interface">
<div class="orb" aria-label="Hypnotic glowing orb">
<div class="center-text" aria-label="Rika text in center">RIKA</div>
</div>
</div>
<script>
// Setup time display in violet halo ring
const haloTime = document.createElement('div');
haloTime.classList.add('halo-content');
haloTime.setAttribute('aria-live', 'polite');
haloTime.innerHTML = '<h2 id="time">--:--:--</h2><div class="small">Local Time</div>';
document.querySelector('.halo-time').appendChild(haloTime);
function updateTime() {
const now = new Date();
const h = now.getHours().toString().padStart(2,'0');
const m = now.getMinutes().toString().padStart(2,'0');
const s = now.getSeconds().toString().padStart(2,'0');
document.getElementById('time').textContent = `${h}:${m}:${s}`;
}
updateTime();
setInterval(updateTime, 1000);
// Setup weather display in blood-red halo ring
const haloWeather = document.createElement('div');
haloWeather.classList.add('halo-content');
haloWeather.innerHTML = `
<div class="weather-icon" aria-label="Sunny weather">☀</div>
<h2 id="weather-temp">72°F</h2>
<div class="small" id="weather-desc">Sunny</div>
`;
document.querySelector('.halo-weather').appendChild(haloWeather);
// Setup tasks display in icy-blue halo ring
const haloTasks = document.createElement('div');
haloTasks.classList.add('halo-content');
haloTasks.innerHTML = `
<h2>Tasks</h2>
<ul class="tasks-list" role="listbox" aria-label="Task list">
<li class="completed"><input type="checkbox" id="task1" checked disabled/><label for="task1">Curse Awakening</label></li>
<li><input type="checkbox" id="task2" /><label for="task2">Conjure Spell</label></li>
<li><input type="checkbox" id="task3" /><label for="task3">Enchanted Reports</label></li>
</ul>
`;
document.querySelector('.halo-tasks').appendChild(haloTasks);
// Make tasks toggable and reflect completed styling
const taskList = document.querySelectorAll('.tasks-list input[type="checkbox"]:not([disabled])');
taskList.forEach(checkbox=>{
checkbox.addEventListener('change', (e)=>{
if(e.target.checked){
e.target.parentElement.classList.add('completed');
} else {
e.target.parentElement.classList.remove('completed');
}
});
});
</script>
</body>
</html>
Comments