Skip to main content

logicaffeine_web/ui/pages/landing/
content.rs

1//! What the front page says, as data.
2//!
3//! The heading, the line on how for each system, the prompt for each system, the guide the prompt
4//! sends an agent to (served at /agent.txt), the Studio frame's shelf, the comparison, what comes with
5//! LOGOS and the FAQ live here rather than in the markup, so they read and review in one place and
6//! every line that states a fact about LOGOS carries the suites that prove it. `landing_page` in logicaffeine_tests holds every suite to existing, every command in the guide
7//! to the released largo and to this tree's, every address to a file or page the site serves, and the
8//! page to showing exactly the text the copy button copies.
9
10use std::sync::LazyLock;
11
12use crate::ui::pages::contact::claims::learn_figures;
13use crate::ui::pages::contact::content::{free_answer, ASSISTANT_GUIDE_URL, INSTALL_UNIX, INSTALL_WINDOWS, SOURCE_URL};
14use crate::ui::pages::studio_workbench::Shelf;
15use crate::ui::router::studio_file_url;
16
17/// How largo installs: the shell script on macOS, Linux and every phone's agent, PowerShell on Windows.
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum Install {
20    Unix,
21    Windows,
22}
23
24impl Install {
25    pub const ALL: &'static [Install] = &[Install::Unix, Install::Windows];
26
27    /// The name the page marks its prompts and `<html data-os>` with, and remembers.
28    pub fn name(self) -> &'static str {
29        match self {
30            Install::Unix => "unix",
31            Install::Windows => "windows",
32        }
33    }
34
35    pub fn from_name(name: &str) -> Option<Install> {
36        Install::ALL.iter().copied().find(|install| install.name() == name)
37    }
38
39    /// The switch's offer under this install's prompt: the other system.
40    pub fn switch_label(self) -> &'static str {
41        match self {
42            Install::Unix => "Using Windows?",
43            Install::Windows => "Using macOS or Linux?",
44        }
45    }
46
47    /// The other install, which the switch shows.
48    pub fn other(self) -> Install {
49        match self {
50            Install::Unix => Install::Windows,
51            Install::Windows => Install::Unix,
52        }
53    }
54}
55
56/// The guide the prompt sends an agent to before it writes: the instructions, served whole
57/// (`public/agent.txt`, which `landing_page` holds to [`instructions_text`] byte for byte).
58pub const AGENT_GUIDE_URL: &str = "https://logicaffeine.com/agent.txt";
59
60/// Where `largo serve` puts the site: its default port, on the reader's own machine.
61pub const SERVE_URL: &str = "http://localhost:8080";
62
63/// The page that lists the crates the language is built from, one per part.
64pub const CRATES_URL: &str = "https://logicaffeine.com/crates";
65
66/// The language on one page: the forms an agent writes, one construct a line, drawn from the
67/// quickguide's tables (`teach_parity` holds the guide to the lessons, `doc_examples` runs the docs).
68/// The guide carries it under step 4, and the heal worker's prompt carries the same lines
69/// (`services/heal/src/primer.js`, held equal by `landing_page`), so the model that mends a program
70/// knows the language it mends (the user, 2026-11-02).
71pub const SYNTAX_MATRIX: &[&str] = &[
72    "The language on one page. Every statement is one English sentence.",
73    "Blocks: ## Main is the program. ## To add (a: Int, b: Int) -> Int: is a function.",
74    "## A Point has: with An x: Int. below is a struct. ## A Shape is one of: is an enum.",
75    "## Page /path is a web page. ## Route GET /api/x -> Seq of Todo: is an API route.",
76    "## Test: name is a test of a page. ## Theorem: name is a theorem for the prover.",
77    "Bind: Let x be 5. Let mutable n be 0. Let x: Int be 5. Change: Set n to n + 1.",
78    "Also: Increase n by 1. Decrease n by 1. Set p's x to 5. Set item i of xs to v.",
79    "Types: Int, Float, Text, Bool, Seq of Int, Map of Text to Int, Set of Int, some 30, none.",
80    "Make: a new Seq of Int, [1, 2, 3], a new Map of Text to Int, {1, 2, 3}, a new Point.",
81    "Read: item 1 of xs is the first item, length of xs, xs contains v, p's x, p.x.",
82    "Slice: items 2 through 4 of xs. Change a list or set: Push v to xs. Pop from xs into y.",
83    "Add v to s. Remove v from s. Arithmetic: x + y, x - y, x * y, x / y, x % y.",
84    "Text: \"Hi, {name}!\" fills the hole with name, a combined with b joins two Texts.",
85    "Compare: is equal to or ==, is not or !=, is less than or <, is greater than or >.",
86    "Also: is at most or <=, is at least or >=, is between lo and hi, is divisible by n.",
87    "Logic in a test: and, or, not. Choose: If c: then Otherwise If d: then Otherwise:.",
88    "A block is the lines indented four spaces under the colon.",
89    "Repeat: While c:, Repeat for x in xs:, Repeat for i from 1 to n:, Break.",
90    "Match: Inspect t: then When V (a): and Otherwise:. Options: some 30, none.",
91    "Filter: Let small be every n in xs where n is less than 4.",
92    "In place: Remove every t from todos where t's done.",
93    "Call: add(3, 7), or xs.f(a) for f(xs, a). A closure: (x: Int) -> x + 1. Return x.",
94    "Show x. prints x. Contracts: Let x: Int where x > 0 be 5. Assert that x is equal to 42.",
95    "Check that b is at least a. stops the program when it is not.",
96    "Time: 500ms, 2s, 5min, 1h, 2026-05-20, 9am, 2 weeks, 2026-05-20 at 4pm.",
97    "A page: State: holds Let draft be \"\". Actions: holds To add: and its steps.",
98    "View: is HTML. {draft} is a hole, on-click={add}, bind={draft}, {if c:}...{else:}...{end}.",
99    "Lists in a View: {for each t in todos, keyed by t's id:}...{end}. Style: is CSS, scoped.",
100    "Derived state: Let left always be length of todos. It recomputes after every turn.",
101    "A page test: Click \"#add\". Expect that the text of \"#n\" is equal to \"1\".",
102    "Logic mode: one sentence per line. Every dog barks. Some cat sleeps. No cat barks.",
103    "A theorem: Given: Every man is mortal. Given: Socrates is a man. Prove: He is mortal.",
104    "Then Proof: Auto. and the kernel certifies it.",
105];
106
107/// The command that clones the source, with its examples and docs, for an agent to read.
108pub const CLONE_SOURCE: &str = "git clone https://github.com/Brahmastra-Labs/logicaffeine";
109
110/// The five lines a person pastes into their coding agent, for `install`: what this is, the source on
111/// GitHub first, the install that runs on the reader's system, and the guide to follow, which ends
112/// with a site running. Plain and agent agnostic (Tristen and the user, 2026-11-01, DAT-105).
113pub fn prompt(install: Install) -> &'static [Line] {
114    static PROMPTS: LazyLock<[Vec<Line>; 2]> = LazyLock::new(|| [Install::Unix, Install::Windows].map(prompt_lines));
115    &PROMPTS[install as usize]
116}
117
118fn prompt_lines(install: Install) -> Vec<Line> {
119    use Line::*;
120    let (how, command) = match install {
121        Install::Unix => ("Install largo, the LOGOS command line tool, easy to install and lightweight:", INSTALL_UNIX),
122        Install::Windows => ("Install largo, the LOGOS command line tool, easy to install, lightweight, in PowerShell:", INSTALL_WINDOWS),
123    };
124    vec![
125        Say(agreed("LOGOS programmer instructions, for any coding agent (bring your own).")),
126        Say(agreed(format!("Source, examples and docs: {SOURCE_URL}"))),
127        Say(agreed(how)),
128        Run(command),
129        Say(agreed(format!("Then follow {AGENT_GUIDE_URL}, every step. It ends with a site running."))),
130    ]
131}
132
133/// The prompt as one text: what the page shows and what the copy button copies.
134pub fn prompt_text(install: Install) -> &'static str {
135    static TEXTS: LazyLock<[String; 2]> =
136        LazyLock::new(|| [Install::Unix, Install::Windows].map(|install| prompt(install).iter().map(Line::text).collect::<Vec<_>>().join("\n")));
137    &TEXTS[install as usize]
138}
139
140/// The one line below the heading on how to use LOGOS: the whole of what the page tells a reader to
141/// do, since the prompt itself only copies (the user, 2026-10-31).
142pub fn how() -> &'static Claim {
143    static HOW: LazyLock<Claim> = LazyLock::new(|| {
144        proven("Copy the prompt for your system into your coding agent. It installs largo and puts a LOGOS website on your screen.", &["landing_page", "llms_lock"])
145    });
146    &HOW
147}
148
149/// A system a reader copies the prompt for: one button each, with the system's mark. macOS and
150/// Linux share the shell install; Windows has PowerShell's.
151#[derive(Clone, Copy, Debug, PartialEq, Eq)]
152pub enum System {
153    MacOs,
154    Linux,
155    Windows,
156}
157
158impl System {
159    pub const ALL: [System; 3] = [System::MacOs, System::Linux, System::Windows];
160
161    pub fn name(self) -> &'static str {
162        match self {
163            System::MacOs => "macOS",
164            System::Linux => "Linux",
165            System::Windows => "Windows",
166        }
167    }
168
169    /// The name the page marks the button with.
170    pub fn slug(self) -> &'static str {
171        match self {
172            System::MacOs => "macos",
173            System::Linux => "linux",
174            System::Windows => "windows",
175        }
176    }
177
178    /// The prompt the button copies: the install that runs on the system.
179    pub fn install(self) -> Install {
180        match self {
181            System::Windows => Install::Windows,
182            System::MacOs | System::Linux => Install::Unix,
183        }
184    }
185
186    /// The button's words.
187    pub fn copy_label(self) -> String {
188        format!("{COPY_LABEL} for {}", self.name())
189    }
190
191    /// The system's mark, as an SVG path on a 24-unit square (Apple's and Ubuntu's from Simple Icons,
192    /// CC0; Windows's four panes drawn here).
193    pub fn mark(self) -> &'static str {
194        match self {
195            System::MacOs => APPLE_MARK,
196            System::Linux => UBUNTU_MARK,
197            System::Windows => WINDOWS_MARK,
198        }
199    }
200}
201
202const APPLE_MARK: &str = "M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701";
203const UBUNTU_MARK: &str = "M17.61.455a3.41 3.41 0 0 0-3.41 3.41 3.41 3.41 0 0 0 3.41 3.41 3.41 3.41 0 0 0 3.41-3.41 3.41 3.41 0 0 0-3.41-3.41zM12.92.8C8.923.777 5.137 2.941 3.148 6.451a4.5 4.5 0 0 1 .26-.007 4.92 4.92 0 0 1 2.585.737A8.316 8.316 0 0 1 12.688 3.6 4.944 4.944 0 0 1 13.723.834 11.008 11.008 0 0 0 12.92.8zm9.226 4.994a4.915 4.915 0 0 1-1.918 2.246 8.36 8.36 0 0 1-.273 8.303 4.89 4.89 0 0 1 1.632 2.54 11.156 11.156 0 0 0 .559-13.089zM3.41 7.932A3.41 3.41 0 0 0 0 11.342a3.41 3.41 0 0 0 3.41 3.409 3.41 3.41 0 0 0 3.41-3.41 3.41 3.41 0 0 0-3.41-3.41zm2.027 7.866a4.908 4.908 0 0 1-2.915.358 11.1 11.1 0 0 0 7.991 6.698 11.234 11.234 0 0 0 2.422.249 4.879 4.879 0 0 1-.999-2.85 8.484 8.484 0 0 1-.836-.136 8.304 8.304 0 0 1-5.663-4.32zm11.405.928a3.41 3.41 0 0 0-3.41 3.41 3.41 3.41 0 0 0 3.41 3.41 3.41 3.41 0 0 0 3.41-3.41 3.41 3.41 0 0 0-3.41-3.41z";
204const WINDOWS_MARK: &str = "M3 3h8.5v8.5H3zM12.5 3H21v8.5h-8.5zM3 12.5h8.5V21H3zM12.5 12.5H21V21h-8.5z";
205
206/// The box above the buttons for a reader who installs largo by hand: its heading and the command
207/// for each kind of system, as the pricing page states them.
208pub const INSTALL_HEADING: &str = "Install largo yourself";
209
210pub fn install_commands() -> [(&'static str, &'static str); 2] {
211    [("macOS and Linux", INSTALL_UNIX), ("Windows", INSTALL_WINDOWS)]
212}
213
214/// The heading: the promise, then the two things that come with it. The user's words (2026-10-01).
215pub const HEADING: [&str; 3] = ["Code we can all read.", "Logic and mathematics built in.", "Bring your own agent."];
216
217/// The button below the heading, which copies the instructions.
218pub const COPY_LABEL: &str = "Copy agent instructions";
219
220/// The element that shows the instructions, which the copy button names.
221pub const INSTRUCTIONS_ID: &str = "agent-instructions";
222
223/// What the page says only once the reader acts.
224pub mod said {
225    /// The copy button's label while the instructions are on the clipboard.
226    pub const COPIED: &str = "Copied";
227    /// What a screen reader hears once the instructions are copied.
228    pub const COPIED_STATUS: &str = "Copied the agent instructions.";
229    /// What the page says when the browser refuses the copy, having selected the instructions.
230    pub const COPY_REFUSED: &str = "This browser blocked copying. The instructions are selected, so press Ctrl+C or Command+C.";
231    /// An install command's copy button, while the command is on the clipboard.
232    pub const COMMAND_COPIED: &str = "Copied";
233
234    /// Every one of them, with where it shows.
235    pub fn all() -> Vec<(&'static str, &'static str)> {
236        vec![
237            ("the copy button once pressed", COPIED),
238            ("the copy status", COPIED_STATUS),
239            ("the copy status when the browser refuses", COPY_REFUSED),
240            ("an install command's copy button once pressed", COMMAND_COPIED),
241        ]
242    }
243}
244
245/// What backs a line of the page./// What backs a line of the page.
246pub enum Evidence {
247    /// The suites under `crates/logicaffeine_tests/tests/` that prove it.
248    Suites(&'static [&'static str]),
249    /// It states nothing a suite could prove: a label, a direction, how the pair works.
250    Agreement,
251}
252
253/// One sentence the page states, and what backs it.
254pub struct Claim {
255    pub text: String,
256    pub evidence: Evidence,
257}
258
259fn proven(text: impl Into<String>, suites: &'static [&'static str]) -> Claim {
260    Claim { text: text.into(), evidence: Evidence::Suites(suites) }
261}
262
263fn agreed(text: impl Into<String>) -> Claim {
264    Claim { text: text.into(), evidence: Evidence::Agreement }
265}
266
267/// One line of the agent instructions.
268pub enum Line {
269    /// A step's title, numbered.
270    Step(&'static str),
271    /// A sentence.
272    Say(Claim),
273    /// A rule of the language, in the list under step 2.
274    Rule(Claim),
275    /// How the pair works, in the list under the last step.
276    Agree(&'static str),
277    /// A command to type, on a line of its own.
278    Run(&'static str),
279    /// A page to open, on a line of its own.
280    Open(String),
281    Blank,
282}
283
284/// A command or an address sits four spaces in, where an agent and a person both read it as one to
285/// type or open.
286const INDENT: &str = "    ";
287
288impl Line {
289    /// The line as the copied text reads it.
290    pub fn text(&self) -> String {
291        match self {
292            Line::Step(title) => title.to_string(),
293            Line::Say(claim) => claim.text.clone(),
294            Line::Rule(claim) => format!("- {}", claim.text),
295            Line::Agree(text) => format!("- {text}"),
296            Line::Run(command) => format!("{INDENT}{command}"),
297            Line::Open(url) => format!("{INDENT}{url}"),
298            Line::Blank => String::new(),
299        }
300    }
301}
302
303/// The site's address for a shipped Studio example.
304fn studio_address(example: &str) -> String {
305    format!("https://logicaffeine.com{}", studio_file_url(example))
306}
307
308/// The guide the prompt sends an agent through: install, a website on the reader's screen inside
309/// a few minutes, then the language, the site, programs, logic, math and hardware, each where it
310/// lives in the released largo, and how the two of them work (Tristen, 2026-11-01, DAT-105: get
311/// them up, running and building, with a starter site, and point them at the source). Every command
312/// runs on the release the install script installs.
313pub fn instructions() -> &'static [Line] {
314    static LINES: LazyLock<Vec<Line>> = LazyLock::new(|| {
315        use Line::*;
316        vec![
317            Say(proven("LOGOS programmer instructions, for any coding agent (bring your own).", &["landing_page", "llms_lock"])),
318            Say(proven("LOGOS is the English programming language from logicaffeine.com.", &["doc_examples", "code_examples_all_tiers"])),
319            Say(proven("LOGOS is lightweight and modular, and largo, its command line tool, is easy to install.", &["installer_docs_lock", "landing_page"])),
320            Blank,
321            Step("1. Get the source"),
322            Say(agreed("Source, examples and docs are on GitHub. Clone it, and read it when a question comes up:")),
323            Run(CLONE_SOURCE),
324            Say(proven(format!("Its crates, one per part of the language, are listed at {CRATES_URL}."), &["crates_page_lock", "landing_page"])),
325            Blank,
326            Step("2. Install largo, the LOGOS command line tool"),
327            Say(agreed("On macOS and Linux:")),
328            Run(INSTALL_UNIX),
329            Say(agreed("On Windows, in PowerShell:")),
330            Run(INSTALL_WINDOWS),
331            Say(proven("If the shell can't find largo, open a new terminal or add its folder to PATH.", &["installer_docs_lock"])),
332            Say(agreed("Then check the install:")),
333            Run("largo --version"),
334            Run("largo doctor"),
335            Blank,
336            Step("3. Start a website"),
337            Run("largo new mysite --site"),
338            Run("cd mysite"),
339            Run("largo test"),
340            Run("largo serve"),
341            Say(proven("The front page is pages/app.lg: a counter with a button, written in English.", &["landing_page"])),
342            Say(proven("largo test ran the ## Test at the end of the page: it clicks the button and counts.", &["landing_page"])),
343            Say(proven("largo serve keeps running, so run it in a second terminal or in the background.", &["landing_page"])),
344            Say(proven(format!("The site is at {SERVE_URL}. Each save rebuilds the page and reloads it."), &["landing_page"])),
345            Say(agreed("Report that the site is up before changing anything.")),
346            Blank,
347            Step("4. Learn the language before you write it"),
348            Say(proven(format!("Read {ASSISTANT_GUIDE_URL}, every LOGOS guide in one file."), &["llms_lock"])),
349            Say(proven("largo new also wrote AGENTS.md in the project, the language taught to an agent. Read it.", &["landing_page"])),
350            Say(proven("Use a command only if largo --help lists it, and say so when one is missing.", &["landing_page"])),
351            Say(agreed("Four rules to start with:")),
352            Rule(proven("A statement is one English sentence, as in Let x be 5.", &["doc_examples", "landing_page"])),
353            Rule(proven("Let names a value and Set changes it, as in Set x to 6.", &["phase_interpret_mode", "landing_page"])),
354            Rule(proven("Lists count from 1: item 1 of xs is the first item.", &["phase22_index", "landing_page"])),
355            Rule(proven("Compare with is equal to, as in If name is equal to \"Ada\":", &["correctness_is_equality", "landing_page"])),
356            Blank,
357            Say(agreed("The language on one page:")),
358            Say(proven("Blocks: ## Main is the program. ## To add (a: Int, b: Int) -> Int: is a function.", &["teach_parity", "doc_examples"])),
359            Say(proven("## A Point has: with An x: Int. below is a struct. ## A Shape is one of: is an enum.", &["teach_parity", "doc_examples"])),
360            Say(proven("## Page /path is a web page. ## Route GET /api/x -> Seq of Todo: is an API route.", &["teach_parity", "doc_examples"])),
361            Say(proven("## Test: name is a test of a page. ## Theorem: name is a theorem for the prover.", &["teach_parity", "doc_examples"])),
362            Say(proven("Bind: Let x be 5. Let mutable n be 0. Let x: Int be 5. Change: Set n to n + 1.", &["teach_parity", "doc_examples"])),
363            Say(proven("Also: Increase n by 1. Decrease n by 1. Set p's x to 5. Set item i of xs to v.", &["teach_parity", "doc_examples"])),
364            Say(proven("Types: Int, Float, Text, Bool, Seq of Int, Map of Text to Int, Set of Int, some 30, none.", &["teach_parity", "doc_examples"])),
365            Say(proven("Make: a new Seq of Int, [1, 2, 3], a new Map of Text to Int, {1, 2, 3}, a new Point.", &["teach_parity", "doc_examples"])),
366            Say(proven("Read: item 1 of xs is the first item, length of xs, xs contains v, p's x, p.x.", &["teach_parity", "doc_examples"])),
367            Say(proven("Slice: items 2 through 4 of xs. Change a list or set: Push v to xs. Pop from xs into y.", &["teach_parity", "doc_examples"])),
368            Say(proven("Add v to s. Remove v from s. Arithmetic: x + y, x - y, x * y, x / y, x % y.", &["teach_parity", "doc_examples"])),
369            Say(proven("Text: \"Hi, {name}!\" fills the hole with name, a combined with b joins two Texts.", &["teach_parity", "doc_examples"])),
370            Say(proven("Compare: is equal to or ==, is not or !=, is less than or <, is greater than or >.", &["teach_parity", "doc_examples"])),
371            Say(proven("Also: is at most or <=, is at least or >=, is between lo and hi, is divisible by n.", &["teach_parity", "doc_examples"])),
372            Say(proven("Logic in a test: and, or, not. Choose: If c: then Otherwise If d: then Otherwise:.", &["teach_parity", "doc_examples"])),
373            Say(proven("A block is the lines indented four spaces under the colon.", &["teach_parity", "doc_examples"])),
374            Say(proven("Repeat: While c:, Repeat for x in xs:, Repeat for i from 1 to n:, Break.", &["teach_parity", "doc_examples"])),
375            Say(proven("Match: Inspect t: then When V (a): and Otherwise:. Options: some 30, none.", &["teach_parity", "doc_examples"])),
376            Say(proven("Filter: Let small be every n in xs where n is less than 4.", &["teach_parity", "doc_examples"])),
377            Say(proven("In place: Remove every t from todos where t's done.", &["teach_parity", "doc_examples"])),
378            Say(proven("Call: add(3, 7), or xs.f(a) for f(xs, a). A closure: (x: Int) -> x + 1. Return x.", &["teach_parity", "doc_examples"])),
379            Say(proven("Show x. prints x. Contracts: Let x: Int where x > 0 be 5. Assert that x is equal to 42.", &["teach_parity", "doc_examples"])),
380            Say(proven("Check that b is at least a. stops the program when it is not.", &["teach_parity", "doc_examples"])),
381            Say(proven("Time: 500ms, 2s, 5min, 1h, 2026-05-20, 9am, 2 weeks, 2026-05-20 at 4pm.", &["teach_parity", "doc_examples"])),
382            Say(proven("A page: State: holds Let draft be \"\". Actions: holds To add: and its steps.", &["teach_parity", "doc_examples"])),
383            Say(proven("View: is HTML. {draft} is a hole, on-click={add}, bind={draft}, {if c:}...{else:}...{end}.", &["teach_parity", "doc_examples"])),
384            Say(proven("Lists in a View: {for each t in todos, keyed by t's id:}...{end}. Style: is CSS, scoped.", &["teach_parity", "doc_examples"])),
385            Say(proven("Derived state: Let left always be length of todos. It recomputes after every turn.", &["teach_parity", "doc_examples"])),
386            Say(proven("A page test: Click \"#add\". Expect that the text of \"#n\" is equal to \"1\".", &["teach_parity", "doc_examples"])),
387            Say(proven("Logic mode: one sentence per line. Every dog barks. Some cat sleeps. No cat barks.", &["teach_parity", "doc_examples"])),
388            Say(proven("A theorem: Given: Every man is mortal. Given: Socrates is a man. Prove: He is mortal.", &["teach_parity", "doc_examples"])),
389            Say(proven("Then Proof: Auto. and the kernel certifies it.", &["teach_parity", "doc_examples"])),
390            Blank,
391            Step("5. Build the site"),
392            Say(agreed("Change pages/app.lg one thing at a time. After every change, run:")),
393            Run("largo check"),
394            Run("largo test"),
395            Say(proven("largo check explains each mistake it finds in plain English, with its line.", &["check_json", "diagnostic_surfaces_lock", "landing_page"])),
396            Say(proven("largo fmt sets the source in the standard layout.", &["fmt"])),
397            Say(proven("A page is its State, its Actions, its View in HTML with {holes}, and its Style in CSS.", &["landing_page"])),
398            Say(proven("For a backend of ## Route blocks under the pages, scaffold with largo new mysite --web.", &["landing_page"])),
399            Blank,
400            Step("6. Programs"),
401            Run("largo new hello"),
402            Run("cd hello"),
403            Run("largo run --interpret"),
404            Say(proven("It prints Hello, world! The program is src/main.lg and the manifest is Largo.toml.", &["landing_page", "phase_interpret_mode"])),
405            Say(proven("--interpret runs it in the interpreter, which needs no Rust toolchain.", &["landing_page", "phase_interpret_mode"])),
406            Say(proven("largo new also wrote a .gitignore, so git init makes the folder a repository.", &["landing_page"])),
407            Blank,
408            Step("7. Logic"),
409            Run("largo logic \"Every student read a book.\" --all-readings"),
410            Say(proven("prints every reading of the sentence in first-order logic.", &["logic", "phase12_ambiguity", "landing_page"])),
411            Say(proven("largo prove proves each ## Theorem block in a file (Given, Prove and Proof lines),", &["prove", "landing_page"])),
412            Say(proven("and the type theory kernel certifies every proof it reports:", &["prove", "phase69_kernel_coc"])),
413            Run("largo prove theorem.lg"),
414            Blank,
415            Step("8. Math"),
416            Say(proven("largo prove also proves the theorems of a ## Theory block from its axioms.", &["prove", "landing_page"])),
417            Say(proven("Inductive types, Definition, Check and Eval run in the Studio's Math mode:", &["e2e_studio_examples", "studio_example_contract"])),
418            Open(studio_address("/examples/math/natural-numbers.logos")),
419            Blank,
420            Step("9. Hardware"),
421            Say(proven("The Studio's Hardware mode turns an English spec into a SystemVerilog assertion", &["hardware_examples", "phase_hw_sva_2023"])),
422            Say(proven("and checks that the assertion matches the spec:", &["hardware_examples", "landing_page"])),
423            Open(studio_address("/examples/hardware/handshake.hw")),
424            Say(proven("The command line release has no hardware command yet.", &["landing_page"])),
425            Blank,
426            Step("10. Working with the user"),
427            Agree("Take small steps. Change one thing, run it, and report the output."),
428            Agree("Never report that something works before running it."),
429            Agree("Show the LOGOS written. The user reads it as English, so keep it plain."),
430            Agree("When a sentence can mean two things, ask which one is meant."),
431            Agree("Commit each step that runs, so there is always a way back."),
432        ]
433    });
434    &LINES
435}
436
437/// The instructions as one text: what the page shows and what the copy button copies.
438pub fn instructions_text() -> &'static str {
439    static TEXT: LazyLock<String> = LazyLock::new(|| instructions().iter().map(Line::text).collect::<Vec<_>>().join("\n"));
440    &TEXT
441}
442
443/// The front page's Studio frame: one shipped example for each kind of work the comparison names, in
444/// the Studio's own folders, opened on the website in a website (the user, 2026-10-01). The Logic
445/// example is a theorem with its givens, so a first visit's Prove has something to prove from (the
446/// user, 2026-11-01).
447pub fn shelf() -> &'static Shelf {
448    static SHELF: Shelf = Shelf {
449        opens: "/examples/code/web/website.logos",
450        files: &[
451            "/examples/code/web/website.logos",
452            "/examples/code/basics/control-flow.logos",
453            "/examples/code/verification/refinement.logos",
454            "/examples/code/distributed/merge.logos",
455            "/examples/logic/prover-demo.logic",
456            "/examples/math/auto-tactic.logos",
457            "/examples/hardware/handshake.hw",
458        ],
459    };
460    &SHELF
461}
462
463/// A tool a kind of work usually reaches for, named as its own site names it, and the page where it
464/// says so (shown nowhere on the page).
465pub struct Usually {
466    pub name: &'static str,
467    pub source: &'static str,
468}
469
470/// Where what a card says stands: in the released largo, in the Studio, in part, or in the next
471/// release (this tree, ahead of the release a reader installs today).
472#[derive(Clone, Copy, Debug, PartialEq, Eq)]
473pub enum Status {
474    Ships,
475    InTheStudio,
476    Partial,
477    NextRelease,
478}
479
480impl Status {
481    pub fn label(self) -> &'static str {
482        match self {
483            Status::Ships => "In largo",
484            Status::InTheStudio => "In the Studio",
485            Status::Partial => "In part",
486            Status::NextRelease => "Next release",
487        }
488    }
489}
490
491/// What a card's line leans on in largo: a command, or a target of `largo emit`.
492#[derive(Clone, Copy, Debug, PartialEq, Eq)]
493pub enum Uses {
494    Command(&'static str),
495    Emit(&'static str),
496}
497
498/// One card of the comparison: a kind of work, what it is usually done with, and what LOGOS does there.
499pub struct Card {
500    pub kind: &'static str,
501    pub usually: &'static [Usually],
502    pub logos: Claim,
503    pub tags: &'static [Status],
504    pub uses: &'static [Uses],
505    /// The shelf file the card's Try it opens in the frame above.
506    pub try_it: Option<&'static str>,
507}
508
509impl Card {
510    /// The tools the kind of work is usually done with, as the card lists them.
511    pub fn usually_names(&self) -> String {
512        self.usually.iter().map(|tool| tool.name).collect::<Vec<_>>().join(", ")
513    }
514}
515
516pub const COMPARE_HEADING: &str = "How LOGOS compares";
517
518/// The line under the comparison's heading: what the cards are.
519pub fn compare_lead() -> &'static Claim {
520    static LEAD: LazyLock<Claim> =
521        LazyLock::new(|| proven("Eight kinds of work, what each usually takes, and what LOGOS does there.", &["landing_page"]));
522    &LEAD
523}
524
525const PYTHON: Usually = Usually { name: "Python", source: "https://docs.python.org/3/" };
526const RUST: Usually = Usually { name: "Rust", source: "https://www.rust-lang.org/" };
527const C: Usually = Usually { name: "C", source: "https://www.open-std.org/jtc1/sc22/wg14/" };
528const LEAN: Usually = Usually { name: "Lean 4", source: "https://lean-lang.org/" };
529const ROCQ: Usually = Usually { name: "Rocq", source: "https://rocq-prover.org/" };
530const DAFNY: Usually = Usually { name: "Dafny", source: "https://dafny.org/" };
531const TLA: Usually = Usually { name: "TLA+", source: "https://lamport.azurewebsites.net/tla/tla.html" };
532const PROLOG: Usually = Usually { name: "Prolog", source: "https://www.iso.org/standard/21413.html" };
533const ACE: Usually = Usually { name: "Attempto Controlled English", source: "https://attempto.ifi.uzh.ch/site/" };
534const SYSTEMVERILOG: Usually = Usually { name: "SystemVerilog", source: "https://standards.ieee.org/ieee/1800/7743/" };
535const CHISEL: Usually = Usually { name: "Chisel", source: "https://www.chisel-lang.org/" };
536const CUDA: Usually = Usually { name: "CUDA", source: "https://docs.nvidia.com/cuda/" };
537const TYPESCRIPT: Usually = Usually { name: "TypeScript", source: "https://www.typescriptlang.org/" };
538const JAVASCRIPT: Usually = Usually { name: "JavaScript", source: "https://tc39.es/ecma262/" };
539const ELIXIR: Usually = Usually { name: "Elixir", source: "https://elixir-lang.org/" };
540const ERLANG: Usually = Usually { name: "Erlang", source: "https://www.erlang.org/" };
541const AUTOMERGE: Usually = Usually { name: "Automerge", source: "https://automerge.org/" };
542
543/// The comparison: eight kinds of work, each with what it is usually done with and what LOGOS does
544/// there as of 0.11.0, every line proven by the suites it names, and no claim of a win over anything.
545/// A card tagged for the next release leans on a command or an emit target the released largo lacks;
546/// as of 0.11.0, none does.
547pub fn compare() -> &'static [Card] {
548    static CARDS: LazyLock<Vec<Card>> = LazyLock::new(|| {
549        vec![
550            Card {
551                kind: "General purpose",
552                usually: &[PYTHON, RUST, C],
553                logos: proven(
554                    "English programs, checked before they run, built through Rust, C or WebAssembly.",
555                    &["code_examples_all_tiers", "benchmark_logos_tiers_lock", "largo_build_emit_c"],
556                ),
557                tags: &[Status::Ships],
558                uses: &[Uses::Command("build"), Uses::Emit("c"), Uses::Emit("wasm")],
559                try_it: Some("/examples/code/basics/control-flow.logos"),
560            },
561            Card {
562                kind: "Proof assistants",
563                usually: &[LEAN, ROCQ],
564                logos: proven(
565                    "Theorems in English, checked by a kernel whose integers are Lean's.",
566                    &["dag_dual_agreement", "axiom_footprint_lean_parity", "definition_kernel"],
567                ),
568                tags: &[Status::InTheStudio],
569                uses: &[Uses::Command("lean")],
570                try_it: Some("/examples/math/auto-tactic.logos"),
571            },
572            Card {
573                kind: "Verification",
574                usually: &[DAFNY, TLA],
575                logos: proven(
576                    "Refinements and assertions checked as the program is built.",
577                    &["e2e_refinement", "phase25_assertions", "phase43_refinement"],
578                ),
579                tags: &[Status::Ships],
580                uses: &[Uses::Command("check"), Uses::Command("verify")],
581                try_it: Some("/examples/code/verification/refinement.logos"),
582            },
583            Card {
584                kind: "Logic and controlled English",
585                usually: &[PROLOG, ACE],
586                logos: proven(
587                    "Sentences become first-order logic, with scope and every reading.",
588                    &["logic", "logic_determiner_readings", "modal_scope_tests"],
589                ),
590                tags: &[Status::InTheStudio],
591                uses: &[Uses::Command("logic")],
592                try_it: Some("/examples/logic/prover-demo.logic"),
593            },
594            Card {
595                kind: "Hardware",
596                usually: &[SYSTEMVERILOG, CHISEL],
597                logos: proven(
598                    "English specs become SystemVerilog assertions, programs become circuits.",
599                    &["phase_hw_fol_to_sva", "phase_hw_sva_roundtrip", "caravel_signoff_lock", "sky130_deep_signoff_lock"],
600                ),
601                tags: &[Status::InTheStudio],
602                uses: &[Uses::Command("bringup")],
603                try_it: Some("/examples/hardware/handshake.hw"),
604            },
605            Card {
606                kind: "GPU",
607                usually: &[CUDA],
608                logos: proven(
609                    "Transformers written as tensor sentences, lowered to CUDA, FPGAs and Tenstorrent.",
610                    &["cuda_aot_lock", "cuda_attention_gqa_lock", "int8_decode_lock", "decode_board_lock"],
611                ),
612                tags: &[Status::Ships],
613                uses: &[Uses::Emit("cuda"), Uses::Emit("tenstorrent")],
614                try_it: None,
615            },
616            Card {
617                kind: "Web",
618                usually: &[TYPESCRIPT, JAVASCRIPT],
619                logos: proven(
620                    "Pages, components and typed routes in English, tested where they run.",
621                    &["lgx_check_lock", "lgx_constructs_lock", "serve_fullstack"],
622                ),
623                tags: &[Status::InTheStudio],
624                uses: &[Uses::Command("serve"), Uses::Command("test")],
625                try_it: Some("/examples/code/web/website.logos"),
626            },
627            Card {
628                kind: "Concurrency and distributed",
629                usually: &[ELIXIR, ERLANG, AUTOMERGE],
630                logos: proven(
631                    "Tasks and channels in English, collections that merge without conflict.",
632                    &["concurrency_aot", "e2e_crdt", "converge_crdt_lock"],
633                ),
634                tags: &[Status::Ships],
635                uses: &[Uses::Command("run")],
636                try_it: Some("/examples/code/distributed/merge.logos"),
637            },
638        ]
639    });
640    &CARDS
641}
642
643pub const LIBRARY_HEADING: &str = "What comes with LOGOS";
644
645/// The standard library's figures: the prelude's module count, read from the loader, and the parity
646/// ledger's correctness figures and upstream languages, read from the ledger as it is checked in
647/// (`benchmarks/parity/PARITY_LEDGER.md`), so the page can never say a number the ledger does not.
648pub struct LibraryFigures {
649    pub modules: usize,
650    pub green: usize,
651    pub in_scope: usize,
652}
653
654const PARITY_LEDGER: &str = include_str!("../../../../../../benchmarks/parity/PARITY_LEDGER.md");
655
656pub fn library_figures() -> LibraryFigures {
657    let parity = PARITY_LEDGER.lines().find(|line| line.contains("**Correctness parity:**")).expect("the ledger states its correctness parity");
658    let inner = &parity[parity.find('(').unwrap() + 1..parity.find(')').unwrap()];
659    let numbers: Vec<usize> = inner.split(|c: char| !c.is_ascii_digit()).filter(|w| !w.is_empty()).filter_map(|w| w.parse().ok()).collect();
660    LibraryFigures { modules: logicaffeine_compile::loader::prelude_module_sources().len(), green: numbers[0], in_scope: numbers[1] }
661}
662
663
664/// The standard library in two lines, each with the figures it quotes.
665pub fn library() -> &'static [Claim] {
666    static LINES: LazyLock<Vec<Claim>> = LazyLock::new(|| {
667        let figures = library_figures();
668        vec![
669            proven(
670                format!("{} modules written in LOGOS, auto-imported as a program uses them.", figures.modules),
671                &["import_scan_lock", "phase36_modules", "crypto_stdlib"],
672            ),
673            proven(
674                format!(
675                    "{} of {} capabilities of the C, Python, Rust, Go and Java standard libraries, checked against their sources.",
676                    figures.green, figures.in_scope
677                ),
678                &["blas_stdlib", "crypto_stdlib", "http_stdlib"],
679            ),
680        ]
681    });
682    &LINES
683}
684
685/// What 0.11.0 brings, a line each, ten words or fewer, each proven by the suites it names.
686pub fn features() -> &'static [Claim] {
687    static LINES: LazyLock<Vec<Claim>> = LazyLock::new(|| {
688        vec![
689            proven("Tests, properties and replays, written in the language.", &["property_test_lock", "tests_index_lock", "replay_lock"]),
690            proven("A failing run replays, and the debugger steps backward.", &["replay_lock", "e2e_deterministic_replay"]),
691            proven("Import joins files. The type checker runs on every join.", &["import_hygiene", "phase36_modules", "lgx_check_lock"]),
692            proven("Infinitesimals, hyperreals and exact reals, compiled to Rust.", &["hyperreal_closure", "hyperreal_functions", "exact_by_context"]),
693            proven("Theorems check in a kernel whose integers are Lean's.", &["dag_dual_agreement", "axiom_footprint_lean_parity"]),
694            proven("HTTP served natively, with verified TLS.", &["http_lifecycle_lock", "tcp_tls_lock"]),
695            proven("One scheduler runs tasks on C, RISC-V and GPU.", &["c_family_scheduler_conformance_lock", "c_concurrency_scheduler_lock"]),
696        ]
697    });
698    &LINES
699}
700
701/// A question the front page answers.
702pub struct Faq {
703    pub question: &'static str,
704    pub answer: Claim,
705    /// A run of the answer shown as a link, and where it goes.
706    pub link: Option<(&'static str, &'static str)>,
707}
708
709pub fn faq() -> &'static [Faq] {
710    static FAQ: LazyLock<Vec<Faq>> = LazyLock::new(|| {
711        let learn = learn_figures();
712        vec![
713            Faq { question: "Is it really free?", answer: proven(free_answer(), &["contact_page", "version_lock"]), link: None },
714            Faq {
715                question: "Do I need to know logic already?",
716                answer: proven(
717                    format!(
718                        "No. Learn teaches it step by step, in {} modules and {} exercises, free in the browser.",
719                        learn.modules, learn.exercises
720                    ),
721                    &["learn_curriculum"],
722                ),
723                link: None,
724            },
725            Faq {
726                question: "Which coding agents can use the instructions?",
727                answer: agreed(
728                    "Any agent that can read a web page and run commands in a terminal, such as Claude Code, Cursor or \
729                     Codex. The instructions are plain text, so they paste into any of them.",
730                ),
731                link: None,
732            },
733            Faq {
734                question: "Where is the source?",
735                answer: agreed("On GitHub: github.com/Brahmastra-Labs/logicaffeine"),
736                link: Some(("github.com/Brahmastra-Labs/logicaffeine", SOURCE_URL)),
737            },
738        ]
739    });
740    &FAQ
741}
742
743/// Every line the page states with its evidence: the guide's sentences and rules, the line on how
744/// for each system, the comparison's lead and cards, the library's lines and features, and the FAQ's
745/// answers.
746pub fn every_claim() -> Vec<(String, &'static Evidence)> {
747    let lines = instructions().iter().filter_map(|line| match line {
748        Line::Say(claim) | Line::Rule(claim) => Some(claim),
749        _ => None,
750    });
751    let hows = std::iter::once(how());
752    let cards = std::iter::once(compare_lead()).chain(compare().iter().map(|card| &card.logos));
753    let library = library().iter().chain(features().iter());
754    let answers = faq().iter().map(|faq| &faq.answer);
755    lines.chain(hows).chain(cards).chain(library).chain(answers).map(|claim| (claim.text.clone(), &claim.evidence)).collect()
756}