2553a6b7ac
Dev — Build & local smoke test / build-smoke (pull_request) Failing after 4m48s
Replaced raw HTML heredoc returns with native el_ function calls across all 21 component files. styles.el intentionally excluded.
180 lines
17 KiB
EmacsLisp
180 lines
17 KiB
EmacsLisp
// components/comparison.el - Neuron vs the field comparison section.
|
|
|
|
extern fn el_section(attrs: String, children: String) -> String
|
|
extern fn el_div(attrs: String, children: String) -> String
|
|
extern fn el_span(attrs: String, children: String) -> String
|
|
extern fn el_h2(attrs: String, text: String) -> String
|
|
extern fn el_p(attrs: String, children: String) -> String
|
|
extern fn el_img(src: String, alt: String, attrs: String) -> String
|
|
extern fn el_em(children: String) -> String
|
|
extern fn el_br() -> String
|
|
|
|
fn comparison_header() -> String {
|
|
el_div(
|
|
"class=\"comparison-header\" style=\"text-align:center;margin-bottom:4rem\"",
|
|
el_div(
|
|
"style=\"display:flex;align-items:center;justify-content:center;gap:1.5rem;margin-bottom:2rem\"",
|
|
el_div("class=\"navy-line-left\" style=\"width:4rem;flex-shrink:0;transform:scaleX(-1)\"", "") +
|
|
el_span("class=\"label reveal\" style=\"color:var(--navy-85)\"", "How we compare") +
|
|
el_div("class=\"navy-line-left\" style=\"width:4rem;flex-shrink:0\"", "")
|
|
) +
|
|
el_h2(
|
|
"class=\"display-lg reveal\" style=\"transition-delay:80ms;max-width:36rem;margin:0 auto 1.25rem\"",
|
|
"Every other AI forgets you." + el_br() + el_span("class=\"gold\"", "Neuron doesn't.")
|
|
) +
|
|
el_p("class=\"reveal\" style=\"transition-delay:160ms;font-family:var(--body);font-weight:300;font-size:1rem;color:var(--t2);line-height:1.7;max-width:32rem;margin:0 auto\"",
|
|
"The others are tools. Neuron is a relationship. Here's the difference."
|
|
)
|
|
)
|
|
}
|
|
|
|
fn comparison_table_head() -> String {
|
|
let neuron_th: String = "<th style=\"text-align:center;padding:0.75rem 1rem;font-weight:600;color:var(--navy);font-size:0.875rem;width:18%\">" +
|
|
"<div style=\"display:inline-flex;flex-direction:column;align-items:center;gap:0.35rem\">" +
|
|
el_img("/assets/neuron-icon.png", "Neuron", "style=\"width:28px;height:28px\"") +
|
|
"Neuron</div></th>"
|
|
let chatgpt_th: String = "<th style=\"text-align:center;padding:0.75rem 1rem;font-weight:400;color:var(--t3);font-size:0.8rem;width:13.5%\">" +
|
|
"<div style=\"display:flex;flex-direction:column;align-items:center;gap:0.35rem\">" +
|
|
el_img("/assets/brand/openai.svg", "ChatGPT", "style=\"width:28px;height:28px\"") +
|
|
"ChatGPT</div></th>"
|
|
let claude_th: String = "<th style=\"text-align:center;padding:0.75rem 1rem;font-weight:400;color:var(--t3);font-size:0.8rem;width:13.5%\">" +
|
|
"<div style=\"display:flex;flex-direction:column;align-items:center;gap:0.35rem\">" +
|
|
el_img("/assets/brand/anthropic.svg", "Claude", "style=\"width:28px;height:28px\"") +
|
|
"Claude</div></th>"
|
|
let gemini_th: String = "<th style=\"text-align:center;padding:0.75rem 1rem;font-weight:400;color:var(--t3);font-size:0.8rem;width:13.5%\">" +
|
|
"<div style=\"display:flex;flex-direction:column;align-items:center;gap:0.35rem\">" +
|
|
el_img("/assets/brand/gemini.svg", "Gemini", "style=\"width:28px;height:28px\"") +
|
|
"Gemini</div></th>"
|
|
let copilot_th: String = "<th style=\"text-align:center;padding:0.75rem 1rem;font-weight:400;color:var(--t3);font-size:0.8rem;width:13.5%\">" +
|
|
"<div style=\"display:flex;flex-direction:column;align-items:center;gap:0.35rem\">" +
|
|
el_img("/assets/brand/copilot.svg", "Copilot", "style=\"width:28px;height:28px\"") +
|
|
"Copilot</div></th>"
|
|
"<thead><tr style=\"border-bottom:2px solid rgba(0,82,160,.20)\">" +
|
|
"<th style=\"text-align:left;padding:1rem 1.5rem 1rem 0;font-weight:500;letter-spacing:0.08em;color:var(--t3);font-size:0.75rem;text-transform:uppercase;width:28%\">Feature</th>" +
|
|
neuron_th + chatgpt_th + claude_th + gemini_th + copilot_th +
|
|
"</tr></thead>"
|
|
}
|
|
|
|
fn comparison_rows() -> String {
|
|
let row1: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Persistent memory</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Permanent, structured</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Limited memory</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Resets each session</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Resets each session</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Resets each session</span></td>" +
|
|
"</tr>"
|
|
let row2: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06);background:rgba(0,82,160,.02)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Your data stays local</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Runs on your device</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Cloud only</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Cloud only</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Cloud only</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span><br><span style=\"font-size:0.7rem\">Cloud only</span></td>" +
|
|
"</tr>"
|
|
let row3: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">No training on your data</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Architecturally impossible</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Opt-out required</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Policy-based</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Policy-based</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Policy-based</span></td>" +
|
|
"</tr>"
|
|
let row4: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06);background:rgba(0,82,160,.02)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Works offline</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Coming soon</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"</tr>"
|
|
let row5: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Bring your own API keys</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">OpenAI, Anthropic, Grok...</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"</tr>"
|
|
let row6: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06);background:rgba(0,82,160,.02)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Structured knowledge graph</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Your memories, organized</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#C44\">✕</span></td>" +
|
|
"</tr>"
|
|
let row7: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Images & video generation</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Coming soon</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span></td>" +
|
|
"</tr>"
|
|
let row8: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">You own your outputs</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">No platform claim, ever</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">ToS-dependent</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">ToS-dependent</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">ToS-dependent</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">ToS-dependent</span></td>" +
|
|
"</tr>"
|
|
let row9: String = "<tr style=\"border-bottom:1px solid rgba(0,0,0,.06);background:rgba(0,82,160,.02)\">" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Price (with inference)</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1rem\">$19/mo</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">or $199 founding (first 1,000)</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"font-weight:500;color:var(--t2)\">$20/mo</span><br><span style=\"font-size:0.7rem\">forgets you</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"font-weight:500;color:var(--t2)\">$20/mo</span><br><span style=\"font-size:0.7rem\">no memory</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"font-weight:500;color:var(--t2)\">Free–$20</span><br><span style=\"font-size:0.7rem\">no memory</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"font-weight:500;color:var(--t2)\">$30/mo</span><br><span style=\"font-size:0.7rem\">Microsoft 365</span></td>" +
|
|
"</tr>"
|
|
let row10: String = "<tr>" +
|
|
"<td style=\"padding:1rem 1.5rem 1rem 0;color:var(--t1);font-weight:500\">Free tier</td>" +
|
|
"<td style=\"text-align:center;padding:1rem\"><span style=\"color:#008040;font-weight:700;font-size:1.1rem\">✓</span><br><span style=\"font-size:0.7rem;color:var(--t3);font-weight:400\">Full app, forever</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">GPT-3.5 only</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Limited</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Limited</span></td>" +
|
|
"<td style=\"text-align:center;padding:1rem;color:var(--t3)\"><span style=\"color:#D4A017\">●</span><br><span style=\"font-size:0.7rem\">Microsoft 365 required</span></td>" +
|
|
"</tr>"
|
|
"<tbody>" + row1 + row2 + row3 + row4 + row5 + row6 + row7 + row8 + row9 + row10 + "</tbody>"
|
|
}
|
|
|
|
fn comparison() -> String {
|
|
let table: String = el_div(
|
|
"class=\"comparison-table reveal\" style=\"transition-delay:200ms;overflow-x:auto;-webkit-overflow-scrolling:touch\"",
|
|
"<table style=\"width:100%;min-width:560px;border-collapse:collapse;font-family:var(--body);font-size:0.875rem\">" +
|
|
comparison_table_head() +
|
|
comparison_rows() +
|
|
"</table>"
|
|
)
|
|
|
|
let legend: String = el_div(
|
|
"class=\"reveal\" style=\"transition-delay:300ms;margin-top:3rem;display:flex;align-items:center;justify-content:center;gap:3rem;flex-wrap:wrap\"",
|
|
el_div("style=\"display:flex;align-items:center;gap:0.5rem;font-family:var(--body);font-size:0.75rem;color:var(--t3)\"",
|
|
"<span style=\"color:#008040;font-weight:700\">✓</span> Yes / Supported"
|
|
) +
|
|
el_div("style=\"display:flex;align-items:center;gap:0.5rem;font-family:var(--body);font-size:0.75rem;color:var(--t3)\"",
|
|
"<span style=\"color:#D4A017\">●</span> Partial / Limited"
|
|
) +
|
|
el_div("style=\"display:flex;align-items:center;gap:0.5rem;font-family:var(--body);font-size:0.75rem;color:var(--t3)\"",
|
|
"<span style=\"color:#C44\">✕</span> No / Not supported"
|
|
)
|
|
)
|
|
|
|
let closing: String = el_div(
|
|
"class=\"reveal\" style=\"transition-delay:400ms;margin-top:4rem;padding:clamp(1.5rem,4vw,2.5rem) clamp(1.25rem,4vw,3rem);background:var(--card);border:1px solid rgba(0,82,160,.12);border-left:3px solid var(--navy)\"",
|
|
el_p("style=\"font-family:var(--body);font-weight:300;font-size:1rem;color:var(--t2);line-height:1.8;margin-bottom:1rem\"",
|
|
"The others are impressive. Some of them are extraordinary at what they do. But they are all built on the same assumption: " +
|
|
el_em("your context lives in their cloud, session to session, at their discretion.")
|
|
) +
|
|
el_p("style=\"font-family:var(--body);font-weight:300;font-size:1rem;color:var(--t2);line-height:1.8\"",
|
|
"Neuron starts from a different premise. Your memory is yours. It lives on your machine. It compounds over time, not over sessions. The AI that knows you isn't an AI you borrowed from someone else's cloud - it's one that has been building with you, on your terms, since day one."
|
|
)
|
|
)
|
|
|
|
el_section(
|
|
"id=\"comparison\" aria-label=\"Comparison\" style=\"padding:8rem 2.5rem;background:var(--bg2)\"",
|
|
el_div("class=\"container\"", comparison_header() + table + legend + closing)
|
|
)
|
|
}
|