>
+ ? Node
+ : never;
+
+export type LC3Node =
+ | NodeTypeOf<"alu", typeof ALUNode>
+ | NodeTypeOf<"logic", typeof LogicNode>
+ | NodeTypeOf<"mux", typeof MuxNode>
+ | NodeTypeOf<"tristate", typeof TriStateNode>
+ | NodeTypeOf<"bus", typeof BusNode>;
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 43be534..c4a7737 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,12 +1,16 @@
import { createApp } from 'vue';
+import router from './router';
import App from './App.vue';
import PrimeVue from 'primevue/config';
import Aura from '@primevue/themes/aura';
import './style.css';
+import '@vue-flow/core/dist/style.css';
+import '@vue-flow/core/dist/theme-default.css';
import { definePreset } from '@primevue/themes';
import type { PrimeVueConfiguration } from 'primevue';
createApp(App)
+ .use(router)
.use(PrimeVue, {
theme: {
preset: definePreset(Aura, {
diff --git a/src/pages/Home.vue b/src/pages/Home.vue
new file mode 100644
index 0000000..fd5d8e6
--- /dev/null
+++ b/src/pages/Home.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
CS 2110 Computer Organization and Programming Visualization Tool
+
+
+
+
+
+
+
+
+
+
{{ p.title }}
+
{{ p.desc }}
+
Open →
+
+
+
No matches – try a different term.
+
+
+
+
+
+
+
diff --git a/src/pages/NotFound.vue b/src/pages/NotFound.vue
new file mode 100644
index 0000000..7001bfe
--- /dev/null
+++ b/src/pages/NotFound.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
Page Not Found
+ Return Home
+
+
diff --git a/src/projects/IEEE/App.vue b/src/projects/IEEE/App.vue
new file mode 100644
index 0000000..ecbe55f
--- /dev/null
+++ b/src/projects/IEEE/App.vue
@@ -0,0 +1,715 @@
+
+
+
+
+ IEEE 754 Floating Point Visualizer
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/projects/IEEE/style.css b/src/projects/IEEE/style.css
new file mode 100644
index 0000000..0a7c9ac
--- /dev/null
+++ b/src/projects/IEEE/style.css
@@ -0,0 +1,858 @@
+@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap');
+
+.ieee-root * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+.ieee-root :root, .ieee-root {
+ --gt-navy: #003057;
+ --gt-gold: #B3A369;
+ --gt-light-gold: #E8D5A3;
+ --gt-dark-navy: #001a33;
+ --gt-accent: #FFD700;
+ --surface: rgba(0, 48, 87, 0.95);
+ --surface-light: rgba(179, 163, 105, 0.1);
+ --text-primary: #ffffff;
+ --text-secondary: #E8D5A3;
+ --border-color: rgba(179, 163, 105, 0.3);
+ --shadow: rgba(0, 26, 51, 0.4);
+}
+
+.ieee-root body, .ieee-root {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+ background: linear-gradient(135deg, var(--gt-dark-navy) 0%, var(--gt-navy) 50%, #002244 100%);
+ background-attachment: fixed;
+ min-height: 100vh;
+ padding: 24px;
+ color: var(--text-primary);
+ position: relative;
+}
+
+.ieee-root body::before, .ieee-root::before {
+ content: '';
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: radial-gradient(ellipse at 20% 20%, rgba(179, 163, 105, 0.05) 0%, transparent 50%),
+ radial-gradient(ellipse at 80% 80%, rgba(255, 215, 0, 0.03) 0%, transparent 50%);
+ pointer-events: none;
+ z-index: -1;
+}
+
+.ieee-root .container {
+ max-width: 1300px;
+ margin: 0 auto;
+ background: var(--surface);
+ backdrop-filter: blur(20px);
+ border-radius: 24px;
+ padding: 40px;
+ box-shadow:
+ 0 24px 48px var(--shadow),
+ 0 0 0 1px var(--border-color),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+ overflow: hidden;
+}
+
+.ieee-root .container::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, var(--gt-gold) 0%, var(--gt-accent) 50%, var(--gt-gold) 100%);
+ animation: shimmer 3s ease-in-out infinite;
+}
+
+@keyframes shimmer {
+ 0%, 100% { opacity: 0.8; }
+ 50% { opacity: 1; }
+}
+
+.ieee-root h1 {
+ text-align: center;
+ font-size: clamp(2rem, 5vw, 3.5rem);
+ font-weight: 700;
+ margin-bottom: 48px;
+ letter-spacing: -0.02em;
+ background: linear-gradient(
+ 45deg,
+ var(--gt-gold) 0%,
+ var(--gt-accent) 25%,
+ var(--gt-light-gold) 50%,
+ var(--gt-accent) 75%,
+ var(--gt-gold) 100%
+ );
+ background-size: 400% 400%;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ animation: gradientFlow 4s ease-in-out infinite;
+}
+
+@keyframes gradientFlow {
+ 0%, 100% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+}
+
+.ieee-root h1 .gt-badge {
+ display: inline-block;
+ font-size: 0.4em;
+ background: var(--gt-gold);
+ color: var(--gt-navy);
+ padding: 4px 8px;
+ border-radius: 12px;
+ margin-left: 12px;
+ font-weight: 600;
+ vertical-align: super;
+}
+
+.ieee-root .input-section {
+ background: var(--surface-light);
+ backdrop-filter: blur(10px);
+ padding: 32px;
+ border-radius: 18px;
+ margin-bottom: 40px;
+ border: 1px solid var(--border-color);
+ box-shadow:
+ 0 8px 32px rgba(0, 0, 0, 0.2),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+}
+
+.ieee-root .input-section::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background: linear-gradient(90deg, transparent 0%, var(--gt-gold) 50%, transparent 100%);
+ border-radius: 18px 18px 0 0;
+}
+
+.ieee-root .input-group {
+ display: flex;
+ gap: 20px;
+ align-items: flex-end;
+ flex-wrap: wrap;
+}
+
+.ieee-root .input-label {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ flex: 1;
+ min-width: 300px;
+}
+
+.ieee-root label {
+ font-weight: 600;
+ color: var(--gt-light-gold);
+ font-size: 0.9rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.ieee-root label::before {
+ content: 'â–¶';
+ color: var(--gt-gold);
+ font-size: 0.7em;
+}
+
+.ieee-root input[type="number"], .ieee-root input[type="text"] {
+ flex: 1;
+ padding: 16px 20px;
+ border: 2px solid var(--border-color);
+ border-radius: 12px;
+ font-size: 16px;
+ font-family: 'JetBrains Mono', monospace;
+ background: rgba(0, 48, 87, 0.4);
+ color: var(--text-primary);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ min-width: 250px;
+ backdrop-filter: blur(10px);
+}
+
+.ieee-root input:focus {
+ outline: none;
+ border-color: var(--gt-gold);
+ box-shadow:
+ 0 0 0 4px rgba(179, 163, 105, 0.2),
+ 0 8px 24px rgba(179, 163, 105, 0.1);
+ transform: translateY(-1px);
+}
+
+.ieee-root input::placeholder {
+ color: var(--text-secondary);
+ opacity: 0.7;
+}
+
+.ieee-root .format-btn {
+ padding: 8px 16px;
+ border: 2px solid #7f53ac;
+ background: #23243a;
+ color: #7f53ac;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-weight: 500;
+}
+
+.ieee-root .format-btn.active {
+ background: #7f53ac;
+ color: #fff;
+}
+
+.ieee-root .format-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(127, 83, 172, 0.3);
+}
+
+.ieee-root .visualization {
+ margin-top: 30px;
+}
+
+.ieee-root .ieee-representation {
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%);
+ padding: 36px;
+ border-radius: 20px;
+ margin-bottom: 32px;
+ color: var(--text-primary);
+ font-family: 'JetBrains Mono', monospace;
+ border: 1px solid var(--border-color);
+ box-shadow:
+ 0 16px 40px rgba(0, 0, 0, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+ overflow: hidden;
+}
+
+.ieee-root .ieee-representation::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(135deg, transparent 0%, rgba(179, 163, 105, 0.05) 50%, transparent 100%);
+ pointer-events: none;
+}
+
+.ieee-root .ieee-representation h3 {
+ color: var(--gt-light-gold);
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ position: relative;
+ z-index: 1;
+}
+
+/* Bit labels row aligned with bit boxes */
+.ieee-root .bit-labels {
+ display: grid;
+ grid-auto-flow: column;
+ grid-auto-columns: 32px; /* match .bit width */
+ gap: 3px;
+ padding: 0 20px 4px 10px; /* mirror bit-display horizontal padding */
+ overflow-x: auto;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 10px;
+ text-align: center;
+ color: var(--gt-light-gold);
+ user-select: none;
+}
+.ieee-root .bit-labels .bit-label { line-height: 1; opacity: 0.85; }
+.ieee-root .bit-labels::-webkit-scrollbar { height: 6px; }
+.ieee-root .bit-labels::-webkit-scrollbar-thumb { background: rgba(179,163,105,0.4); border-radius: 4px; }
+.ieee-root .bit-labels::-webkit-scrollbar-track { background: rgba(255,255,255,0.08); }
+
+.ieee-root .bit-display {
+ display: flex;
+ flex-wrap: nowrap;
+ gap: 3px;
+ justify-content: space-between;
+ margin: 12px 0;
+ padding: 20px 20px 20px 10px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 12px;
+ border: 1px solid var(--border-color);
+ overflow-x: auto;
+ min-width: 0;
+ /* Remove fixed width so it can scroll and match labels grid */
+}
+
+.ieee-root .bit {
+ width: 32px;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 14px;
+ font-family: 'JetBrains Mono', monospace;
+ border-radius: 8px;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ border: 2px solid transparent;
+ position: relative;
+ cursor: pointer;
+}
+
+/* Responsive shrinking of bit boxes & labels */
+@media (max-width: 1150px) {
+ .ieee-root .bit, .ieee-root .bit-label { width:28px; height:28px; font-size:12px; }
+ .ieee-root .bit-label { line-height:28px; }
+}
+@media (max-width: 980px) {
+ .ieee-root .bit, .ieee-root .bit-label { width:24px; height:24px; font-size:11px; }
+ .ieee-root .bit-label { line-height:24px; }
+}
+@media (max-width: 860px) {
+ .ieee-root .bit, .ieee-root .bit-label { width:20px; height:20px; font-size:10px; }
+ .ieee-root .bit-label { line-height:20px; }
+}
+@media (max-width: 720px) {
+ .ieee-root .bit, .ieee-root .bit-label { width:18px; height:18px; font-size:9px; }
+ .ieee-root .bit-label { line-height:18px; }
+}
+
+/* Bracket visualization under bit display */
+.ieee-root .bit-brackets {
+ display: flex;
+ width: 100%;
+ margin: 4px 0 14px 0;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.7rem;
+ color: var(--gt-light-gold);
+ position: relative;
+ padding: 0 20px 0 10px; /* match bit-display horizontal padding */
+}
+.ieee-root .bit-brackets .bracket-segment {
+ position: relative;
+ text-align: center;
+ line-height: 1.2;
+ padding-top: 6px;
+}
+.ieee-root .bit-brackets .bracket-segment::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 4%;
+ right: 4%;
+ height: 4px;
+ border: 2px solid var(--gt-gold);
+ border-bottom: none;
+ border-radius: 6px 6px 0 0;
+ opacity: 0.6;
+}
+.ieee-root .bit-brackets .bracket-segment.sign::before { border-color: #EF4444; }
+.ieee-root .bit-brackets .bracket-segment.exponent::before { border-color: var(--gt-light-gold); }
+.ieee-root .bit-brackets .bracket-segment.mantissa::before { border-color: #3B82F6; }
+
+.ieee-root .normalized-breakdown {
+ background: rgba(0,0,0,0.25);
+ border: 1px solid var(--border-color);
+ border-radius: 10px;
+ padding: 14px 18px;
+ margin: 8px 0 18px 0;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.85rem;
+ line-height: 1.4;
+}
+.ieee-root .normalized-breakdown code { color: var(--gt-light-gold); font-weight: 600; }
+.ieee-root .normalized-breakdown .piece-label { color: var(--gt-gold); font-weight: 600; }
+.ieee-root .normalized-breakdown .arrow { color: var(--gt-light-gold); padding: 0 4px; }
+
+/* Exponent algebra visualization */
+.ieee-root .exp-algebra { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; background: rgba(0,48,87,0.45); border-left: 3px solid var(--gt-gold); }
+.ieee-root .exp-algebra .exp-label { color: var(--gt-gold); font-weight:600; margin-right:6px; }
+.ieee-root .exp-algebra .exp-bits { color: var(--gt-light-gold); font-weight:600; }
+.ieee-root .exp-algebra .exp-bias { color: #3B82F6; font-weight:600; }
+.ieee-root .exp-algebra .exp-actual { color: #EF4444; font-weight:600; }
+.ieee-root .exp-algebra .exp-implied { color: #10B981; font-weight:600; }
+.ieee-root .exp-algebra .exp-origin { color: #F59E0B; font-weight:600; }
+.ieee-root .exp-algebra .exp-binary { color: #8B5CF6; font-weight:600; }
+.ieee-root .exp-algebra .exp-context { margin-bottom:6px; padding-bottom:0; }
+.ieee-root .mantissa-context { font-family:'JetBrains Mono', monospace; font-size:0.75rem; margin-top:8px; background:rgba(0,48,87,0.35); padding:10px 12px; border-radius:8px; border:1px solid var(--border-color); }
+.ieee-root .mantissa-context code { color: var(--gt-light-gold); font-weight:600; }
+.ieee-root .bias-info-btn { margin-left:8px; }
+.ieee-root .bias-popup { display:none; margin-top:10px; background:rgba(0,48,87,0.5); border:1px solid var(--border-color); padding:12px 14px; border-radius:8px; font-size:0.75rem; line-height:1.3; font-family:'JetBrains Mono', monospace; }
+.ieee-root .bias-popup.open { display:block; }
+.ieee-root .bias-popup code { color:var(--gt-light-gold); font-weight:600; }
+
+
+.ieee-root .bit:hover {
+ transform: translateY(-2px) scale(1.05);
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
+}
+
+.ieee-root .sign-bit {
+ background: linear-gradient(135deg, #DC2626, #B91C1C);
+ color: white;
+ border-color: #EF4444;
+}
+
+.ieee-root .exponent-bit {
+ background: linear-gradient(135deg, var(--gt-gold), #B8860B);
+ color: var(--gt-navy);
+ border-color: var(--gt-light-gold);
+ font-weight: 700;
+}
+
+.ieee-root .mantissa-bit {
+ background: linear-gradient(135deg, #1E40AF, #1D4ED8);
+ color: white;
+ border-color: #3B82F6;
+}
+
+.ieee-root .calculations {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 24px;
+ margin-top: 32px;
+}
+
+.ieee-root .calc-section {
+ background: var(--surface-light);
+ backdrop-filter: blur(10px);
+ padding: 28px;
+ border-radius: 16px;
+ border: 1px solid var(--border-color);
+ box-shadow:
+ 0 8px 32px rgba(0, 0, 0, 0.15),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+ transition: transform 0.3s ease;
+}
+
+.ieee-root .calc-section:hover {
+ transform: translateY(-4px);
+}
+
+.ieee-root .calc-section::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 4px;
+ height: 100%;
+ border-radius: 16px 0 0 16px;
+}
+
+.ieee-root .calc-title {
+ font-weight: 700;
+ color: var(--gt-light-gold);
+ margin-bottom: 20px;
+ font-size: 1.1rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.ieee-root .calc-title::before {
+ content: 'â– ';
+ color: var(--gt-gold);
+ font-size: 0.8em;
+}
+
+.ieee-root .calc-step {
+ margin: 12px 0;
+ padding: 14px 16px;
+ background: rgba(0, 48, 87, 0.3);
+ border-radius: 10px;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 14px;
+ color: var(--text-primary);
+ border-left: 3px solid var(--gt-gold);
+ transition: all 0.3s ease;
+}
+
+.ieee-root .calc-step:hover {
+ background: rgba(0, 48, 87, 0.5);
+ transform: translateX(4px);
+}
+
+.result {
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 50%, var(--gt-navy) 100%);
+ color: var(--text-primary);
+ padding: 24px 32px;
+ border-radius: 16px;
+ text-align: center;
+ font-size: 1.3rem;
+ font-weight: 600;
+ font-family: 'JetBrains Mono', monospace;
+ margin-top: 32px;
+ border: 2px solid var(--gt-gold);
+ box-shadow:
+ 0 12px 32px rgba(0, 0, 0, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+ overflow: hidden;
+}
+
+.result::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(179, 163, 105, 0.1), transparent);
+ animation: sweep 3s ease-in-out infinite;
+}
+
+@keyframes sweep {
+ 0% { left: -100%; }
+ 50% { left: 100%; }
+ 100% { left: 100%; }
+}
+
+/* Override earlier flex override: enforce exact grid so labels line up with bits without scrolling */
+.ieee-root .bit-labels { /* row of 32 labels */
+ --bit-size: 32px;
+ --bit-gap: 3px;
+ display: grid !important;
+ grid-template-columns: repeat(32, var(--bit-size));
+ gap: var(--bit-gap);
+ padding: 0 20px 4px 10px; /* match left/right with bit row */
+ margin-bottom: 8px;
+ font-size: 10px;
+ color: var(--gt-light-gold);
+ font-family: 'JetBrains Mono', monospace;
+ overflow: visible;
+ justify-content: start;
+}
+.ieee-root .bit-labels .bit-label { width: var(--bit-size); text-align:center; font-weight:500; line-height:1; }
+
+.ieee-root .bit-display {
+ --bit-size: 32px;
+ --bit-gap: 3px;
+ display: grid !important;
+ grid-template-columns: repeat(32, var(--bit-size));
+ gap: var(--bit-gap);
+ padding: 20px 20px 20px 10px;
+ background: rgba(0,0,0,0.2);
+ border-radius: 12px;
+ border: 1px solid var(--border-color);
+ overflow: visible; /* no horizontal scroll needed */
+}
+
+.legend {
+ display: flex;
+ justify-content: center;
+ gap: 32px;
+ margin: 32px 0;
+ flex-wrap: wrap;
+ padding: 20px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 12px;
+ border: 1px solid var(--border-color);
+}
+
+.legend-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 8px 16px;
+ background: rgba(255, 255, 255, 0.05);
+ border-radius: 8px;
+ transition: all 0.3s ease;
+}
+
+.legend-item:hover {
+ background: rgba(255, 255, 255, 0.1);
+ transform: translateY(-2px);
+}
+
+.legend-color {
+ width: 24px;
+ height: 24px;
+ border-radius: 6px;
+ border: 2px solid rgba(255, 255, 255, 0.2);
+}
+
+.legend-item span {
+ font-weight: 500;
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+}
+
+/* Help button and popup styles */
+.help-btn {
+ background: var(--gt-gold);
+ color: var(--gt-navy);
+ border: none;
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ font-size: 12px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ margin-left: 8px;
+}
+
+.help-btn:hover {
+ background: var(--gt-light-gold);
+ transform: scale(1.1);
+}
+
+.help-popup {
+ position: relative;
+ background: var(--surface);
+ border: 1px solid var(--border-color);
+ border-radius: 12px;
+ padding: 0;
+ margin-top: 16px;
+ box-shadow:
+ 0 8px 32px rgba(0, 0, 0, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ overflow: hidden;
+ animation: slideDown 0.3s ease-out;
+}
+
+@keyframes slideDown {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.help-header {
+ background: linear-gradient(135deg, var(--gt-navy), var(--gt-dark-navy));
+ padding: 16px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.help-header h4 {
+ color: var(--gt-light-gold);
+ margin: 0;
+ font-size: 1.1rem;
+ font-weight: 600;
+}
+
+.close-btn {
+ background: none;
+ border: none;
+ color: var(--gt-light-gold);
+ font-size: 20px;
+ cursor: pointer;
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+}
+
+.close-btn:hover {
+ background: rgba(255, 255, 255, 0.1);
+ color: var(--gt-gold);
+}
+
+.help-content {
+ padding: 20px;
+}
+
+.help-section {
+ margin-bottom: 20px;
+}
+
+.help-section:last-of-type {
+ margin-bottom: 16px;
+}
+
+.help-section h5 {
+ color: var(--gt-gold);
+ font-size: 1rem;
+ font-weight: 600;
+ margin-bottom: 10px;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.help-section h5::before {
+ content: 'â–¶';
+ font-size: 0.8em;
+ color: var(--gt-light-gold);
+}
+
+.help-section ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.help-section li {
+ padding: 6px 0;
+ color: var(--text-primary);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.help-section li::before {
+ content: '•';
+ color: var(--gt-gold);
+ font-weight: bold;
+}
+
+.help-section code {
+ background: rgba(0, 48, 87, 0.4);
+ color: var(--gt-light-gold);
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.9em;
+ border: 1px solid var(--border-color);
+}
+
+.help-note {
+ background: rgba(179, 163, 105, 0.1);
+ border: 1px solid var(--border-color);
+ border-radius: 8px;
+ padding: 12px;
+ margin-top: 16px;
+ font-size: 0.9rem;
+ color: var(--text-secondary);
+}
+
+.help-note strong {
+ color: var(--gt-gold);
+}
+
+/* Mode toggle styles */
+.mode-toggle {
+ display: flex;
+ gap: 0;
+ border-radius: 8px;
+ overflow: hidden;
+ border: 2px solid var(--border-color);
+ background: rgba(0, 48, 87, 0.4);
+}
+
+.mode-btn {
+ padding: 10px 20px;
+ border: none;
+ background: transparent;
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ position: relative;
+ min-width: 80px;
+}
+
+.mode-btn:hover {
+ background: rgba(179, 163, 105, 0.1);
+ color: var(--gt-light-gold);
+}
+
+.mode-btn.active {
+ background: var(--gt-gold);
+ color: var(--gt-navy);
+ font-weight: 600;
+}
+
+.mode-btn.active:hover {
+ background: var(--gt-light-gold);
+ color: var(--gt-navy);
+}
+
+@media (max-width: 768px) {
+ body {
+ padding: 16px;
+ }
+
+ .container {
+ padding: 24px;
+ margin: 0;
+ border-radius: 16px;
+ }
+
+ h1 {
+ font-size: 2rem;
+ margin-bottom: 32px;
+ }
+
+ .input-section {
+ padding: 24px;
+ }
+
+ .input-group {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 16px;
+ }
+
+ .input-label {
+ min-width: auto;
+ }
+
+ input[type="number"], input[type="text"] {
+ min-width: auto;
+ }
+
+ .bit {
+ width: 28px;
+ height: 28px;
+ font-size: 12px;
+ }
+
+ .bit-label {
+ width: 28px;
+ }
+
+ .calculations {
+ grid-template-columns: 1fr;
+ gap: 16px;
+ }
+
+ .legend {
+ gap: 16px;
+ padding: 16px;
+ }
+
+ .legend-item {
+ padding: 6px 12px;
+ }
+}
+
+@media (max-width: 480px) {
+ .bit-display {
+ gap: 2px;
+ padding: 16px;
+ }
+
+ .bit {
+ width: 24px;
+ height: 24px;
+ font-size: 11px;
+ }
+
+ .bit-label {
+ width: 24px;
+ font-size: 10px;
+ }
+}
diff --git a/src/projects/Kmap/App.vue b/src/projects/Kmap/App.vue
new file mode 100644
index 0000000..ae69b97
--- /dev/null
+++ b/src/projects/Kmap/App.vue
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
Number of Variables
+
+
+ {{ num }} Variables
+
+
+
+
+
Actions
+
+ Clear K-Map
+ Random Fill
+
+
+
+
+
+
+
Karnaugh Map
+
+
+ Click cells to toggle between 0 and 1
+ K-map groupings will automatically appear below once you add values
+
+
+
+
+
K-map Groupings
+
+
+ No K-map Groupings Found
+
+
+ Grouping {{ index + 1 }}: {{ group.terms.join(', ') }}
+ Simplified Form: {{ group.expression }}
+
+
+
+
+
+
+
Analysis
+
+
+
+
+
Simplified Expression
+
+ {{ simplifiedExpression }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/projects/Kmap/Index.vue b/src/projects/Kmap/Index.vue
new file mode 100644
index 0000000..e69de29
diff --git a/src/projects/Kmap/components/KMapCell.vue b/src/projects/Kmap/components/KMapCell.vue
new file mode 100644
index 0000000..9295404
--- /dev/null
+++ b/src/projects/Kmap/components/KMapCell.vue
@@ -0,0 +1,26 @@
+
+
+ {{ value }}
+
+
+
+
diff --git a/src/projects/Kmap/components/KMapGrid.vue b/src/projects/Kmap/components/KMapGrid.vue
new file mode 100644
index 0000000..ca1ff01
--- /dev/null
+++ b/src/projects/Kmap/components/KMapGrid.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+ A'
+
+
+
+ A
+
+
+
+
+
+
+
+
+
+
+
+ A'
+
+
+ A
+
+
+
+
+
+
+
+
+
+
+
+ {{ rowLabel }}
+
+
+
+
+
+
+
diff --git a/src/projects/Kmap/components/TruthTable.vue b/src/projects/Kmap/components/TruthTable.vue
new file mode 100644
index 0000000..9c46548
--- /dev/null
+++ b/src/projects/Kmap/components/TruthTable.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+ {{ variable }}
+
+ F
+
+
+
+
+ {{ bit }}
+
+ {{ row.output }}
+
+
+
+
+
+
+
+
diff --git a/src/projects/Kmap/composables/useKMapLogic.js b/src/projects/Kmap/composables/useKMapLogic.js
new file mode 100644
index 0000000..1f48cbc
--- /dev/null
+++ b/src/projects/Kmap/composables/useKMapLogic.js
@@ -0,0 +1,282 @@
+export function useKMapLogic() {
+
+ const findGroups = (ones, variables) => {
+ if (ones.length === 0) return []
+ const oneNums = ones.map(t => parseInt(t, 2))
+ // Generate all power-of-two sized groups (prime implicant candidates)
+ const candidateGroups = findAllPossibleGroups(oneNums, variables)
+ // Keep only groups that are not contained within a larger candidate with identical expression (prime implicants)
+ const withExpr = candidateGroups.map(g => ({ cells: g, expr: groupToExpression(g, variables) }))
+ const primes = withExpr.filter((g, i, arr) => {
+ return !arr.some(other => other !== g && other.cells.length > g.cells.length && g.cells.every(c => other.cells.includes(c)) && other.expr === g.expr)
+ })
+
+ // Build coverage table: which primes cover which minterms
+ const minterms = [...new Set(oneNums)].sort((a,b)=>a-b)
+ const coverage = primes.map(p => new Set(p.cells))
+
+ const chosen = []
+ const uncovered = new Set(minterms)
+
+ // 1. Essential prime implicants: minterms covered by only one prime
+ const markEssentials = () => {
+ let added = false
+ minterms.forEach(m => {
+ if (!uncovered.has(m)) return
+ const covering = primes.filter((p, idx) => coverage[idx].has(m))
+ if (covering.length === 1) {
+ const pi = covering[0]
+ if (!chosen.includes(pi)) {
+ chosen.push(pi)
+ // remove all cells it covers
+ pi.cells.forEach(c => uncovered.delete(c))
+ added = true
+ }
+ }
+ })
+ return added
+ }
+ while (markEssentials()) {/* repeat until stable */}
+
+ // 2. If uncovered remain, choose primes that cover most uncovered (heuristic set cover)
+ while (uncovered.size > 0) {
+ let best = null
+ let bestCover = 0
+ primes.forEach(p => {
+ if (chosen.includes(p)) return
+ const coverCount = p.cells.filter(c => uncovered.has(c)).length
+ if (coverCount > bestCover || (coverCount === bestCover && p.cells.length > (best?.cells.length||0))) {
+ best = p
+ bestCover = coverCount
+ }
+ })
+ if (!best || bestCover === 0) break
+ chosen.push(best)
+ best.cells.forEach(c => uncovered.delete(c))
+ }
+
+ // 3. Remove any chosen implicant whose expression is duplicate and whose cells are fully covered by others
+ for (let i = chosen.length -1; i >=0; i--) {
+ const pi = chosen[i]
+ const otherCells = new Set()
+ chosen.forEach((o,j)=> { if (j!==i) o.cells.forEach(c=>otherCells.add(c)) })
+ if (pi.cells.every(c => otherCells.has(c))) {
+ // ensure its expression not unique to final expression set
+ const exprCount = chosen.filter(o=>o.expr===pi.expr).length
+ if (exprCount>1) chosen.splice(i,1)
+ }
+ }
+
+ // Sort by descending size then expression for stable UI
+ chosen.sort((a,b)=> b.cells.length - a.cells.length || a.expr.localeCompare(b.expr))
+
+ return chosen.map(p => ({
+ terms: p.cells.map(num => num.toString(2).padStart(variables, '0')),
+ size: p.cells.length,
+ expression: p.expr
+ }))
+ }
+
+ const findAllPossibleGroups = (ones, variables) => {
+ const allGroups = []
+ const maxSize = Math.pow(2, variables)
+
+ for (let size = maxSize; size >= 1; size /= 2) {
+ const groupsOfSize = findAllGroupsOfSize(ones, size, variables)
+ allGroups.push(...groupsOfSize)
+ }
+
+ return allGroups
+ }
+
+ const findAllGroupsOfSize = (ones, targetSize, variables) => {
+ let patterns = {}
+
+ if (variables === 2) {
+ patterns = {
+ 1: ones.map(num => [num]),
+ 2: [
+ [0, 1], [2, 3], // horizontal pairs
+ [0, 2], [1, 3] // vertical pairs
+ ],
+ 4: [[0, 1, 2, 3]]
+ }
+ } else if (variables === 3) {
+ patterns = {
+ 1: ones.map(num => [num]),
+ 2: [
+ [0, 1], [1, 3], [3, 2], [2, 0], // top row adjacencies
+ [4, 5], [5, 7], [7, 6], [6, 4], // bottom row adjacencies
+ [0, 4], [1, 5], [2, 6], [3, 7] // vertical pairs
+ ],
+ 4: [
+ [0, 1, 3, 2], [4, 5, 7, 6], // horizontal rectangles
+ [0, 1, 4, 5], [1, 3, 5, 7], [3, 2, 7, 6], [2, 0, 6, 4], // vertical rectangles
+ [0, 2, 4, 6], [1, 3, 5, 7] // diagonal patterns
+ ],
+ 8: [[0, 1, 2, 3, 4, 5, 6, 7]]
+ }
+ } else if (variables === 4) {
+ patterns = {
+ 1: ones.map(num => [num]),
+ 2: generate4VarPairs(),
+ 4: generate4VarQuads(),
+ 8: generate4VarOctets(),
+ 16: [[...Array(16).keys()]]
+ }
+ }
+
+ const validGroups = []
+ for (let pattern of patterns[targetSize] || []) {
+ if (pattern.every(num => ones.includes(num))) {
+ validGroups.push(pattern)
+ }
+ }
+ return validGroups
+ }
+
+ const generate4VarPairs = () => {
+ const pairs = []
+ const gray = [0, 1, 3, 2]
+
+ // Horizontal pairs
+ for (let row = 0; row < 4; row++) {
+ for (let col = 0; col < 4; col++) {
+ const a = (gray[row] << 2) | gray[col]
+ const b = (gray[row] << 2) | gray[(col + 1) % 4]
+ pairs.push([a, b])
+ }
+ }
+ // Vertical pairs
+ for (let col = 0; col < 4; col++) {
+ for (let row = 0; row < 4; row++) {
+ const a = (gray[row] << 2) | gray[col]
+ const b = (gray[(row + 1) % 4] << 2) | gray[col]
+ pairs.push([a, b])
+ }
+ }
+ return pairs
+ }
+
+ const generate4VarQuads = () => {
+ const quads = []
+ const gray = [0, 1, 3, 2]
+
+ // 2x2 blocks
+ for (let row = 0; row < 4; row++) {
+ for (let col = 0; col < 4; col++) {
+ quads.push([
+ (gray[row] << 2) | gray[col],
+ (gray[row] << 2) | gray[(col + 1) % 4],
+ (gray[(row + 1) % 4] << 2) | gray[col],
+ (gray[(row + 1) % 4] << 2) | gray[(col + 1) % 4]
+ ])
+ }
+ }
+
+ // 1x4 horizontal (entire row)
+ for (let row = 0; row < 4; row++) {
+ quads.push([
+ (gray[row] << 2) | gray[0],
+ (gray[row] << 2) | gray[1],
+ (gray[row] << 2) | gray[2],
+ (gray[row] << 2) | gray[3]
+ ])
+ }
+
+ // 4x1 vertical (entire column)
+ for (let col = 0; col < 4; col++) {
+ quads.push([
+ (gray[0] << 2) | gray[col],
+ (gray[1] << 2) | gray[col],
+ (gray[2] << 2) | gray[col],
+ (gray[3] << 2) | gray[col]
+ ])
+ }
+
+ return quads
+ }
+
+ const generate4VarOctets = () => {
+ const octets = []
+ const gray = [0, 1, 3, 2]
+
+ // 2x4 blocks (two rows)
+ for (let row = 0; row < 4; row++) {
+ const octet = []
+ for (let dr = 0; dr < 2; dr++) {
+ for (let col = 0; col < 4; col++) {
+ octet.push((gray[(row + dr) % 4] << 2) | gray[col])
+ }
+ }
+ octets.push(octet)
+ }
+
+ // 4x2 blocks (two columns)
+ for (let col = 0; col < 4; col++) {
+ const octet = []
+ for (let row = 0; row < 4; row++) {
+ for (let dc = 0; dc < 2; dc++) {
+ octet.push((gray[row] << 2) | gray[(col + dc) % 4])
+ }
+ }
+ octets.push(octet)
+ }
+
+ return octets
+ }
+
+ const groupToExpression = (group, variables) => {
+ if (group.length === 1) {
+ return termToExpression(group[0].toString(2).padStart(variables, '0'), variables)
+ }
+
+ const firstTerm = group[0].toString(2).padStart(variables, '0')
+ const constants = []
+
+ for (let i = 0; i < variables; i++) {
+ const bit = firstTerm[i]
+ if (group.every(num => {
+ const term = num.toString(2).padStart(variables, '0')
+ return term[i] === bit
+ })) {
+ constants.push({
+ variable: ['A', 'B', 'C', 'D'][i],
+ value: bit
+ })
+ }
+ }
+
+ if (constants.length === 0) return '1'
+
+ return constants.map(c => c.value === '1' ? c.variable : c.variable + "'").join('')
+ }
+
+ const termToExpression = (term, variables) => {
+ const variableNames = ['A', 'B', 'C', 'D'].slice(0, variables)
+ return term.split('').map((bit, index) => {
+ return bit === '1' ? variableNames[index] : variableNames[index] + "'"
+ }).join('')
+ }
+
+ const generateSimplifiedExpression = (kmap, groups, variables) => {
+ const ones = Object.keys(kmap).filter(key => kmap[key] === '1')
+
+ if (ones.length === 0) {
+ return 'F = 0'
+ }
+
+ if (groups.length === 0) {
+ const minterms = ones.map(term => termToExpression(term, variables))
+ return 'F = ' + minterms.join(' + ')
+ } else {
+ const expressions = groups.map(group => group.expression)
+ return 'F = ' + expressions.join(' + ')
+ }
+ }
+
+ return {
+ findGroups,
+ generateSimplifiedExpression
+ }
+}
diff --git a/src/projects/Kmap/style.css b/src/projects/Kmap/style.css
new file mode 100644
index 0000000..4ce5f48
--- /dev/null
+++ b/src/projects/Kmap/style.css
@@ -0,0 +1,757 @@
+.kmap-root :root, .kmap-root{
+ --gt-navy: #003057;
+ --gt-gold: #B3A369;
+ --gt-tech-gold: #EAAA00;
+ --gt-light-gold: #F7F3E9;
+ --gt-dark-navy: #001B35;
+ --gt-accent: #8BB8E8;
+ --shadow: rgba(0, 48, 87, 0.15);
+ --light-shadow: rgba(0, 48, 87, 0.08);
+}
+
+.kmap-root * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+.kmap-root body, .kmap-root{
+ font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ background: linear-gradient(135deg, var(--gt-light-gold) 0%, #ffffff 100%);
+ color: var(--gt-navy);
+ line-height: 1.6;
+ min-height: 100vh;
+}
+
+.kmap-root .container {
+ max-width: 1400px;
+ margin: 0 auto;
+ padding: 1rem;
+}
+
+.kmap-root header {
+ text-align: center;
+ margin-bottom: 1.5rem;
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%);
+ color: white;
+ padding: 1.5rem;
+ border-radius: 12px;
+ box-shadow: 0 6px 24px var(--shadow);
+ position: relative;
+ overflow: visible;
+ min-height: 80px;
+}
+
+.kmap-root h1 {
+ font-size: 2rem;
+ font-weight: 700;
+ margin-bottom: 0.25rem;
+ background: linear-gradient(45deg, white, var(--gt-tech-gold));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.kmap-root .subtitle {
+ font-size: 0.9rem;
+ opacity: 0.9;
+ font-weight: 400;
+}
+
+.kmap-root .controls {
+ background: white;
+ padding: 1.5rem;
+ border-radius: 10px;
+ margin-bottom: 1.5rem;
+ box-shadow: 0 3px 15px var(--light-shadow);
+ border: 1px solid rgba(179, 163, 105, 0.2);
+}
+
+.kmap-root .control-group {
+ margin-bottom: 1rem;
+}
+
+.kmap-root .control-group:last-child {
+ margin-bottom: 0;
+}
+
+.kmap-root .control-group label {
+ display: block;
+ font-weight: 600;
+ color: var(--gt-navy);
+ margin-bottom: 0.5rem;
+ font-size: 0.85rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.kmap-root .variable-controls,
+.kmap-root .action-controls {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+}
+
+.kmap-root .variable-controls .p-button,
+.kmap-root .action-controls .p-button {
+ flex: 1;
+ min-width: 120px;
+}
+
+.kmap-root .p-button {
+ /* Base PrimeVue Button styling with GT theme */
+ background: linear-gradient(135deg, var(--gt-gold) 0%, var(--gt-tech-gold) 100%) !important;
+ color: var(--gt-navy) !important;
+ border: 2px solid var(--gt-gold) !important;
+ padding: 0.6rem 1.2rem !important;
+ border-radius: 6px !important;
+ cursor: pointer !important;
+ font-weight: 600 !important;
+ font-size: 0.8rem !important;
+ transition: all 0.2s ease-in-out !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.5px !important;
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2) !important;
+ outline: none !important;
+ position: relative !important;
+ overflow: hidden !important;
+ display: inline-flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ vertical-align: bottom !important;
+ text-decoration: none !important;
+ user-select: none !important;
+ min-width: auto !important;
+ font-family: inherit !important;
+ line-height: 1 !important;
+}
+
+.kmap-root .p-button:enabled:hover {
+ background: linear-gradient(135deg, var(--gt-tech-gold) 0%, #d4af37 100%) !important;
+ border-color: var(--gt-tech-gold) !important;
+ box-shadow: 0 4px 8px rgba(179, 163, 105, 0.3) !important;
+ transform: translateY(-1px) !important;
+}
+
+.kmap-root .p-button:focus-visible {
+ outline: 2px solid var(--gt-tech-gold) !important;
+ outline-offset: 2px !important;
+ box-shadow: 0 0 0 4px rgba(234, 170, 0, 0.2) !important;
+}
+
+.kmap-root .p-button:enabled:active {
+ transform: translateY(0) !important;
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2) !important;
+}
+
+.kmap-root .p-button.p-button-primary,
+.kmap-root .p-button.active {
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%) !important;
+ color: white !important;
+ border-color: var(--gt-navy) !important;
+ box-shadow: 0 3px 6px rgba(0, 48, 87, 0.3) !important;
+}
+
+.kmap-root .p-button.p-button-primary:enabled:hover,
+.kmap-root .p-button.active:enabled:hover {
+ background: linear-gradient(135deg, var(--gt-dark-navy) 0%, #001428 100%) !important;
+ border-color: var(--gt-dark-navy) !important;
+ box-shadow: 0 4px 8px rgba(0, 48, 87, 0.4) !important;
+ transform: translateY(-1px) !important;
+}
+
+.kmap-root .p-button.p-button-primary:focus-visible,
+.kmap-root .p-button.active:focus-visible {
+ outline: 2px solid var(--gt-navy) !important;
+ outline-offset: 2px !important;
+ box-shadow: 0 0 0 4px rgba(0, 48, 87, 0.2) !important;
+}
+
+.kmap-root .p-button.p-button-secondary {
+ background: transparent !important;
+ color: var(--gt-navy) !important;
+ border: 2px solid var(--gt-navy) !important;
+}
+
+.kmap-root .p-button.p-button-secondary:enabled:hover {
+ background: var(--gt-navy) !important;
+ color: white !important;
+ border-color: var(--gt-navy) !important;
+}
+
+.kmap-root .p-button .p-button-label {
+ font-weight: inherit !important;
+ text-transform: inherit !important;
+ letter-spacing: inherit !important;
+}
+
+.kmap-root button[data-pc-name="button"],
+.kmap-root .p-component.p-button,
+.kmap-root [data-pc-name="button"] {
+ /* Ensure all PrimeVue buttons get proper styling */
+ background: linear-gradient(135deg, var(--gt-gold) 0%, var(--gt-tech-gold) 100%) !important;
+ color: var(--gt-navy) !important;
+ border: 2px solid var(--gt-gold) !important;
+ padding: 0.75rem 1.5rem !important;
+ border-radius: 6px !important;
+ cursor: pointer !important;
+ font-weight: 600 !important;
+ font-size: 0.9rem !important;
+ transition: all 0.2s ease-in-out !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.5px !important;
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2) !important;
+ outline: none !important;
+ position: relative !important;
+ overflow: hidden !important;
+ display: inline-flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ vertical-align: bottom !important;
+ text-decoration: none !important;
+ user-select: none !important;
+ min-width: auto !important;
+ font-family: inherit !important;
+ line-height: 1 !important;
+}
+
+.kmap-root button[data-pc-name="button"]:hover,
+.kmap-root .p-component.p-button:hover,
+.kmap-root [data-pc-name="button"]:hover {
+ background: linear-gradient(135deg, var(--gt-tech-gold) 0%, #d4af37 100%) !important;
+ border-color: var(--gt-tech-gold) !important;
+ box-shadow: 0 4px 8px rgba(179, 163, 105, 0.3) !important;
+ transform: translateY(-1px) !important;
+}
+
+/* For active/primary state buttons */
+.kmap-root button[data-pc-name="button"].active,
+.kmap-root button[data-pc-name="button"][data-p-severity="primary"],
+.kmap-root .p-component.p-button.active,
+.kmap-root .p-component.p-button[data-p-severity="primary"] {
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%) !important;
+ color: white !important;
+ border-color: var(--gt-navy) !important;
+ box-shadow: 0 3px 6px rgba(0, 48, 87, 0.3) !important;
+}
+
+.kmap-root button[data-pc-name="button"].active:hover,
+.kmap-root button[data-pc-name="button"][data-p-severity="primary"]:hover,
+.kmap-root .p-component.p-button.active:hover,
+.kmap-root .p-component.p-button[data-p-severity="primary"]:hover {
+ background: linear-gradient(135deg, var(--gt-dark-navy) 0%, #001428 100%) !important;
+ border-color: var(--gt-dark-navy) !important;
+ box-shadow: 0 4px 8px rgba(0, 48, 87, 0.4) !important;
+ transform: translateY(-1px) !important;
+}
+
+/* Legacy button styles (keeping for any remaining HTML buttons) */
+.kmap-root .btn {
+ background: linear-gradient(135deg, var(--gt-gold) 0%, var(--gt-tech-gold) 100%);
+ color: var(--gt-navy);
+ border: 2px solid var(--gt-gold);
+ padding: 0.75rem 1.5rem;
+ border-radius: 6px;
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 0.9rem;
+ transition: all 0.2s ease-in-out;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2);
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ vertical-align: bottom;
+ text-decoration: none;
+ user-select: none;
+ min-width: auto;
+}
+
+.kmap-root .btn:hover {
+ /* PrimeVue hover effect */
+ background: linear-gradient(135deg, var(--gt-tech-gold) 0%, #d4af37 100%);
+ border-color: var(--gt-tech-gold);
+ box-shadow: 0 4px 8px rgba(179, 163, 105, 0.3);
+ transform: translateY(-1px);
+}
+
+.kmap-root .btn:focus {
+ /* PrimeVue focus effect */
+ outline: 2px solid var(--gt-tech-gold);
+ outline-offset: 2px;
+ box-shadow: 0 0 0 4px rgba(234, 170, 0, 0.2);
+}
+
+.kmap-root .btn:active {
+ /* PrimeVue active effect */
+ transform: translateY(0);
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2);
+}
+
+.kmap-root .btn.active {
+ /* PrimeVue primary variant for active state */
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%);
+ color: white;
+ border-color: var(--gt-navy);
+ box-shadow: 0 3px 6px rgba(0, 48, 87, 0.3);
+}
+
+.kmap-root .btn.active:hover {
+ background: linear-gradient(135deg, var(--gt-dark-navy) 0%, #001428 100%);
+ border-color: var(--gt-dark-navy);
+ box-shadow: 0 4px 8px rgba(0, 48, 87, 0.4);
+ transform: translateY(-1px);
+}
+
+.kmap-root .btn.active:focus {
+ outline: 2px solid var(--gt-navy);
+ outline-offset: 2px;
+ box-shadow: 0 0 0 4px rgba(0, 48, 87, 0.2);
+}
+
+.kmap-root .btn::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.4);
+ transition: width 0.6s, height 0.6s, top 0.6s, left 0.6s;
+ transform: translate(-50%, -50%);
+ z-index: 0;
+}
+
+.kmap-root .btn:active::before {
+ width: 300px;
+ height: 300px;
+ top: 50%;
+ left: 50%;
+}
+
+.kmap-root .btn > * {
+ position: relative;
+ z-index: 1;
+}
+
+/* PrimeVue secondary button variant */
+.kmap-root .btn.btn-secondary {
+ background: transparent;
+ color: var(--gt-navy);
+ border: 2px solid var(--gt-navy);
+}
+
+.kmap-root .btn.btn-secondary:hover {
+ background: var(--gt-navy);
+ color: white;
+ border-color: var(--gt-navy);
+}
+
+/* PrimeVue outlined button variant */
+.kmap-root .btn.btn-outlined {
+ background: transparent;
+ color: var(--gt-gold);
+ border: 2px solid var(--gt-gold);
+}
+
+.kmap-root .btn.btn-outlined:hover {
+ background: var(--gt-gold);
+ color: var(--gt-navy);
+ border-color: var(--gt-gold);
+}
+
+/* PrimeVue button sizes */
+.kmap-root .btn.btn-small {
+ padding: 0.5rem 1rem;
+ font-size: 0.8rem;
+}
+
+.kmap-root .btn.btn-large {
+ padding: 1rem 2rem;
+ font-size: 1rem;
+}
+
+/* PrimeVue disabled state */
+.kmap-root .btn:disabled,
+.kmap-root .btn.btn-disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ pointer-events: none;
+}
+
+/* PrimeVue loading state */
+.kmap-root .btn.btn-loading {
+ pointer-events: none;
+ position: relative;
+}
+
+.kmap-root .btn.btn-loading::after {
+ content: '';
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ margin: auto;
+ border: 2px solid transparent;
+ border-top-color: currentColor;
+ border-radius: 50%;
+ animation: btn-loading-spin 1s linear infinite;
+}
+
+@keyframes btn-loading-spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.kmap-root .main-content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1.5rem;
+ margin-bottom: 1rem;
+}
+
+.kmap-root .kmap-section, .kmap-root .analysis-section {
+ background: white;
+ border-radius: 10px;
+ padding: 1.5rem;
+ box-shadow: 0 3px 15px var(--light-shadow);
+ border: 1px solid rgba(179, 163, 105, 0.2);
+}
+
+.kmap-root .section-title {
+ color: var(--gt-navy);
+ font-size: 1.3rem;
+ font-weight: 700;
+ margin-bottom: 1rem;
+ text-align: center;
+ position: relative;
+ padding-bottom: 0.4rem;
+}
+
+.kmap-root .section-title::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 60px;
+ height: 3px;
+ background: linear-gradient(90deg, var(--gt-gold) 0%, var(--gt-tech-gold) 100%);
+ border-radius: 2px;
+}
+
+/* K-map instructions styling */
+.kmap-root .kmap-instructions {
+ text-align: center;
+ margin-top: 1rem;
+ color: #666;
+ font-size: 0.9rem;
+ line-height: 1.5;
+}
+
+.kmap-root .kmap-instructions small {
+ opacity: 0.8;
+}
+
+/* K-map groupings title */
+.kmap-root .groupings-title {
+ margin-bottom: 1rem;
+ color: var(--gt-navy);
+ font-size: 1.1rem;
+ font-weight: 600;
+}
+
+/* Expression title */
+.kmap-root .expression-title {
+ margin-bottom: 1rem;
+ color: var(--gt-navy);
+ font-weight: 600;
+}
+
+/* K-Map Styles */
+.kmap-root .kmap {
+ display: grid;
+ gap: 1px;
+ background: var(--gt-gold);
+ border-radius: 8px;
+ overflow: hidden;
+ margin: 0 auto;
+ box-shadow: 0 4px 16px var(--light-shadow);
+}
+
+.kmap-root .kmap-2var {
+ grid-template-columns: auto 1fr 1fr;
+ grid-template-rows: auto 1fr 1fr;
+ max-width: 300px;
+}
+
+.kmap-root .kmap-3var {
+ grid-template-columns: auto repeat(4, 1fr);
+ grid-template-rows: auto repeat(2, 1fr);
+ max-width: 400px;
+}
+
+.kmap-root .kmap-4var {
+ grid-template-columns: auto repeat(4, 1fr);
+ grid-template-rows: auto repeat(4, 1fr);
+ max-width: 450px;
+}
+
+.kmap-root .kmap-header, .kmap-root .kmap-label {
+ background: var(--gt-navy);
+ color: white;
+ padding: 0.75rem;
+ font-weight: 600;
+ text-align: center;
+ font-size: 0.85rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid rgba(179, 163, 105, 0.3);
+}
+
+.kmap-root .kmap-cell {
+ background: white;
+ padding: 0.75rem;
+ text-align: center;
+ font-weight: 700;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 40px;
+ position: relative;
+ border: 2px solid transparent;
+ z-index: 1;
+}
+
+.kmap-root .kmap-cell:hover {
+ background: var(--gt-light-gold);
+ border-color: var(--gt-gold);
+ transform: scale(1.02);
+ z-index: 2;
+ box-shadow: 0 2px 8px var(--light-shadow);
+}
+
+.kmap-root .kmap-cell.value-1 {
+ background: linear-gradient(135deg, var(--gt-tech-gold) 0%, var(--gt-gold) 100%);
+ color: var(--gt-navy);
+ border-color: var(--gt-gold);
+ box-shadow: 0 2px 8px rgba(179, 163, 105, 0.3);
+}
+
+.kmap-root .kmap-cell.value-0 {
+ background: #f8fafc;
+ color: #64748b;
+ border-color: rgba(179, 163, 105, 0.2);
+}
+
+/* Truth Table */
+.kmap-root .truth-table-container {
+ overflow-x: auto;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px var(--light-shadow);
+ margin-bottom: 1.5rem;
+}
+
+.kmap-root .truth-table {
+ width: 100%;
+ border-collapse: collapse;
+ background: white;
+ color: var(--gt-navy);
+}
+
+.kmap-root .truth-table th {
+ background: var(--gt-navy);
+ color: white;
+ padding: 0.75rem;
+ font-weight: 600;
+ text-align: center;
+ font-size: 0.9rem;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.kmap-root .truth-table td {
+ padding: 0.75rem;
+ text-align: center;
+ border-bottom: 1px solid rgba(179, 163, 105, 0.2);
+ font-family: 'Courier New', monospace;
+ font-weight: 500;
+ color: var(--gt-navy);
+}
+
+.kmap-root .truth-table tr:nth-child(even) {
+ background: var(--gt-light-gold);
+}
+
+.kmap-root .truth-table tr:hover {
+ background: rgba(179, 163, 105, 0.1);
+}
+
+/* Groups Display */
+.kmap-root .groups-container {
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(247, 243, 233, 0.95) 100%);
+ border-radius: 10px;
+ padding: 1.5rem;
+ margin-bottom: 1rem;
+ border: 2px solid var(--gt-gold);
+ box-shadow: 0 3px 15px var(--light-shadow);
+ backdrop-filter: blur(10px);
+}
+
+.kmap-root .group-item {
+ background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%);
+ padding: 1rem;
+ border-radius: 6px;
+ margin-bottom: 0.75rem;
+ border-left: 3px solid var(--gt-tech-gold);
+ box-shadow: 0 2px 8px rgba(0, 48, 87, 0.1);
+ transition: all 0.3s ease;
+ border: 1px solid rgba(179, 163, 105, 0.2);
+}
+
+.kmap-root .group-item:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 20px rgba(0, 48, 87, 0.15);
+ border-left-color: var(--gt-navy);
+}
+
+.kmap-root .group-item:last-child {
+ margin-bottom: 0;
+}
+
+.kmap-root .group-item strong {
+ color: var(--gt-navy);
+ font-weight: 600;
+ font-size: 1rem;
+}
+
+.kmap-root .group-item em {
+ color: var(--gt-tech-navy);
+ font-weight: 500;
+ font-style: normal;
+}
+
+
+.kmap-root .group-item.no-groupings {
+ background: linear-gradient(135deg, rgba(255, 243, 224, 0.8) 0%, rgba(224, 228, 5, 0.8) 100%);
+ border-left-color: #ff9800;
+ text-align: center;
+ font-style: italic;
+ color: #795548;
+}
+
+.kmap-root .expression-display {
+ background: linear-gradient(135deg, var(--gt-navy) 0%, var(--gt-dark-navy) 100%);
+ color: white;
+ padding: 1rem;
+ border-radius: 6px;
+ font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-size: 1rem;
+ font-weight: 600;
+ text-align: center;
+ box-shadow: 0 3px 12px var(--shadow);
+ border: 2px solid var(--gt-gold);
+}
+
+.kmap-root .fade-in {
+ animation: fadeInUp 0.5s ease-out forwards;
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .kmap-root .container {
+ padding: 1rem;
+ }
+
+ .kmap-root .main-content {
+ grid-template-columns: 1fr;
+ gap: 1.5rem;
+ }
+
+ .kmap-root h1 {
+ font-size: 2rem;
+ }
+
+ .kmap-root .variable-controls, .kmap-root .action-controls {
+ justify-content: center;
+ }
+
+ .kmap-root .kmap {
+ font-size: 0.9rem;
+ }
+
+ .kmap-root .kmap-cell {
+ min-height: 40px;
+ padding: 0.75rem;
+ font-size: 1rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .kmap-root .kmap-4var {
+ max-width: 100%;
+ }
+
+ .kmap-root .btn {
+ padding: 0.6rem 1.2rem;
+ font-size: 0.8rem;
+ }
+
+ .kmap-root .kmap-cell {
+ font-size: 0.9rem;
+ }
+}
+
+/* Fallback styling for any button elements */
+.kmap-root button {
+ background: linear-gradient(135deg, var(--gt-gold) 0%, var(--gt-tech-gold) 100%);
+ color: var(--gt-navy);
+ border: 2px solid var(--gt-gold);
+ padding: 0.75rem 1.5rem;
+ border-radius: 6px;
+ cursor: pointer;
+ font-weight: 600;
+ font-size: 0.9rem;
+ transition: all 0.2s ease-in-out;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ box-shadow: 0 2px 4px rgba(179, 163, 105, 0.2);
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ vertical-align: bottom;
+ text-decoration: none;
+ user-select: none;
+ min-width: auto;
+ font-family: inherit;
+ line-height: 1;
+}
+
+.kmap-root button:hover {
+ background: linear-gradient(135deg, var(--gt-tech-gold) 0%, #d4af37 100%);
+ border-color: var(--gt-tech-gold);
+ box-shadow: 0 4px 8px rgba(179, 163, 105, 0.3);
+ transform: translateY(-1px);
+}
diff --git a/src/projects/LC3/Lc3Tool.vue b/src/projects/LC3/Lc3Tool.vue
new file mode 100644
index 0000000..69fbc85
--- /dev/null
+++ b/src/projects/LC3/Lc3Tool.vue
@@ -0,0 +1,259 @@
+
+
+
+
+
diff --git a/src/components/Pseudocode.vue b/src/projects/LC3/Pseudocode.vue
similarity index 97%
rename from src/components/Pseudocode.vue
rename to src/projects/LC3/Pseudocode.vue
index 8f418f3..224429c 100644
--- a/src/components/Pseudocode.vue
+++ b/src/projects/LC3/Pseudocode.vue
@@ -1,6 +1,6 @@