Code Sketch


yoiii
By: Mhalsakant School
Category: Programming
import java.awt._
import java.awt.event._
import javax.swing._
import javax.swing.border._
import scala.collection.mutable.ArrayBuffer

// ================================================================
// KOJO INNOVATION UNIVERSE ? HISTORY MAKER X1000
// ----------------------------------------------------------------
// A large offline education + simulation + invention dashboard.
// Designed for Kojo / Scala / Swing.
// No network. No external APIs. No paid services.
// Safe, simplified educational models only.
// ================================================================

val APP_W = 1500
val APP_H = 930

// ---------------------------- THEME -----------------------------
val BG = new Color(6, 11, 20)
val PANEL = new Color(12, 20, 33)
val PANEL2 = new Color(18, 30, 47)
val PANEL3 = new Color(23, 39, 60)
val BORDER = new Color(70, 105, 140)
val TEXT = new Color(239, 247, 255)
val MUTED = new Color(155, 178, 201)
val CYAN = new Color(70, 215, 255)
val GREEN = new Color(73, 230, 142)
val YELLOW = new Color(255, 214, 88)
val RED = new Color(250, 92, 105)
val PURPLE = new Color(175, 110, 255)
val ORANGE = new Color(255, 156, 73)

val F_TITLE = new Font("SansSerif", Font.BOLD, 29)
val F_H1 = new Font("SansSerif", Font.BOLD, 21)
val F_H2 = new Font("SansSerif", Font.BOLD, 14)
val F_BODY = new Font("SansSerif", Font.PLAIN, 13)
val F_SMALL = new Font("SansSerif", Font.PLAIN, 11)
val F_MONO = new Font("Monospaced", Font.BOLD, 12)

case class Project(name: String, category: String, purpose: String, keys: String)
case class Feature(id: Int, domain: String, phase: String, challenge: String, action: String, metric: String)

val projects = Array(
  Project("SMART ELECTRICITY", "ENERGY", "Model appliance usage and reduce wasted energy.", "1-4 toggle loads; UP/DOWN changes selected hours"),
  Project("SOLAR OPTIMIZER", "ENERGY", "Explore angle, tracking, reflection, storage and load timing.", "LEFT/RIGHT mode; UP/DOWN angle; R/F reflection"),
  Project("SMART WATER", "WATER", "Explore rain capture, storage, demand and leakage.", "UP/DOWN rain; LEFT/RIGHT demand"),
  Project("SMART FARM", "FARM", "Balance water, sunlight, crop choice and budget.", "W/S water; A/D sunlight; C crop"),
  Project("SMART HOME", "HOME", "Balance comfort, devices and energy use.", "1-5 toggle devices"),
  Project("FACTORY QUALITY", "FACTORY", "Simulate a production line with quality inspection.", "SPACE batch; M manual; 1-8 stage"),
  Project("SMART CITY", "CITY", "Design infrastructure while tracking cost and benefit.", "1-5 add infrastructure"),
  Project("INVENTION LAB", "CREATE", "Build an invention from input -> controller -> storage -> output.", "I/C/S/O change blocks"),
  Project("STUDY SUPER OS", "LEARN", "Run a learn -> recall -> quiz -> review loop.", "SPACE study; Q quiz; C subject"),
  Project("EMERGENCY PLANNER", "SAFETY", "Practice safe preparedness and route planning.", "1-3 scenario; R adds route step"),
  Project("RESEARCH NOTEBOOK", "RESEARCH", "Turn an idea into a measurable experiment plan.", "1-5 choose research step; SPACE log result"),
  Project("GREEN DESIGN STUDIO", "SUSTAIN", "Compare repair, reuse, efficiency and lifecycle choices.", "1-6 toggle design actions")
)

// ================================================================
// 1000+ FEATURE / IDEA CATALOG
// 12 domains x 10 phases x 10 challenge patterns = 1200 items.
// The combinations are generated at runtime so the source stays fast.
// ================================================================
val catalogDomains = Array(
  "ENERGY", "WATER", "FARM", "HOME", "FACTORY", "CITY",
  "HEALTHY HABITS", "EDUCATION", "ENVIRONMENT", "INVENTION", "SAFETY", "DIGITAL SKILLS"
)

val catalogPhases = Array(
  "OBSERVE", "MEASURE", "MAP", "MODEL", "DESIGN", "BUILD", "TEST", "COMPARE", "IMPROVE", "EXPLAIN"
)

val catalogChallenges = Array(
  "reduce waste without reducing useful output",
  "measure input, output and efficiency",
  "identify the biggest bottleneck",
  "compare a baseline with one improvement",
  "balance cost, reliability and benefit",
  "create a simple feedback loop",
  "find a safer and simpler workflow",
  "make the result easy to explain",
  "repeat the test and record change",
  "turn a problem into a clear experiment"
)

val catalogActions = Array(
  "switch one variable at a time",
  "record a before value",
  "record an after value",
  "rank the strongest improvement",
  "draw the system as blocks",
  "estimate resource use",
  "set a target and check progress",
  "write a short conclusion",
  "run three comparison trials",
  "design a next-step experiment"
)

val catalogMetrics = Array(
  "ENERGY", "WATER", "TIME", "COST", "QUALITY", "SAFETY", "OUTPUT", "EFFICIENCY", "RELIABILITY", "LEARNING"
)

val featureCatalog = new ArrayBuffer[Feature]()
var fDomain = 0
var featureId = 1
while (fDomain < catalogDomains.length) {
  var fPhase = 0
  while (fPhase < catalogPhases.length) {
    var fChallenge = 0
    while (fChallenge < catalogChallenges.length) {
      featureCatalog += Feature(
        featureId,
        catalogDomains(fDomain),
        catalogPhases(fPhase),
        catalogChallenges(fChallenge),
        catalogActions((fDomain + fPhase + fChallenge) % catalogActions.length),
        catalogMetrics((fDomain * 3 + fPhase + fChallenge) % catalogMetrics.length)
      )
      featureId += 1
      fChallenge += 1
    }
    fPhase += 1
  }
  fDomain += 1
}

// Extra special rows make the library visibly larger than 1200.
var extraId = featureCatalog.length + 1
var special = 0
while (special < 40) {
  featureCatalog += Feature(
    extraId,
    "HISTORY MAKER",
    "MASTER",
    "combine two disciplines into one useful project",
    "merge observation + simulation + explanation",
    "INNOVATION"
  )
  extraId += 1
  special += 1
}

// ---------------------------- STATE ------------------------------
var selected = 0
var status = "READY"
var score = 0
var simCount = 0
var lastAction = "OPENED UNIVERSE"

// Smart Electricity
var elec = Array(true, true, false, false)
var elecHours = Array(6.0, 5.0, 3.0, 2.0)
var elecSelect = 0

// Solar
var solarAngle = 30.0
var solarMode = 1
var solarReflect = 0.20
var solarStorage = 55.0
var solarSize = 1000.0

// Water
var waterTank = 800.0
var waterRoof = 100.0
var waterRain = 20.0
var waterDemand = 120.0
var waterLeak = 5.0

// Farm
var farmWater = 60.0
var farmSun = 75.0
var farmCrop = 1
var farmBudget = 5000.0

// Home
var homeDevices = Array(true, true, true, false, false)

// Factory
var factoryProduced = 0
var factoryPassed = 0
var factoryRejected = 0
var factoryQuality = 96.0
var factoryStage = 1
var factoryRunning = false
var factoryModeManual = false

// City
var city = Array(2, 1, 1, 1, 1)

// Invention
var invInput = 0
var invController = 0
var invStorage = 0
var invOutput = 0
var invScore = 0
val invInputs = Array("SUNLIGHT", "RAINWATER", "MOTION", "HAND CRANK")
val invControllers = Array("SMART SWITCH", "TIMER", "SENSOR", "MICRO CONTROLLER")
val invStorages = Array("BATTERY", "TANK", "SUPER CAP", "NONE")
val invOutputs = Array("LED LIGHT", "GARDEN", "FAN", "WATER PUMP")

// Study
var studySubject = 0
var studyHours = 2
var studyProgress = 0
var studyQuiz = 0
val subjects = Array("SCIENCE", "MATH", "CODING", "DESIGN")

// Emergency
var emergency = 0
var emergencyPeople = 4
var emergencyRoutes = 0
var emergencyScore = 0
val emergencyNames = Array("POWER OUTAGE", "FLOOD PLANNING", "EARTHQUAKE PLANNING")

// Research
var researchStep = 0
var researchTrials = 0
var researchResult = 0.0
val researchSteps = Array("QUESTION", "HYPOTHESIS", "VARIABLES", "TRIAL", "CONCLUSION")

// Green Design
var greenActions = Array(true, false, true, false, false, true)
val greenNames = Array("REPAIR", "REUSE", "EFFICIENCY", "LOCAL", "RECYCLE", "DURABILITY")

// Catalog browsing
var catalogCursor = 0
var catalogFilter = "ALL"

// ---------------------------- HELPERS ----------------------------
def clamp(v: Double, lo: Double, hi: Double): Double = math.max(lo, math.min(hi, v))

def fmt(v: Double): String = java.lang.String.format("%.1f", java.lang.Double.valueOf(v))

def button(text: String): JButton = {
  val b = new JButton(text)
  b.setFocusable(false)
  b.setFont(F_SMALL)
  b.setForeground(TEXT)
  b.setBackground(PANEL3)
  b.setBorder(BorderFactory.createLineBorder(BORDER))
  b
}

// ================================================================
// UI ? all component vals are declared before functions that mutate them
// ================================================================
val root = new JPanel(new BorderLayout(8, 8))
root.setBackground(BG)
root.setBorder(new EmptyBorder(8, 8, 8, 8))

val header = new JPanel(new BorderLayout())
header.setBackground(new Color(5, 10, 17))
header.setBorder(new EmptyBorder(10, 14, 10, 14))

val heading = new JPanel(new GridLayout(2, 1))
heading.setOpaque(false)
val title = new JLabel("KOJO INNOVATION UNIVERSE")
title.setForeground(TEXT)
title.setFont(F_TITLE)
val sub = new JLabel("HISTORY MAKER X1000+  ?  LEARN  ?  DESIGN  ?  SIMULATE  ?  IMPROVE")
sub.setForeground(MUTED)
sub.setFont(F_SMALL)
heading.add(title)
heading.add(sub)
header.add(heading, BorderLayout.WEST)

val statusLabel = new JLabel("  READY  ")
statusLabel.setForeground(GREEN)
statusLabel.setFont(F_MONO)
header.add(statusLabel, BorderLayout.EAST)
root.add(header, BorderLayout.NORTH)

val projectModel = new DefaultListModel[String]()
var pi = 0
while (pi < projects.length) {
  projectModel.addElement(projects(pi).name)
  pi += 1
}

val projectList = new JList[String](projectModel)
projectList.setFont(F_BODY)
projectList.setBackground(new Color(9, 16, 27))
projectList.setForeground(TEXT)
projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
projectList.setSelectedIndex(0)

val leftPanel = new JPanel(new BorderLayout(5, 5))
leftPanel.setBackground(BG)
leftPanel.setPreferredSize(new Dimension(300, 650))
val leftLabel = new JLabel("INNOVATION LABS")
leftLabel.setForeground(CYAN)
leftLabel.setFont(F_H2)
leftPanel.add(leftLabel, BorderLayout.NORTH)
leftPanel.add(new JScrollPane(projectList), BorderLayout.CENTER)

val center = new JPanel(new BorderLayout(8, 8))
center.setBackground(BG)

val projectTitle = new JLabel("HOME")
projectTitle.setForeground(TEXT)
projectTitle.setFont(F_H1)

val topButtons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 6, 0))
topButtons.setOpaque(false)
val runButton = button("RUN SIMULATION")
val resetButton = button("RESET")
val nextButton = button("NEXT LAB")
val catalogButton = button("MASTER CATALOG")
val randomButton = button("RANDOM IDEA")
topButtons.add(runButton)
topButtons.add(resetButton)
topButtons.add(nextButton)
topButtons.add(catalogButton)
topButtons.add(randomButton)

val centerHeader = new JPanel(new BorderLayout())
centerHeader.setBackground(PANEL2)
centerHeader.setBorder(new EmptyBorder(9, 12, 9, 12))
centerHeader.add(projectTitle, BorderLayout.WEST)
centerHeader.add(topButtons, BorderLayout.EAST)
center.add(centerHeader, BorderLayout.NORTH)

val info = new JTextArea()
info.setEditable(false)
info.setLineWrap(true)
info.setWrapStyleWord(true)
info.setFont(F_BODY)
info.setForeground(TEXT)
info.setBackground(PANEL)
info.setBorder(new EmptyBorder(14, 14, 14, 14))

val output = new JTextArea()
output.setEditable(false)
output.setLineWrap(true)
output.setWrapStyleWord(true)
output.setFont(F_MONO)
output.setForeground(GREEN)
output.setBackground(new Color(3, 8, 13))
output.setBorder(new EmptyBorder(14, 14, 14, 14))

val workSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(info), new JScrollPane(output))
workSplit.setDividerLocation(470)
center.add(workSplit, BorderLayout.CENTER)

val right = new JPanel(new GridLayout(0, 1, 6, 6))
right.setBackground(BG)
right.setPreferredSize(new Dimension(270, 600))

val statTitle = new JLabel("LIVE METRICS")
statTitle.setForeground(CYAN)
statTitle.setFont(F_H2)
right.add(statTitle)

val metric1 = new JLabel()
val metric2 = new JLabel()
val metric3 = new JLabel()
val metric4 = new JLabel()
val metric5 = new JLabel()
val metric6 = new JLabel()
val metrics = Array(metric1, metric2, metric3, metric4, metric5, metric6)
var mi = 0
while (mi < metrics.length) {
  metrics(mi).setOpaque(true)
  metrics(mi).setBackground(PANEL)
  metrics(mi).setForeground(TEXT)
  metrics(mi).setBorder(BorderFactory.createLineBorder(BORDER))
  metrics(mi).setFont(F_H2)
  mi += 1
}
right.add(metric1)
right.add(metric2)
right.add(metric3)
right.add(metric4)
right.add(metric5)
right.add(metric6)

val countLabel = new JLabel("1200+ IDEAS")
countLabel.setForeground(YELLOW)
countLabel.setFont(F_MONO)
countLabel.setHorizontalAlignment(SwingConstants.CENTER)
countLabel.setOpaque(true)
countLabel.setBackground(PANEL2)
countLabel.setBorder(BorderFactory.createLineBorder(BORDER))
right.add(countLabel)

val footer = new JLabel("Offline ? educational models ? measure ? test ? improve")
footer.setForeground(MUTED)
footer.setFont(F_SMALL)
right.add(footer)

root.add(leftPanel, BorderLayout.WEST)
root.add(center, BorderLayout.CENTER)
root.add(right, BorderLayout.EAST)

// ----------------------- Shared UI helpers ----------------------
def setStatus(s: String): Unit = {
  status = s
  statusLabel.setText("  " + s + "  ")
}

def setMetrics(a: String, b: String, c: String, d: String, e: String, f: String): Unit = {
  metrics(0).setText("  " + a)
  metrics(1).setText("  " + b)
  metrics(2).setText("  " + c)
  metrics(3).setText("  " + d)
  metrics(4).setText("  " + e)
  metrics(5).setText("  " + f)
}

def addScore(n: Int, message: String): Unit = {
  score += n
  simCount += 1
  lastAction = message
  setStatus(message + "  +" + n)
}

def setProject(i: Int): Unit = {
  selected = math.max(0, math.min(projects.length - 1, i))
  projectList.setSelectedIndex(selected)
  renderProject()
}

// ================================================================
// RENDER HOME / CATALOG / LABS
// ================================================================
def renderHome(): Unit = {
  projectTitle.setText("HOME ? HISTORY MAKER")
  info.setText(
    "KOJO INNOVATION UNIVERSE\n\n" +
      "A large offline laboratory for learning, design, simulation and useful problem solving.\n\n" +
      "CORE LOOP\n" +
      "1. Observe a real problem.\n" +
      "2. Measure the important variables.\n" +
      "3. Build a small model.\n" +
      "4. Run a test.\n" +
      "5. Compare results.\n" +
      "6. Improve one thing.\n" +
      "7. Explain what changed.\n\n" +
      "FEATURE LIBRARY\n" +
      "The Master Catalog contains " + featureCatalog.length + " generated experiment/design prompts.\n" +
      "Use MASTER CATALOG or RANDOM IDEA to explore them.\n\n" +
      "LABS\n" +
      projects.map(p => "? " + p.name + " ? " + p.purpose).mkString("\n") +
      "\n\n" +
      "Important: all numerical systems are simplified educational models, not engineering guarantees."
  )
  output.setText(
    "HISTORY MAKER DASHBOARD\n\n" +
      "LABS            : " + projects.length + "\n" +
      "CATALOG ITEMS    : " + featureCatalog.length + "\n" +
      "SIMULATIONS      : " + simCount + "\n" +
      "TOTAL SCORE      : " + score + "\n" +
      "LAST ACTION      : " + lastAction + "\n\n" +
      "BEST WORKFLOW\n" +
      "MEASURE -> MODEL -> TEST -> COMPARE -> IMPROVE -> EXPLAIN"
  )
  setMetrics(projects.length + " LABS", featureCatalog.length + " IDEAS", "OFFLINE", "NO API", "SCORE " + score, "TESTS " + simCount)
  countLabel.setText(featureCatalog.length + "+ IDEAS")
  setStatus("HOME READY")
}

def renderCatalog(): Unit = {
  projectTitle.setText("MASTER CATALOG ? " + featureCatalog.length + "+ IDEAS")
  val start = catalogCursor
  val end = math.min(featureCatalog.length, start + 24)
  val chunk = new StringBuilder
  chunk.append("MASTER INNOVATION CATALOG\n\n")
  chunk.append("Filter: " + catalogFilter + "\n")
  chunk.append("Showing " + (start + 1) + " to " + end + " of " + featureCatalog.length + "\n\n")
  var i = start
  while (i < end) {
    val x = featureCatalog(i)
    val allowed = catalogFilter == "ALL" || x.domain == catalogFilter
    if (allowed) {
      chunk.append("#" + x.id + "  " + x.domain + "  /  " + x.phase + "\n")
      chunk.append("Challenge: " + x.challenge + "\n")
      chunk.append("Action: " + x.action + "\n")
      chunk.append("Metric: " + x.metric + "\n\n")
    }
    i += 1
  }
  info.setText(chunk.toString)
  output.setText(
    "CATALOG CONTROL\n\n" +
      "1-9 : quick jump\n" +
      "LEFT/RIGHT : previous/next block\n" +
      "UP/DOWN : same block navigation\n" +
      "SPACE : score current idea\n" +
      "F : cycle domain filter\n\n" +
      "CURRENT IDEA\n" +
      "#" + featureCatalog(catalogCursor).id + "\n" +
      featureCatalog(catalogCursor).domain + " / " + featureCatalog(catalogCursor).phase + "\n" +
      featureCatalog(catalogCursor).challenge + "\n\n" +
      "A strong project turns this prompt into: QUESTION + VARIABLES + TEST + RESULT + CONCLUSION."
  )
  setMetrics("CATALOG", featureCatalog.length + " ITEMS", catalogFilter, "ITEM #" + featureCatalog(catalogCursor).id, "SCORE " + score, "BLOCK " + ((catalogCursor / 24) + 1))
  countLabel.setText(featureCatalog.length + "+ IDEAS")
  setStatus("CATALOG READY")
}

def showElectricity(): Unit = {
  val watts = Array(60.0, 75.0, 120.0, 40.0)
  val names = Array("FAN", "COMPUTER", "HEATER", "LIGHT")
  var dailyWh = 0.0
  var i = 0
  while (i < 4) { if (elec(i)) dailyWh += watts(i) * elecHours(i); i += 1 }
  val kWh = dailyWh / 1000.0
  val monthly = kWh * 30.0
  output.setText(
    "SMART ELECTRICITY\n\n" +
      "Selected load: " + names(elecSelect) + "\n\n" +
      "FAN       : " + elec(0) + "  " + fmt(elecHours(0)) + " h\n" +
      "COMPUTER  : " + elec(1) + "  " + fmt(elecHours(1)) + " h\n" +
      "HEATER    : " + elec(2) + "  " + fmt(elecHours(2)) + " h\n" +
      "LIGHT     : " + elec(3) + "  " + fmt(elecHours(3)) + " h\n\n" +
      "Daily estimate : " + fmt(dailyWh) + " Wh\n" +
      "Monthly estimate: " + fmt(monthly) + " kWh" 
  )
  setMetrics("ENERGY", fmt(dailyWh) + " WH/DAY", fmt(monthly) + " KWH", "LOAD " + (elecSelect + 1), "SCORE " + score, "TESTS " + simCount)
}

def showSolar(): Unit = {
  val angleLoss = math.abs(solarAngle - 25.0) / 90.0
  val modeBonus = if (solarMode == 1) 1.05 else if (solarMode == 2) 1.10 else 1.15
  val reflectionBonus = 1.0 + clamp(solarReflect, 0.0, 0.50) * 0.35
  val efficiency = clamp((1.0 - angleLoss) * modeBonus * reflectionBonus, 0.0, 1.20)
  val outputW = solarSize * efficiency * 0.80
  solarStorage = clamp(solarStorage + outputW / 5000.0 - 0.5, 0.0, 100.0)
  val modeName = if (solarMode == 1) "FIXED" else if (solarMode == 2) "1-AXIS" else "2-AXIS"
  output.setText(
    "SOLAR OPTIMIZER\n\n" +
      "Mode       : " + modeName + "\n" +
      "Panel angle: " + fmt(solarAngle) + " deg\n" +
      "Reflection : " + fmt(solarReflect * 100.0) + "%\n" +
      "Storage    : " + fmt(solarStorage) + "%\n\n" +
      "Simplified output estimate: " + fmt(outputW) + " W\n\n" +
      "This is an educational whole-system model, not a claim that a panel can create extra energy from nothing."
  )
  setMetrics(modeName, "ANGLE " + fmt(solarAngle), fmt(solarReflect * 100.0) + "% REF", fmt(outputW) + " W", "STORAGE " + fmt(solarStorage) + "%", "SCORE " + score)
}

def showWater(): Unit = {
  val capture = clamp(waterRain * waterRoof * 0.02, 0.0, 1200.0)
  val nextTank = clamp(waterTank + capture - waterDemand - waterLeak, 0.0, 2000.0)
  output.setText(
    "SMART WATER\n\n" +
      "Rain index : " + fmt(waterRain) + "\n" +
      "Roof area  : " + fmt(waterRoof) + "\n" +
      "Demand     : " + fmt(waterDemand) + "\n" +
      "Leakage    : " + fmt(waterLeak) + "\n\n" +
      "Captured today (simplified): " + fmt(capture) + " L\n" +
      "Next tank level: " + fmt(nextTank) + " L\n\n" +
      "Goal: keep enough stored water while lowering waste and leakage."
  )
  setMetrics("WATER", "CAPTURE " + fmt(capture) + " L", "DEMAND " + fmt(waterDemand) + " L", "TANK " + fmt(nextTank) + " L", "LEAK " + fmt(waterLeak) + " L", "SCORE " + score)
}

def showFarm(): Unit = {
  val crops = Array("WHEAT", "RICE", "VEGETABLE", "MILLETS")
  val cropFactor = Array(0.80, 1.20, 1.05, 0.90)
  val fit = clamp((farmWater / 100.0) * 0.5 + (farmSun / 100.0) * 0.5, 0.0, 1.0)
  val yieldIndex = clamp(fit * cropFactor(farmCrop), 0.0, 1.5)
  val cost = 300.0 + farmWater * 4.0 + farmSun * 2.0
  output.setText(
    "SMART FARM\n\n" +
      "Crop   : " + crops(farmCrop) + "\n" +
      "Water  : " + fmt(farmWater) + "%\n" +
      "Sun    : " + fmt(farmSun) + "%\n" +
      "Budget : Rs " + fmt(farmBudget) + "\n\n" +
      "Yield index: " + fmt(yieldIndex * 100.0) + "%\n" +
      "Estimated cycle cost: Rs " + fmt(cost) + "\n\n" +
      "Try one-variable changes and compare the yield index."
  )
  setMetrics(crops(farmCrop), "WATER " + fmt(farmWater), "SUN " + fmt(farmSun), "YIELD " + fmt(yieldIndex * 100.0) + "%", "COST " + fmt(cost), "SCORE " + score)
}

def showHome(): Unit = {
  val watts = Array(60, 75, 100, 40, 25)
  val names = Array("FAN", "PC", "TV", "LIGHT", "CHARGER")
  var total = 0
  var i = 0
  while (i < homeDevices.length) { if (homeDevices(i)) total += watts(i); i += 1 }
  output.setText(
    "SMART HOME\n\n" +
      "1 FAN       : " + homeDevices(0) + "\n" +
      "2 PC        : " + homeDevices(1) + "\n" +
      "3 TV        : " + homeDevices(2) + "\n" +
      "4 LIGHT     : " + homeDevices(3) + "\n" +
      "5 CHARGER   : " + homeDevices(4) + "\n\n" +
      "Instant modeled load: " + total + " W\n\n" +
      "A useful smart-home rule is to turn off devices that are not serving a current purpose.\n\n" +
      "Active: " + names.zip(homeDevices).filter(_._2).map(_._1).mkString(", ")
  )
  setMetrics("HOME", "LOAD " + total + " W", "DEVICES " + homeDevices.count(x => x), "CONTROL READY", "SCORE " + score, "TESTS " + simCount)
}

def showFactory(): Unit = {
  output.setText(
    "FACTORY QUALITY\n\n" +
      "Stage   : " + factoryStage + " / 8\n" +
      "Mode    : " + (if (factoryModeManual) "MANUAL" else "AUTO") + "\n" +
      "Running : " + factoryRunning + "\n\n" +
      "Produced : " + factoryProduced + "\n" +
      "Passed   : " + factoryPassed + "\n" +
      "Rejected : " + factoryRejected + "\n" +
      "Quality  : " + fmt(factoryQuality) + "%\n\n" +
      "SPACE = run batch\nM = toggle manual/auto\n1-8 = select stage"
  )
  setMetrics("FACTORY", "STAGE " + factoryStage, "PASS " + factoryPassed, "REJECT " + factoryRejected, "QUALITY " + fmt(factoryQuality) + "%", "SCORE " + score)
}

def showCity(): Unit = {
  val names = Array("ROADS", "PARKS", "SCHOOLS", "WATER", "SOLAR")
  var total = 0
  var i = 0
  while (i < city.length) { total += city(i); i += 1 }
  val cost = city(0) * 120 + city(1) * 60 + city(2) * 140 + city(3) * 110 + city(4) * 150
  output.setText(
    "SMART CITY\n\n" +
      "ROADS   : " + city(0) + "\n" +
      "PARKS   : " + city(1) + "\n" +
      "SCHOOLS : " + city(2) + "\n" +
      "WATER   : " + city(3) + "\n" +
      "SOLAR   : " + city(4) + "\n\n" +
      "Infrastructure units: " + total + "\n" +
      "Modeled planning cost: " + cost + " points\n\n" +
      "Design principle: essential services first, then resilience and sustainability."
  )
  setMetrics("CITY", "UNITS " + total, "COST " + cost, "SOLAR " + city(4), "WATER " + city(3), "SCORE " + score)
}

def showInvention(): Unit = {
  invScore = (invInput + invController + invStorage + invOutput + 1) * 10
  output.setText(
    "INVENTION LAB\n\n" +
      "INPUT      : " + invInputs(invInput) + "\n" +
      "CONTROL    : " + invControllers(invController) + "\n" +
      "STORAGE    : " + invStorages(invStorage) + "\n" +
      "OUTPUT     : " + invOutputs(invOutput) + "\n\n" +
      "Concept score: " + invScore + " / 180\n\n" +
      "Architecture:\n" +
      "INPUT -> CONTROLLER -> STORAGE -> OUTPUT\n\n" +
      "Ask: What is measured? What changes? What proves it works?"
  )
  setMetrics("CREATE", invInputs(invInput), invControllers(invController), invStorages(invStorage), "OUTPUT " + invOutputs(invOutput), "SCORE " + invScore)
}

def showStudy(): Unit = {
  output.setText(
    "STUDY SUPER OS\n\n" +
      "Subject : " + subjects(studySubject) + "\n" +
      "Hours   : " + studyHours + "\n" +
      "Progress: " + studyProgress + "%\n" +
      "Quiz    : " + studyQuiz + "%\n\n" +
      "Loop:\nLEARN -> RECALL -> QUIZ -> REVIEW\n\n" +
      "SPACE = study block\nQ = quiz\nC = change subject"
  )
  setMetrics("LEARN", subjects(studySubject), "PROGRESS " + studyProgress + "%", "QUIZ " + studyQuiz + "%", "HOURS " + studyHours, "SCORE " + score)
}

def showEmergency(): Unit = {
  output.setText(
    "EMERGENCY PLANNER\n\n" +
      "Scenario : " + emergencyNames(emergency) + "\n" +
      "People   : " + emergencyPeople + "\n" +
      "Routes   : " + emergencyRoutes + "\n" +
      "Score    : " + emergencyScore + "\n\n" +
      "Planning basics:\n" +
      "? identify safe areas\n" +
      "? keep communication options\n" +
      "? protect important supplies\n" +
      "? follow official local guidance\n\n" +
      "1-3 = scenario\nR = add route step"
  )
  setMetrics("SAFETY", emergencyNames(emergency), "PEOPLE " + emergencyPeople, "ROUTES " + emergencyRoutes, "PLAN " + emergencyScore, "SCORE " + score)
}

def showResearch(): Unit = {
  output.setText(
    "RESEARCH NOTEBOOK\n\n" +
      "Step   : " + researchSteps(researchStep) + "\n" +
      "Trials : " + researchTrials + "\n" +
      "Result : " + fmt(researchResult) + "\n\n" +
      "Workflow:\n" +
      "QUESTION -> HYPOTHESIS -> VARIABLES -> TRIAL -> CONCLUSION\n\n" +
      "1-5 = choose step\nSPACE = log a result\nR = run trial"
  )
  setMetrics("RESEARCH", researchSteps(researchStep), "TRIALS " + researchTrials, "RESULT " + fmt(researchResult), "STEP " + (researchStep + 1) + "/5", "SCORE " + score)
}

def showGreen(): Unit = {
  var active = 0
  var i = 0
  while (i < greenActions.length) { if (greenActions(i)) active += 1; i += 1 }
  val benefit = active * 16
  output.setText(
    "GREEN DESIGN STUDIO\n\n" +
      "Active design actions:\n" +
      "1 REPAIR      : " + greenActions(0) + "\n" +
      "2 REUSE       : " + greenActions(1) + "\n" +
      "3 EFFICIENCY  : " + greenActions(2) + "\n" +
      "4 LOCAL       : " + greenActions(3) + "\n" +
      "5 RECYCLE     : " + greenActions(4) + "\n" +
      "6 DURABILITY  : " + greenActions(5) + "\n\n" +
      "Simple design benefit index: " + benefit + "\n\n" +
      "This is a learning model. Real lifecycle impacts depend on material, transport, repairability and use."
  )
  setMetrics("SUSTAIN", "ACTIVE " + active, "INDEX " + benefit, "DESIGN READY", "SCORE " + score, "TESTS " + simCount)
}

def renderProject(): Unit = {
  selected match {
    case 0 =>
      projectTitle.setText("SMART ELECTRICITY")
      info.setText("SMART ELECTRICITY SAVER\n\nGoal: understand energy use and identify waste.\n\nLoads:\n1 = FAN 60 W\n2 = COMPUTER 75 W\n3 = HEATER 120 W\n4 = LIGHT 40 W\n\nKeys:\n1-4 toggle loads.\nUP/DOWN changes selected load hours.\nRUN SIMULATION calculates the estimate.")
      showElectricity()
    case 1 =>
      projectTitle.setText("SOLAR OPTIMIZER")
      info.setText("SOLAR SYSTEM OPTIMIZER\n\nStudy angle, tracking, reflection, storage and timing.\n\nUP/DOWN = angle\nLEFT/RIGHT = tracking mode\nR/F = reflection\n+/- = storage\n\nEducational model only. It does not claim impossible energy creation.")
      showSolar()
    case 2 =>
      projectTitle.setText("SMART WATER")
      info.setText("SMART WATER LAB\n\nExplore rain capture, tank storage, demand and leakage.\n\nUP/DOWN = rain\nLEFT/RIGHT = demand\n\nGoal: increase useful capture and reduce waste.")
      showWater()
    case 3 =>
      projectTitle.setText("SMART FARM")
      info.setText("SMART FARM LAB\n\nBalance water, sunlight, crop and budget.\n\nW/S = water\nA/D = sunlight\nC = crop\n\nUse one-variable experiments to compare outcomes.")
      showFarm()
    case 4 =>
      projectTitle.setText("SMART HOME")
      info.setText("SMART HOME\n\nToggle devices and observe modeled power load.\n\n1-5 = toggle devices\n\nThink in terms of useful service, timing, automation and standby waste.")
      showHome()
    case 5 =>
      projectTitle.setText("FACTORY QUALITY")
      info.setText("FACTORY QUALITY\n\nSimulate a simple production line.\n\nSPACE = run batch\nM = manual/auto\n1-8 = choose stage\n\nAim for repeatability and inspection, not just speed.")
      showFactory()
    case 6 =>
      projectTitle.setText("SMART CITY")
      info.setText("SMART CITY\n\nBuild a balanced infrastructure plan.\n\n1 ROADS\n2 PARKS\n3 SCHOOLS\n4 WATER\n5 SOLAR\n\nAsk which service is essential before adding extras.")
      showCity()
    case 7 =>
      projectTitle.setText("INVENTION LAB")
      info.setText("INVENTION LAB\n\nBuild a system from input to useful output.\n\nI = input\nC = controller\nS = storage\nO = output\n\nUse the architecture to turn an idea into a testable prototype.")
      showInvention()
    case 8 =>
      projectTitle.setText("STUDY SUPER OS")
      info.setText("STUDY SUPER OS\n\nUse active learning rather than only rereading.\n\nSPACE = study\nQ = quiz\nC = subject\n\nThe model rewards recall and review cycles.")
      showStudy()
    case 9 =>
      projectTitle.setText("EMERGENCY PLANNER")
      info.setText("EMERGENCY PLANNER\n\nPractice preparedness thinking.\n\n1-3 = scenario\nR = add route step\n\nAlways use official local emergency guidance for real situations.")
      showEmergency()
    case 10 =>
      projectTitle.setText("RESEARCH NOTEBOOK")
      info.setText("RESEARCH NOTEBOOK\n\nTurn an idea into a measurable experiment.\n\n1-5 = research step\nSPACE = record a result\nR = run a trial\n\nWrite the question before changing variables.")
      showResearch()
    case 11 =>
      projectTitle.setText("GREEN DESIGN STUDIO")
      info.setText("GREEN DESIGN STUDIO\n\nCompare repair, reuse, efficiency, local sourcing, recycling and durability.\n\n1-6 = toggle actions\n\nThink across the full lifecycle, not a single moment.")
      showGreen()
  }
}

// ------------------------ Simulations ---------------------------
def runSimulation(): Unit = {
  selected match {
    case 0 =>
      val before = elecHours.sum
      var i = 0
      while (i < elecHours.length) { if (elec(i)) elecHours(i) = clamp(elecHours(i) - 0.5, 0.5, 12.0); i += 1 }
      val after = elecHours.sum
      addScore(if (after < before) 15 else 5, "ELECTRICITY TEST")
      showElectricity()
    case 1 =>
      solarAngle = clamp(solarAngle + 5.0, 0.0, 90.0)
      addScore(12, "SOLAR TEST")
      showSolar()
    case 2 =>
      waterLeak = clamp(waterLeak - 1.0, 0.0, 30.0)
      waterTank = clamp(waterTank + 80.0, 0.0, 2000.0)
      addScore(15, "WATER TEST")
      showWater()
    case 3 =>
      farmWater = clamp(farmWater + 4.0, 0.0, 100.0)
      addScore(10, "FARM TEST")
      showFarm()
    case 4 =>
      homeDevices(4) = !homeDevices(4)
      addScore(8, "HOME TEST")
      showHome()
    case 5 =>
      factoryRunning = true
      factoryProduced += 10
      factoryPassed += 9
      factoryRejected += 1
      factoryQuality = clamp((factoryPassed.toDouble / math.max(1, factoryProduced)) * 100.0, 0.0, 100.0)
      addScore(14, "FACTORY BATCH")
      showFactory()
    case 6 =>
      city(4) += 1
      addScore(11, "CITY SOLAR")
      showCity()
    case 7 =>
      invController = (invController + 1) % invControllers.length
      addScore(13, "INVENTION ITERATION")
      showInvention()
    case 8 =>
      studyProgress = math.min(100, studyProgress + 16)
      studyQuiz = math.min(100, 50 + studyProgress / 2)
      addScore(12, "STUDY CYCLE")
      showStudy()
    case 9 =>
      emergencyRoutes += 1
      emergencyScore = math.min(100, emergencyRoutes * 20 + emergencyPeople * 5)
      addScore(10, "SAFETY PLAN")
      showEmergency()
    case 10 =>
      researchTrials += 1
      researchResult = researchTrials * 7.5 + researchStep * 2.0
      addScore(16, "RESEARCH TRIAL")
      showResearch()
    case 11 =>
      var i = 0
      while (i < greenActions.length) { if (i % 2 == 0) greenActions(i) = !greenActions(i); i += 1 }
      addScore(11, "GREEN DESIGN")
      showGreen()
  }
}

def resetAll(): Unit = {
  selected = 0
  score = 0
  simCount = 0
  lastAction = "RESET TO BASELINE"
  elec = Array(true, true, false, false)
  elecHours = Array(6.0, 5.0, 3.0, 2.0)
  elecSelect = 0
  solarAngle = 30.0
  solarMode = 1
  solarReflect = 0.20
  solarStorage = 55.0
  waterTank = 800.0
  waterRain = 20.0
  waterDemand = 120.0
  waterLeak = 5.0
  farmWater = 60.0
  farmSun = 75.0
  farmCrop = 1
  farmBudget = 5000.0
  homeDevices = Array(true, true, true, false, false)
  factoryProduced = 0
  factoryPassed = 0
  factoryRejected = 0
  factoryQuality = 96.0
  factoryStage = 1
  factoryRunning = false
  factoryModeManual = false
  city = Array(2, 1, 1, 1, 1)
  invInput = 0
  invController = 0
  invStorage = 0
  invOutput = 0
  studySubject = 0
  studyHours = 2
  studyProgress = 0
  studyQuiz = 0
  emergency = 0
  emergencyPeople = 4
  emergencyRoutes = 0
  emergencyScore = 0
  researchStep = 0
  researchTrials = 0
  researchResult = 0.0
  greenActions = Array(true, false, true, false, false, true)
  renderProject()
  addScore(0, "RESET COMPLETE")
}

// ------------------------ Catalog tools --------------------------
def showRandomIdea(): Unit = {
  catalogCursor = (catalogCursor * 37 + 97) % featureCatalog.length
  renderCatalog()
  lastAction = "OPENED IDEA #" + featureCatalog(catalogCursor).id
  setStatus("RANDOM IDEA")
}

def cycleCatalogFilter(): Unit = {
  if (catalogFilter == "ALL") catalogFilter = catalogDomains(0)
  else {
    var idx = 0
    while (idx < catalogDomains.length && catalogDomains(idx) != catalogFilter) idx += 1
    if (idx >= catalogDomains.length - 1) catalogFilter = "ALL"
    else catalogFilter = catalogDomains(idx + 1)
  }
  catalogCursor = 0
  renderCatalog()
}

def scoreCurrentIdea(): Unit = {
  val x = featureCatalog(catalogCursor)
  score += 20
  simCount += 1
  lastAction = "SCORED #" + x.id
  setStatus("IDEA SCORED +20")
  renderCatalog()
}

// ----------------------- Event handlers -------------------------
projectList.addListSelectionListener(new javax.swing.event.ListSelectionListener {
  override def valueChanged(e: javax.swing.event.ListSelectionEvent): Unit = {
    if (!e.getValueIsAdjusting) {
      selected = projectList.getSelectedIndex
      renderProject()
      root.requestFocusInWindow()
    }
  }
})

runButton.addActionListener(new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    if (currentIsCatalog) scoreCurrentIdea() else runSimulation()
    root.requestFocusInWindow()
  }
})

resetButton.addActionListener(new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    resetAll()
    renderHome()
    root.requestFocusInWindow()
  }
})

nextButton.addActionListener(new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    selected = (selected + 1) % projects.length
    renderProject()
    root.requestFocusInWindow()
  }
})

catalogButton.addActionListener(new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    renderCatalog()
    root.requestFocusInWindow()
  }
})

randomButton.addActionListener(new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    showRandomIdea()
    root.requestFocusInWindow()
  }
})

// Helper to detect whether the current screen is the catalog.
def currentIsCatalog: Boolean = projectTitle.getText.startsWith("MASTER CATALOG")

root.setFocusable(true)
root.setFocusTraversalKeysEnabled(false)
root.addKeyListener(new KeyAdapter {
  override def keyPressed(e: KeyEvent): Unit = {
    if (currentIsCatalog) {
      e.getKeyCode match {
        case KeyEvent.VK_RIGHT => catalogCursor = math.min(featureCatalog.length - 1, catalogCursor + 24); renderCatalog()
        case KeyEvent.VK_LEFT => catalogCursor = math.max(0, catalogCursor - 24); renderCatalog()
        case KeyEvent.VK_DOWN => catalogCursor = math.min(featureCatalog.length - 1, catalogCursor + 1); renderCatalog()
        case KeyEvent.VK_UP => catalogCursor = math.max(0, catalogCursor - 1); renderCatalog()
        case KeyEvent.VK_SPACE => scoreCurrentIdea()
        case KeyEvent.VK_F => cycleCatalogFilter()
        case KeyEvent.VK_1 => catalogCursor = 0; renderCatalog()
        case KeyEvent.VK_2 => catalogCursor = math.min(featureCatalog.length - 1, 120); renderCatalog()
        case KeyEvent.VK_3 => catalogCursor = math.min(featureCatalog.length - 1, 240); renderCatalog()
        case KeyEvent.VK_4 => catalogCursor = math.min(featureCatalog.length - 1, 360); renderCatalog()
        case KeyEvent.VK_5 => catalogCursor = math.min(featureCatalog.length - 1, 480); renderCatalog()
        case KeyEvent.VK_6 => catalogCursor = math.min(featureCatalog.length - 1, 600); renderCatalog()
        case KeyEvent.VK_7 => catalogCursor = math.min(featureCatalog.length - 1, 720); renderCatalog()
        case KeyEvent.VK_8 => catalogCursor = math.min(featureCatalog.length - 1, 840); renderCatalog()
        case KeyEvent.VK_9 => catalogCursor = math.min(featureCatalog.length - 1, 960); renderCatalog()
        case _ =>
      }
    } else {
      selected match {
        case 0 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 | KeyEvent.VK_2 | KeyEvent.VK_3 | KeyEvent.VK_4 =>
              elecSelect = e.getKeyCode - KeyEvent.VK_1
              elec(elecSelect) = !elec(elecSelect)
            case KeyEvent.VK_UP => elecHours(elecSelect) = clamp(elecHours(elecSelect) + 0.5, 0.5, 12.0)
            case KeyEvent.VK_DOWN => elecHours(elecSelect) = clamp(elecHours(elecSelect) - 0.5, 0.5, 12.0)
            case _ =>
          }
          showElectricity()
        case 1 =>
          e.getKeyCode match {
            case KeyEvent.VK_UP => solarAngle = clamp(solarAngle + 5.0, 0.0, 90.0)
            case KeyEvent.VK_DOWN => solarAngle = clamp(solarAngle - 5.0, 0.0, 90.0)
            case KeyEvent.VK_LEFT => solarMode = math.max(1, solarMode - 1)
            case KeyEvent.VK_RIGHT => solarMode = math.min(3, solarMode + 1)
            case KeyEvent.VK_R => solarReflect = clamp(solarReflect + 0.05, 0.0, 0.50)
            case KeyEvent.VK_F => solarReflect = clamp(solarReflect - 0.05, 0.0, 0.50)
            case KeyEvent.VK_ADD | KeyEvent.VK_EQUALS => solarStorage = clamp(solarStorage + 5.0, 0.0, 100.0)
            case KeyEvent.VK_SUBTRACT | KeyEvent.VK_MINUS => solarStorage = clamp(solarStorage - 5.0, 0.0, 100.0)
            case _ =>
          }
          showSolar()
        case 2 =>
          e.getKeyCode match {
            case KeyEvent.VK_UP => waterRain = clamp(waterRain + 5.0, 0.0, 100.0)
            case KeyEvent.VK_DOWN => waterRain = clamp(waterRain - 5.0, 0.0, 100.0)
            case KeyEvent.VK_LEFT => waterDemand = clamp(waterDemand - 10.0, 10.0, 250.0)
            case KeyEvent.VK_RIGHT => waterDemand = clamp(waterDemand + 10.0, 10.0, 250.0)
            case _ =>
          }
          showWater()
        case 3 =>
          e.getKeyCode match {
            case KeyEvent.VK_W => farmWater = clamp(farmWater + 5.0, 0.0, 100.0)
            case KeyEvent.VK_S => farmWater = clamp(farmWater - 5.0, 0.0, 100.0)
            case KeyEvent.VK_A => farmSun = clamp(farmSun - 5.0, 0.0, 100.0)
            case KeyEvent.VK_D => farmSun = clamp(farmSun + 5.0, 0.0, 100.0)
            case KeyEvent.VK_C => farmCrop = (farmCrop + 1) % 4
            case _ =>
          }
          showFarm()
        case 4 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 => homeDevices(0) = !homeDevices(0)
            case KeyEvent.VK_2 => homeDevices(1) = !homeDevices(1)
            case KeyEvent.VK_3 => homeDevices(2) = !homeDevices(2)
            case KeyEvent.VK_4 => homeDevices(3) = !homeDevices(3)
            case KeyEvent.VK_5 => homeDevices(4) = !homeDevices(4)
            case _ =>
          }
          showHome()
        case 5 =>
          e.getKeyCode match {
            case KeyEvent.VK_SPACE =>
              factoryRunning = true
              factoryProduced += 10
              val passed = 8 + ((factoryProduced + factoryStage) % 3)
              factoryPassed += passed
              factoryRejected += 10 - passed
              factoryQuality = (factoryPassed.toDouble / math.max(1, factoryProduced)) * 100.0
            case KeyEvent.VK_M => factoryModeManual = !factoryModeManual
            case KeyEvent.VK_1 => factoryStage = 1
            case KeyEvent.VK_2 => factoryStage = 2
            case KeyEvent.VK_3 => factoryStage = 3
            case KeyEvent.VK_4 => factoryStage = 4
            case KeyEvent.VK_5 => factoryStage = 5
            case KeyEvent.VK_6 => factoryStage = 6
            case KeyEvent.VK_7 => factoryStage = 7
            case KeyEvent.VK_8 => factoryStage = 8
            case _ =>
          }
          showFactory()
        case 6 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 => city(0) += 1
            case KeyEvent.VK_2 => city(1) += 1
            case KeyEvent.VK_3 => city(2) += 1
            case KeyEvent.VK_4 => city(3) += 1
            case KeyEvent.VK_5 => city(4) += 1
            case _ =>
          }
          showCity()
        case 7 =>
          e.getKeyCode match {
            case KeyEvent.VK_I => invInput = (invInput + 1) % invInputs.length
            case KeyEvent.VK_C => invController = (invController + 1) % invControllers.length
            case KeyEvent.VK_S => invStorage = (invStorage + 1) % invStorages.length
            case KeyEvent.VK_O => invOutput = (invOutput + 1) % invOutputs.length
            case _ =>
          }
          showInvention()
        case 8 =>
          e.getKeyCode match {
            case KeyEvent.VK_SPACE => studyProgress = math.min(100, studyProgress + studyHours * 8)
            case KeyEvent.VK_Q => studyQuiz = math.min(100, 50 + studyProgress / 2)
            case KeyEvent.VK_C => studySubject = (studySubject + 1) % subjects.length
            case _ =>
          }
          showStudy()
        case 9 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 => emergency = 0
            case KeyEvent.VK_2 => emergency = 1
            case KeyEvent.VK_3 => emergency = 2
            case KeyEvent.VK_R => emergencyRoutes += 1; emergencyScore = math.min(100, emergencyRoutes * 20 + emergencyPeople * 5)
            case _ =>
          }
          showEmergency()
        case 10 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 => researchStep = 0
            case KeyEvent.VK_2 => researchStep = 1
            case KeyEvent.VK_3 => researchStep = 2
            case KeyEvent.VK_4 => researchStep = 3
            case KeyEvent.VK_5 => researchStep = 4
            case KeyEvent.VK_SPACE => researchResult += 10.0
            case KeyEvent.VK_R => researchTrials += 1; researchResult = researchTrials * 7.5 + researchStep * 2.0
            case _ =>
          }
          showResearch()
        case 11 =>
          e.getKeyCode match {
            case KeyEvent.VK_1 => greenActions(0) = !greenActions(0)
            case KeyEvent.VK_2 => greenActions(1) = !greenActions(1)
            case KeyEvent.VK_3 => greenActions(2) = !greenActions(2)
            case KeyEvent.VK_4 => greenActions(3) = !greenActions(3)
            case KeyEvent.VK_5 => greenActions(4) = !greenActions(4)
            case KeyEvent.VK_6 => greenActions(5) = !greenActions(5)
            case _ =>
          }
          showGreen()
      }
    }
    root.requestFocusInWindow()
    root.repaint()
  }
})

// -------------------------- Window -------------------------------
val frame = new JFrame("KOJO INNOVATION UNIVERSE ? HISTORY MAKER X1000+")
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
frame.setSize(APP_W, APP_H)
frame.setLocationRelativeTo(null)
frame.setContentPane(root)
frame.setVisible(true)

val timer = new Timer(700, new ActionListener {
  override def actionPerformed(e: ActionEvent): Unit = {
    if (!currentIsCatalog && selected == 5 && !factoryModeManual && factoryRunning) {
      factoryStage = if (factoryStage >= 8) 1 else factoryStage + 1
      showFactory()
    }
  }
})
timer.start()

renderHome()
root.requestFocusInWindow()