Merge branch 'worktree-philosophy' into macros

This commit is contained in:
2026-03-08 15:19:14 +00:00
5 changed files with 379 additions and 8 deletions

View File

@@ -72,7 +72,7 @@ ESSAYS_NAV = [
("On-Demand CSS", "/essays/on-demand-css"),
("Client Reactivity", "/essays/client-reactivity"),
("SX Native", "/essays/sx-native"),
("The SX Manifesto", "/essays/sx-manifesto"),
("The SX Manifesto", "/philosophy/sx-manifesto"),
("Tail-Call Optimization", "/essays/tail-call-optimization"),
("Continuations", "/essays/continuations"),
]

View File

@@ -1,5 +1,336 @@
;; Essay content — static content extracted from essays.py
;; ---------------------------------------------------------------------------
;; Philosophy section content
;; ---------------------------------------------------------------------------
(defcomp ~philosophy-index-content ()
(~doc-page :title "Philosophy"
(div :class "space-y-4"
(p :class "text-lg text-stone-600 mb-4"
"The deeper ideas behind SX — manifestos, self-reference, and the philosophical traditions that shaped the language.")
(div :class "space-y-3"
(map (fn (item)
(a :href (get item "href")
:sx-get (get item "href") :sx-target "#main-panel" :sx-select "#main-panel"
:sx-swap "outerHTML" :sx-push-url "true"
:class "block rounded border border-stone-200 p-4 hover:border-violet-300 hover:bg-violet-50 transition-colors"
(div :class "font-semibold text-stone-800" (get item "label"))
(when (get item "summary")
(p :class "text-sm text-stone-500 mt-1" (get item "summary")))))
philosophy-nav-items)))))
(defcomp ~essay-sx-and-wittgenstein ()
(~doc-page :title "SX and Wittgenstein"
(p :class "text-stone-500 text-sm italic mb-8"
"The limits of my language are the limits of my world.")
(~doc-section :title "I. Language games" :id "language-games"
(p :class "text-stone-600"
"In 1953, Ludwig " (a :href "https://en.wikipedia.org/wiki/Ludwig_Wittgenstein" :class "text-violet-600 hover:underline" "Wittgenstein") " published " (a :href "https://en.wikipedia.org/wiki/Philosophical_Investigations" :class "text-violet-600 hover:underline" "Philosophical Investigations") " — a book that dismantled the theory of language he had built in his own earlier work. The " (a :href "https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus" :class "text-violet-600 hover:underline" "Tractatus") " had argued that language pictures the world: propositions mirror facts, and the structure of a sentence corresponds to the structure of reality. The Investigations abandoned this. Language does not picture anything. Language is " (em "used") ".")
(p :class "text-stone-600"
"Wittgenstein replaced the picture theory with " (a :href "https://en.wikipedia.org/wiki/Language_game_(philosophy)" :class "text-violet-600 hover:underline" "language games") " — activities in which words get their meaning from how they are employed, not from what they refer to. \"Slab!\" on a building site means \"bring me a slab.\" The same word in a dictionary means nothing until it enters a game. Meaning is use.")
(p :class "text-stone-600"
"Web development is a proliferation of language games. HTML is one game — a markup game where tags denote structure. CSS is another — a declaration game where selectors denote style. JavaScript is a third — an imperative game where statements denote behaviour. JSX is a fourth game layered on top of the third, pretending to be the first. TypeScript is a fifth game that annotates the third. Each has its own grammar, its own rules, its own way of meaning.")
(p :class "text-stone-600"
"SX collapses these into a single game. " (code "(div :class \"p-4\" (h2 title))") " is simultaneously structure (a div containing an h2), style (the class attribute), and behaviour (the symbol " (code "title") " is evaluated). There is one syntax, one set of rules, one way of meaning. Not because the distinctions between structure, style, and behaviour have been erased — they haven't — but because they are all expressed in the same language game."))
(~doc-section :title "II. The limits of my language" :id "limits"
(p :class "text-stone-600"
"\"" (a :href "https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus" :class "text-violet-600 hover:underline" "Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt") "\" — the limits of my language mean the limits of my world. This is proposition 5.6 of the Tractatus, and it is the most important sentence Wittgenstein ever wrote.")
(p :class "text-stone-600"
"If your language is HTML, your world is documents. You can link documents. You can nest elements inside documents. You cannot compose documents from smaller documents without a server-side include, an iframe, or JavaScript. The language does not have composition, so your world does not have composition.")
(p :class "text-stone-600"
"If your language is React, your world is components that re-render. You can compose components. You can pass props. You cannot inspect a component's structure at runtime without React DevTools. You cannot serialize a component tree to a format another framework can consume. You cannot send a component over HTTP and have it work on the other side without the same React runtime. The language has composition but not portability, so your world has composition but not portability.")
(p :class "text-stone-600"
"If your language is s-expressions, your world is " (em "expressions") ". An expression can represent a DOM node, a function call, a style declaration, a macro transformation, a component definition, a wire-format payload, or a specification of the evaluator itself. The language has no built-in limits on what can be expressed, because the syntax — the list — can represent anything. The limits of the language are only the limits of what you choose to evaluate.")
(~doc-code :lang "lisp" :code
";; The same syntax expresses everything:\n(div :class \"card\" (h2 \"Title\")) ;; structure\n(css :flex :gap-4 :p-2) ;; style\n(defcomp ~card (&key title) (div title)) ;; abstraction\n(defmacro ~log (x) `(console.log ,x)) ;; metaprogramming\n(quote (div :class \"card\" (h2 \"Title\"))) ;; data about structure")
(p :class "text-stone-600"
"Wittgenstein's proposition cuts both ways. A language that limits you to documents limits your world to documents. A language that can express anything — because its syntax is the minimal recursive structure — limits your world to " (em "everything") "."))
(~doc-section :title "III. Whereof one cannot speak" :id "silence"
(p :class "text-stone-600"
"The Tractatus ends: \"" (a :href "https://en.wikipedia.org/wiki/Tractatus_Logico-Philosophicus#Proposition_7" :class "text-violet-600 hover:underline" "Whereof one cannot speak, thereof one must be silent") ".\" Proposition 7. The things that cannot be said in a language simply do not exist within that language's world.")
(p :class "text-stone-600"
"HTML cannot speak of composition. It is silent on components. You cannot define " (code "~card") " in HTML. You can define " (code "<template>") " and " (code "<slot>") " in Web Components, but that requires JavaScript — you have left HTML's language game and entered another.")
(p :class "text-stone-600"
"CSS cannot speak of conditions. It is silent on logic. You cannot say \"if the user is logged in, use this colour.\" You can use " (code ":has()") " and " (code "@container") " queries, but these are conditions about " (em "the document") ", not conditions about " (em "the application") ". CSS can only speak of what CSS can see.")
(p :class "text-stone-600"
"JavaScript can speak of almost everything — but it speaks in statements, not expressions. The difference matters. A statement executes and is gone. An expression evaluates to a value. Values compose. Statements require sequencing. React discovered this when it moved from class components (imperative, statement-oriented) to hooks (closer to expressions, but not quite — hence the rules of hooks).")
(p :class "text-stone-600"
"S-expressions are pure expression. Every form evaluates to a value. There is nothing that cannot be spoken, because lists can nest arbitrarily and symbols can name anything. There is no proposition 7 for s-expressions — no enforced silence, no boundary where the language gives out. The programmer decides where to draw the line, not the syntax."))
(~doc-section :title "IV. Family resemblance" :id "family-resemblance"
(p :class "text-stone-600"
"Wittgenstein argued that concepts do not have sharp definitions. What is a \"" (a :href "https://en.wikipedia.org/wiki/Family_resemblance" :class "text-violet-600 hover:underline" "game") "\"? Chess, football, solitaire, ring-a-ring-o'-roses — they share no single essential feature. Instead, they form a network of overlapping similarities. A " (a :href "https://en.wikipedia.org/wiki/Family_resemblance" :class "text-violet-600 hover:underline" "family resemblance") ".")
(p :class "text-stone-600"
"Web frameworks have this property. What is a \"component\"? In React, it is a function that returns JSX. In Vue, it is an object with a template property. In Svelte, it is a " (code ".svelte") " file. In Web Components, it is a class that extends HTMLElement. In Angular, it is a TypeScript class with a decorator. These are not the same thing. They share a family resemblance — they all produce reusable UI — but their definitions are incompatible. A React component cannot be used in Vue. A Svelte component cannot be used in Angular. The family does not communicate.")
(p :class "text-stone-600"
"In SX, a component is a list whose first element is a symbol beginning with " (code "~") ". That is the complete definition. It is not a function, not a class, not a file, not a decorator. It is a " (em "naming convention on a data structure") ". Any system that can process lists can process SX components. Python evaluates them on the server. JavaScript evaluates them in the browser. A future Rust evaluator could evaluate them on an embedded device. The family resemblance sharpens into actual identity: a component is a component is a component, because the representation is the same everywhere.")
(~doc-code :lang "lisp" :code
";; This is a component in every SX evaluator:\n(defcomp ~greeting (&key name)\n (div :class \"p-4\"\n (h2 (str \"Hello, \" name))))\n\n;; The same s-expression is:\n;; - parsed by the same parser\n;; - evaluated by the same eval rules\n;; - rendered by the same render spec\n;; - on every host, in every context"))
(~doc-section :title "V. Private language" :id "private-language"
(p :class "text-stone-600"
"The " (a :href "https://en.wikipedia.org/wiki/Private_language_argument" :class "text-violet-600 hover:underline" "private language argument") " is one of Wittgenstein's most provocative claims: there can be no language whose words refer to the speaker's private sensations and nothing else. Language requires public criteria — shared rules that others can check. A word that means something only to you is not a word at all.")
(p :class "text-stone-600"
"Most web frameworks are private languages. React's JSX is meaningful only to the React runtime. Vue's " (code ".vue") " single-file components are meaningful only to the Vue compiler. Svelte's " (code ".svelte") " files are meaningful only to the Svelte compiler. Each framework speaks a language that no one else can understand. They are private languages in Wittgenstein's sense — their terms have meaning only within their own closed world.")
(p :class "text-stone-600"
"S-expressions are radically public. The syntax is universal: open paren, atoms, close paren. Any Lisp, any s-expression processor, any JSON-to-sexp converter can read them. The SX evaluator adds meaning — " (code "defcomp") ", " (code "defmacro") ", " (code "if") ", " (code "let") " — but these meanings are specified in s-expressions themselves (" (code "eval.sx") "), readable by anyone. There is no private knowledge. There is no compilation step that transforms the public syntax into a private intermediate form. The source is the artefact.")
(p :class "text-stone-600"
"This is why SX can be self-hosting. A private language cannot define itself — it would need a second private language to define the first, and a third to define the second. A public language, one whose rules are expressible in its own terms, can close the loop. " (code "eval.sx") " defines SX in SX. The language defines itself publicly, in a form that any reader can inspect."))
(~doc-section :title "VI. Showing and saying" :id "showing-saying"
(p :class "text-stone-600"
"The Tractatus makes a crucial distinction between what can be " (em "said") " and what can only be " (em "shown") ". Logic, Wittgenstein argued, cannot be said — it can only be shown by the structure of propositions. You cannot step outside logic to make statements about logic; you can only exhibit logical structure by using it.")
(p :class "text-stone-600"
"Most languages " (em "say") " their semantics — in English-language specifications, in RFC documents, in MDN pages. The semantics are described " (em "about") " the language, in a different medium.")
(p :class "text-stone-600"
"SX " (em "shows") " its semantics. The specification is not a description of the language — it is the language operating on itself. " (code "eval.sx") " does not say \"the evaluator dispatches on the type of expression.\" It " (em "is") " an evaluator that dispatches on the type of expression. " (code "parser.sx") " does not say \"strings are delimited by double quotes.\" It " (em "is") " a parser that recognises double-quoted strings.")
(p :class "text-stone-600"
"This is exactly the distinction Wittgenstein drew. What can be said (described, documented, specified in English) is limited. What can be shown (exhibited, demonstrated, enacted) goes further. SX's self-hosting spec shows its semantics by " (em "being") " them — the strongest form of specification possible. The spec cannot be wrong, because the spec runs."))
(~doc-section :title "VII. The beetle in the box" :id "beetle"
(p :class "text-stone-600"
"Wittgenstein's " (a :href "https://en.wikipedia.org/wiki/Private_language_argument#The_beetle_in_a_box" :class "text-violet-600 hover:underline" "beetle-in-a-box") " thought experiment: suppose everyone has a box, and everyone calls what's inside their box a \"beetle.\" No one can look in anyone else's box. The word \"beetle\" refers to whatever is in the box — but since no one can check, the contents might be different for each person, or the box might even be empty. The word gets its meaning from the " (em "game") " it plays in public, not from the private contents of the box.")
(p :class "text-stone-600"
"A web component is a beetle in a box. You call it " (code "<my-button>") " but what's inside — Shadow DOM, event listeners, internal state, style encapsulation — is private. Two components with the same tag name might do completely different things. Two frameworks with the same concept of \"component\" might mean completely different things by it. The word \"component\" functions in the language game of developer conversation, but the actual contents are private to each implementation.")
(p :class "text-stone-600"
"In SX, you can open the box. Components are data. " (code "(defcomp ~card (&key title) (div title))") " — the entire definition is visible, inspectable, serializable. There is no shadow DOM, no hidden state machine, no encapsulated runtime. The component's body is an s-expression. You can quote it, transform it, analyse it, send it over HTTP, evaluate it in a different context. The beetle is on the table."))
(~doc-section :title "VIII. The fly-bottle" :id "fly-bottle"
(p :class "text-stone-600"
"\"What is your aim in philosophy?\" Wittgenstein was asked. \"" (a :href "https://en.wikipedia.org/wiki/Philosophical_Investigations#Meaning_and_definition" :class "text-violet-600 hover:underline" "To show the fly the way out of the fly-bottle") ".\"")
(p :class "text-stone-600"
"The fly-bottle is the trap of false problems — questions that seem deep but are actually artefacts of confused language. \"What is the virtual DOM?\" is a fly-bottle question. The virtual DOM exists because React needed a way to reconcile its component model with the browser's DOM. If your component model " (em "is") " the DOM — if components evaluate directly to DOM nodes, as they do in SX — the question dissolves. There is no virtual DOM because there is no gap between the component and what it produces.")
(p :class "text-stone-600"
"\"How do we solve CSS scoping?\" Fly-bottle. CSS scoping is a problem because CSS is a global language applied to a local context. If styles are expressions evaluated in the same scope as the component that uses them — as in SX's CSSX — there is nothing to scope. The problem was created by the language separation, not by the nature of styling.")
(p :class "text-stone-600"
"\"How do we share state between server and client?\" Fly-bottle. This is hard when the server speaks one language (Python templates) and the client speaks another (JavaScript). When both speak s-expressions, and the wire format IS the source syntax, state transfer is serialisation — which is identity for s-expressions. " (code "aser") " serialises an SX expression as an SX expression. The server and client share state by sharing code.")
(p :class "text-stone-600"
"SX does not solve these problems. It dissolves them — by removing the language confusion that created them. Wittgenstein's method, applied to web development: the problems were never real. They were artefacts of speaking in the wrong language."))
(~doc-section :title "IX. Back to rough ground" :id "rough-ground"
(p :class "text-stone-600"
"\"We have got on to slippery ice where there is no friction and so in a certain sense the conditions are ideal, but also, just because of that, we are unable to walk. We want to walk: so we need " (a :href "https://en.wikipedia.org/wiki/Philosophical_Investigations" :class "text-violet-600 hover:underline" "friction") ". Back to the rough ground!\"")
(p :class "text-stone-600"
"The slippery ice is the idealised abstraction — the framework that promises a perfect developer experience, the type system that promises to catch all bugs, the architecture diagram that promises clean separation. These are frictionless surfaces. They look beautiful. You cannot walk on them.")
(p :class "text-stone-600"
"SX is rough ground. S-expressions are not pretty. Parentheses are friction. There is no syntax highlighting tuned for this. There is no IDE with SX autocomplete. There is no build system to smooth over rough edges because there is no build system. You write s-expressions. You evaluate them. You see the result. The feedback loop is immediate and unmediated.")
(p :class "text-stone-600"
"This is a feature. Friction is how you know you are touching the ground. Friction is where the work happens. The perfectly frictionless framework lets you get started in five minutes and spend six months debugging its abstractions. SX asks you to understand s-expressions — a syntax that has not changed since 1958 — and then gives you the entire web as your world.")
(p :class "text-stone-600"
"Wittgenstein wanted philosophy to stop theorising and start looking at how language actually works. SX wants web development to stop abstracting and start looking at what expressions actually are. Lists. Symbols. Evaluation. Composition. Everything else is a fly-bottle."))))
(defcomp ~essay-sx-and-dennett ()
(~doc-page :title "SX and Dennett"
(p :class "text-stone-500 text-sm italic mb-8"
"Real patterns, multiple drafts, and the intentional stance — a philosopher of mind meets a language that thinks about itself.")
(~doc-section :title "I. The intentional stance" :id "intentional-stance"
(p :class "text-stone-600"
"Daniel " (a :href "https://en.wikipedia.org/wiki/Daniel_Dennett" :class "text-violet-600 hover:underline" "Dennett") " spent fifty years arguing that the mind is not what it seems. His central method is the " (a :href "https://en.wikipedia.org/wiki/Intentional_stance" :class "text-violet-600 hover:underline" "intentional stance") " — a strategy for predicting a system's behaviour by treating it " (em "as if") " it has beliefs, desires, and intentions, whether or not it \"really\" does.")
(p :class "text-stone-600"
"There are three stances. The " (em "physical stance") " predicts from physics — voltage levels, transistor states, bytes in memory. The " (em "design stance") " predicts from how the thing was built — a thermostat turns on the heating when the temperature drops below the set point, regardless of its internal wiring. The " (em "intentional stance") " predicts from ascribed beliefs and goals — the chess program \"wants\" to protect its king, \"believes\" the centre is important.")
(p :class "text-stone-600"
"Web frameworks enforce a single stance. React's mental model is the design stance: components are functions, props go in, JSX comes out. You reason about the system by reasoning about its design. If you need the physical stance (what is actually in the DOM right now?), you reach for " (code "useRef") ". If you need the intentional stance (what does this component " (em "mean") "?), you read the documentation. Each stance requires a different tool, a different context switch.")
(p :class "text-stone-600"
"SX lets you shift stances without shifting languages. The physical stance: " (code "(div :class \"card\" (h2 \"Title\"))") " — this is exactly the DOM structure that will be produced. One list, one element. The design stance: " (code "(defcomp ~card (&key title) (div title))") " — this is how the component is built, its contract. The intentional stance: " (code "(~card :title \"Hello\")") " — this " (em "means") " \"render a card with this title,\" and you can reason about it at that level without knowing the implementation.")
(~doc-code :lang "lisp" :code
";; Physical stance — the literal structure\n(div :class \"card\" (h2 \"Title\"))\n\n;; Design stance — how it's built\n(defcomp ~card (&key title) (div :class \"card\" (h2 title)))\n\n;; Intentional stance — what it means\n(~card :title \"Title\")\n\n;; All three are s-expressions.\n;; All three can be inspected, transformed, quoted.\n;; Shifting stance = changing which expression you look at.")
(p :class "text-stone-600"
"The key insight: all three stances are expressed in the same medium. You do not need a debugger for the physical stance, a type system for the design stance, and documentation for the intentional stance. You need lists. The stances are not different tools — they are different ways of reading the same data."))
(~doc-section :title "II. Real patterns" :id "real-patterns"
(p :class "text-stone-600"
"Dennett's 1991 paper \"" (a :href "https://en.wikipedia.org/wiki/Real_Patterns" :class "text-violet-600 hover:underline" "Real Patterns") "\" makes a deceptively simple argument: a pattern is real if it lets you compress data — if recognising the pattern gives you predictive leverage that you would not have otherwise. Patterns are not " (em "in the mind") " of the observer. They are not " (em "in the object") " independently of any observer. They are real features of the world that exist at a particular level of description.")
(p :class "text-stone-600"
"Consider a bitmap of noise. If you describe it pixel by pixel, the description is as long as the image. No compression. No pattern. Now consider a bitmap of a checkerboard. You can say \"alternating black and white squares, 8x8\" — vastly shorter than the pixel-by-pixel description. The checkerboard pattern is " (em "real") ". It exists in the data. Recognising it gives you compression.")
(p :class "text-stone-600"
"Components are real patterns. " (code "(~card :title \"Hello\")") " compresses " (code "(div :class \"card\" (h2 \"Hello\"))") " — and more importantly, it compresses every instance of card-like structure across the application into a single abstraction. The component is not a convenient fiction. It is a real pattern in the codebase: a regularity that gives you predictive power. When you see " (code "~card") ", you know the structure, the styling, the contract — without expanding the definition.")
(p :class "text-stone-600"
"Macros are real patterns at a higher level. A macro like " (code "defcomp") " captures the pattern of \"name, parameters, body\" that every component shares. It compresses the regularity of component definition itself. The macro is real in exactly Dennett's sense — it captures a genuine pattern, and that pattern gives you leverage.")
(p :class "text-stone-600"
"Now here is where SX makes Dennett's argument concrete. In most languages, the reality of patterns is debatable — are classes real? Are interfaces real? Are design patterns real? You can argue either way because the patterns exist at a different level from the code. In SX, patterns " (em "are") " code. A component is a list. A macro is a function over lists. The pattern and the data it describes are the same kind of thing — s-expressions. There is no level-of-description gap. The pattern is as real as the data it compresses, because they inhabit the same ontological plane.")
(~doc-code :lang "lisp" :code
";; The data (expanded)\n(div :class \"card\"\n (h2 \"Pattern\")\n (p \"A real one.\"))\n\n;; The pattern (compressed)\n(~card :title \"Pattern\" (p \"A real one.\"))\n\n;; The meta-pattern (the definition)\n(defcomp ~card (&key title &rest children)\n (div :class \"card\" (h2 title) children))\n\n;; All three levels: data, pattern, meta-pattern.\n;; All three are lists. All three are real."))
(~doc-section :title "III. Multiple Drafts" :id "multiple-drafts"
(p :class "text-stone-600"
"In " (a :href "https://en.wikipedia.org/wiki/Consciousness_Explained" :class "text-violet-600 hover:underline" "Consciousness Explained") " (1991), Dennett proposed the " (a :href "https://en.wikipedia.org/wiki/Multiple_drafts_model" :class "text-violet-600 hover:underline" "Multiple Drafts model") " of consciousness. There is no " (a :href "https://en.wikipedia.org/wiki/Cartesian_theater" :class "text-violet-600 hover:underline" "Cartesian theater") " — no single place in the brain where \"it all comes together\" for a central observer. Instead, multiple parallel processes generate content simultaneously. Various drafts of narrative are in process at any time, some getting revised, some abandoned, some incorporated into the ongoing story. There is no master draft. There is no final audience. There is just the process of revision itself.")
(p :class "text-stone-600"
"React is a Cartesian theater. The virtual DOM is the stage. Reconciliation is the moment where \"it all comes together\" — the single canonical comparison between what was and what should be. One tree diffs against another. One algorithm produces one patch. The entire UI passes through a single bottleneck. There is a master draft, and its name is " (code "ReactDOM.render") ".")
(p :class "text-stone-600"
"SX has no theater. There are multiple drafts, genuinely parallel, with no single canonical render:")
(ul :class "list-disc pl-6 space-y-1 text-stone-600"
(li (span :class "font-semibold" "Server draft") " — Python evaluates components into SX wire format. This is a draft: it contains component calls unexpanded, slots unfilled, decisions deferred.")
(li (span :class "font-semibold" "Wire draft") " — the SX source text transmitted over HTTP. It is a draft in transit — meaningful as text, interpretable by any reader, but not yet rendered.")
(li (span :class "font-semibold" "Client draft") " — JavaScript evaluates the wire format into DOM nodes. Another draft: the browser's layout engine will revise it further (CSS computation, reflow, paint).")
(li (span :class "font-semibold" "Interaction draft") " — the user clicks, the server produces new SX, the client patches the DOM. The revision process continues. No draft is final."))
(p :class "text-stone-600"
"Each draft is a complete s-expression. Each is meaningful on its own terms. No single process \"sees\" the whole page — the server doesn't see the DOM, the client doesn't see the Python context, the browser's layout engine doesn't see the s-expressions. The page emerges from the drafting process, not from a central reconciler.")
(p :class "text-stone-600"
"This is not a metaphor stretched over engineering. It is the actual architecture. There is no virtual DOM because there is no need for a Cartesian theater. The multiple drafts model works because each draft is in the same format — s-expressions — so revision is natural. A draft can be inspected, compared, serialised, sent somewhere else, and revised further. Dennett's insight was that consciousness works this way. SX's insight is that rendering can too."))
(~doc-section :title "IV. Heterophenomenology" :id "heterophenomenology"
(p :class "text-stone-600"
(a :href "https://en.wikipedia.org/wiki/Heterophenomenology" :class "text-violet-600 hover:underline" "Heterophenomenology") " is Dennett's method for studying consciousness. Instead of asking \"what is it like to be a bat?\" — a question we cannot answer — we ask the bat to tell us, and then we study " (em "the report") ". We take the subject's testimony seriously, catalogue it rigorously, but we do not take it as infallible. The report is data. We are scientists of the report.")
(p :class "text-stone-600"
"Most programming languages cannot report on themselves. JavaScript can " (code "toString()") " a function, but the result is a string — opaque, unparseable, implementation-dependent. Python can inspect a function's AST via " (code "ast.parse(inspect.getsource(f))") " — but the AST is a separate data structure, disconnected from the running code. The language's self-report is in a different format from the language itself. Studying it requires tools, transformations, bridges.")
(p :class "text-stone-600"
"SX is natively heterophenomenological. The language's self-report " (em "is") " the language. " (code "eval.sx") " is the evaluator reporting on how evaluation works — in the same s-expressions that it evaluates. " (code "parser.sx") " is the parser reporting on how parsing works — in the same syntax it parses. You study the report by reading it. You verify the report by running it. The report and the reality are the same object.")
(~doc-code :lang "lisp" :code
";; The evaluator's self-report (from eval.sx):\n(define eval-expr\n (fn (expr env)\n (cond\n (number? expr) expr\n (string? expr) expr\n (symbol? expr) (env-get env expr)\n (list? expr) (eval-list expr env)\n :else (error \"Unknown expression type\"))))\n\n;; This is simultaneously:\n;; 1. A specification (what eval-expr does)\n;; 2. A program (it runs)\n;; 3. A report (the evaluator describing itself)\n;; Heterophenomenology without the hetero.")
(p :class "text-stone-600"
"Dennett insisted that heterophenomenology is the only honest method. First-person reports are unreliable — introspection gets things wrong. Third-person observation misses the subject's perspective. The middle path is to take the report as data and study it rigorously. SX's self-hosting spec is this middle path enacted in code: neither a first-person account (\"trust me, this is how it works\") nor a third-person observation (English prose describing the implementation), but a structured report that can be verified, compiled, and run."))
(~doc-section :title "V. Where am I?" :id "where-am-i"
(p :class "text-stone-600"
"Dennett's thought experiment \"" (a :href "https://en.wikipedia.org/wiki/Where_Am_I%3F_(Dennett)" :class "text-violet-600 hover:underline" "Where Am I?") "\" imagines his brain removed from his body, connected by radio. His body walks around; his brain sits in a vat. Where is Dennett? Where the brain is? Where the body is? The question has no clean answer because identity is not located in a single place — it is distributed across the system.")
(p :class "text-stone-600"
"Where is an SX component? On the server, it is a Python object — a closure with a body and bound environment. On the wire, it is text: " (code "(~card :title \"Hello\")") ". In the browser, it is a JavaScript function registered in the component environment. In the DOM, it is a tree of elements. Which one is the \"real\" component? All of them. None of them. The component is not located in one runtime — it is the pattern that persists across all of them.")
(p :class "text-stone-600"
"This is Dennett's point about personal identity applied to software identity. The SX component " (code "~card") " is defined in a " (code ".sx") " file, compiled by the Python bootstrapper into the server evaluator, transmitted as SX wire format to the browser, compiled by the JavaScript bootstrapper into the client evaluator, and rendered into DOM. At every stage, it is " (code "~card") ". At no single stage is it " (em "the") " " (code "~card") ". The identity is the pattern, not the substrate.")
(p :class "text-stone-600"
"Most frameworks bind component identity to a substrate. A React component is a JavaScript function. Full stop. It cannot exist outside the JavaScript runtime. Its identity is its implementation. SX components have substrate independence — the same definition runs on any host that implements the SX platform interface. The component's identity is its specification, not its execution."))
(~doc-section :title "VI. Competence without comprehension" :id "competence"
(p :class "text-stone-600"
"Dennett argued in " (a :href "https://en.wikipedia.org/wiki/From_Bacteria_to_Bach_and_Back" :class "text-violet-600 hover:underline" "From Bacteria to Bach and Back") " (2017) that evolution produces " (em "competence without comprehension") ". Termites build elaborate mounds without understanding architecture. Neurons produce consciousness without understanding thought. The competence is real — the mound regulates temperature, the brain solves problems — but there is no comprehension anywhere in the system. No termite has a blueprint. No neuron knows it is thinking.")
(p :class "text-stone-600"
"A macro is competence without comprehension. " (code "defcomp") " expands into a component registration — it " (em "does") " the right thing — but it does not \"know\" what a component is. It is a pattern-matching function on lists that produces other lists. The expansion is mechanical, local, uncomprehending. Yet the result is a fully functional component that participates in the rendering pipeline, responds to props, composes with other components. Competence. No comprehension.")
(~doc-code :lang "lisp" :code
";; defcomp is a macro — mechanical list transformation\n(defmacro defcomp (name params &rest body)\n `(define ,name (make-component ,params ,@body)))\n\n;; It does not \"understand\" components.\n;; It rearranges symbols according to a rule.\n;; The resulting component works perfectly.\n;; Competence without comprehension.")
(p :class "text-stone-600"
"The bootstrap compiler is another level of the same phenomenon. " (code "bootstrap_js.py") " reads " (code "eval.sx") " and emits JavaScript. It does not understand SX semantics — it applies mechanical transformation rules to s-expression ASTs. Yet its output is a correct, complete SX evaluator. The compiler is competent (it produces working code) without being comprehending (it has no model of what SX expressions mean).")
(p :class "text-stone-600"
"Dennett used this insight to deflate the mystery of intelligence: you do not need a homunculus — a little man inside the machine who \"really\" understands — you just need enough competence at each level. SX embodies this architecturally. No part of the system comprehends the whole. The parser does not know about rendering. The evaluator does not know about HTTP. The bootstrap compiler does not know about the DOM. Each part is a competent specialist. The system works because the parts compose, not because any part understands the composition."))
(~doc-section :title "VII. Intuition pumps" :id "intuition-pumps"
(p :class "text-stone-600"
"Dennett called his thought experiments \"" (a :href "https://en.wikipedia.org/wiki/Intuition_pump" :class "text-violet-600 hover:underline" "intuition pumps") "\" — devices for moving your intuitions from one place to another, making the unfamiliar familiar by analogy. Not proofs. Not arguments. Machines for changing how you see.")
(p :class "text-stone-600"
"SX components are intuition pumps. A " (code "defcomp") " definition is not just executable code — it is a device for showing someone what a piece of UI " (em "is") ". Reading " (code "(defcomp ~card (&key title &rest children) (div :class \"card\" (h2 title) children))") " tells you the contract, the structure, and the output in a single expression. It pumps your intuition about what \"card\" means in this application.")
(p :class "text-stone-600"
"Compare this to a React component:")
(~doc-code :lang "lisp" :code
";; React: you must simulate the runtime in your head\nfunction Card({ title, children }) {\n return (\n <div className=\"card\">\n <h2>{title}</h2>\n {children}\n </div>\n );\n}\n\n;; SX: the definition IS the output\n(defcomp ~card (&key title &rest children)\n (div :class \"card\"\n (h2 title)\n children))")
(p :class "text-stone-600"
"The React version requires you to know that JSX compiles to createElement calls, that className maps to the class attribute, that curly braces switch to JavaScript expressions, and that the function return value becomes the rendered output. You must simulate a compiler in your head. The SX version requires you to know that lists are expressions and keywords are attributes. The gap between the definition and what it produces is smaller. The intuition pump is more efficient — fewer moving parts, less machinery between the reader and the meaning.")
(p :class "text-stone-600"
"Dennett valued intuition pumps because philosophy is full of false intuitions. The Cartesian theater feels right — of course there is a place where consciousness happens. But it is wrong. Intuition pumps help you " (em "see") " that it is wrong by giving you a better picture. SX is an intuition pump for web development: of course you need a build step, of course you need a virtual DOM, of course you need separate languages for structure and style and behaviour. But you don't. The s-expression is the better picture."))
(~doc-section :title "VIII. The Joycean machine" :id "joycean-machine"
(p :class "text-stone-600"
"In Consciousness Explained, Dennett describes the brain as a \"" (a :href "https://en.wikipedia.org/wiki/Consciousness_Explained" :class "text-violet-600 hover:underline" "Joycean machine") "\" — a virtual machine running on the parallel hardware of the brain, producing the serial narrative of conscious experience. Just as a word processor is a virtual machine running on silicon, consciousness is a virtual machine running on neurons. The virtual machine is real — it does real work, produces real effects — even though it is implemented in a substrate that knows nothing about it.")
(p :class "text-stone-600"
"SX is a Joycean machine running on the web. The web's substrate — TCP/IP, HTTP, the DOM, JavaScript engines — knows nothing about s-expressions, components, or evaluators. Yet the SX virtual machine runs on this substrate, producing real pages, real interactions, real applications. The substrate provides the physical-stance machinery. SX provides the intentional-stance narrative: this is a card, this is a page, this is a layout, this composes with that.")
(p :class "text-stone-600"
"The deeper parallel: Dennett argued that the Joycean machine is " (em "not an illusion") ". The serial narrative of consciousness is not fake — it is the real output of real processing, even though the underlying hardware is parallel and narrativeless. Similarly, SX's component model is not a convenient fiction layered over \"real\" HTML. It is the real structure of the application. The components are the thing. The HTML is the substrate, not the reality.")
(p :class "text-stone-600"
"And like Dennett's Joycean machine, SX's virtual machine can reflect on itself. It can inspect its own running code, define its own evaluator, test its own semantics. The virtual machine is aware of itself — not in the sense of consciousness, but in the functional sense of self-modelling. The spec models the evaluator. The evaluator runs the spec. The virtual machine contains a description of itself, and that description works."))
(~doc-section :title "IX. Quining" :id "quining"
(p :class "text-stone-600"
"Dennett borrowed the term \"" (a :href "https://en.wikipedia.org/wiki/Qualia#Dennett's_criticism" :class "text-violet-600 hover:underline" "quining") "\" from the logician " (a :href "https://en.wikipedia.org/wiki/Willard_Van_Orman_Quine" :class "text-violet-600 hover:underline" "W. V. O. Quine") " — a philosopher who argued that many seemingly deep concepts dissolve under scrutiny. Dennett \"quined\" qualia — the supposedly irreducible subjective qualities of experience — arguing that they are not what they seem, that the intuition of an inner experiential essence is a philosophical illusion.")
(p :class "text-stone-600"
"The concept of a \"" (a :href "https://en.wikipedia.org/wiki/Quine_(computing)" :class "text-violet-600 hover:underline" "quine") "\" in computing is related: a program that outputs its own source code. The word honours the same Quine, for the same reason — self-reference that collapses the distinction between describer and described.")
(p :class "text-stone-600"
"SX quines in both senses. In the computing sense: the self-hosting spec is a quine-like structure — " (code "eval.sx") " is an SX program that, when compiled and run, produces an evaluator capable of running " (code "eval.sx") ". It is not a literal quine (it doesn't output itself character-for-character), but it has the essential quine property: the output contains the input.")
(p :class "text-stone-600"
"In Dennett's philosophical sense: SX quines the web's qualia. The supposedly irreducible essences of web development — \"components,\" \"state,\" \"the DOM,\" \"the server-client boundary\" — dissolve under SX's scrutiny into what they always were: data structures. Lists of symbols. Expressions that evaluate to other expressions. The qualia of web development are not irreducible. They are patterns in s-expressions, and once you see that, you cannot unsee it.")
(p :class "text-stone-600"
"Dennett's lifelong project was to show that the mind is not what our intuitions say it is — that consciousness, free will, and the self are real phenomena that do not require the metaphysical foundations we instinctively assign them. They are " (a :href "https://en.wikipedia.org/wiki/Real_Patterns" :class "text-violet-600 hover:underline" "real patterns") " in physical processes, not ghostly essences hovering above matter.")
(p :class "text-stone-600"
"SX makes the same move for the web. Components are real patterns, not framework essences. The server-client boundary is a draft boundary, not an ontological divide. The build step is a habit, not a necessity. The virtual DOM is a Cartesian theater, not a requirement. Strip away the false intuitions, and what remains is what was always there: expressions, evaluation, and composition. All the way down."))))
(defcomp ~essay-s-existentialism ()
(~doc-page :title "S-Existentialism"
(p :class "text-stone-500 text-sm italic mb-8"
"Existence precedes essence — and s-expressions exist before anything gives them meaning.")
(~doc-section :title "I. Existence precedes essence" :id "existence-precedes-essence"
(p :class "text-stone-600"
"In 1946, Jean-Paul " (a :href "https://en.wikipedia.org/wiki/Jean-Paul_Sartre" :class "text-violet-600 hover:underline" "Sartre") " gave a lecture called \"" (a :href "https://en.wikipedia.org/wiki/Existentialism_Is_a_Humanism" :class "text-violet-600 hover:underline" "Existentialism Is a Humanism") ".\" Its central claim: " (em "existence precedes essence") ". A paper knife is designed before it exists — someone conceives its purpose, then builds it. A human being is the opposite — we exist first, then define ourselves through our choices. There is no blueprint. There is no human nature that precedes the individual human.")
(p :class "text-stone-600"
"A React component is a paper knife. Its essence precedes its existence. Before a single line of JSX runs, React has decided what a component is: a function that returns elements, governed by the rules of hooks, reconciled by a virtual DOM, managed by a scheduler. The framework defines the essence. The developer fills in the blanks. You exist within React's concept of you.")
(p :class "text-stone-600"
"An s-expression exists before any essence is assigned to it. " (code "(div :class \"card\" (h2 title))") " is a list. That is all it is. It has no inherent meaning. It is not a component, not a template, not a function call — not yet. It is raw existence: a nested structure of symbols, keywords, and other lists, waiting.")
(p :class "text-stone-600"
"The evaluator gives it essence. " (code "render-to-html") " makes it HTML. " (code "render-to-dom") " makes it DOM nodes. " (code "aser") " makes it wire format. " (code "quote") " keeps it as data. The same expression, the same existence, can receive different essences depending on what acts on it. The expression does not know what it is. It becomes what it is used for.")
(~doc-code :lang "lisp" :code
";; The same existence, different essences:\n(define expr '(div :class \"card\" (h2 \"Hello\")))\n\n(render-to-html expr) ;; → <div class=\"card\"><h2>Hello</h2></div>\n(render-to-dom expr) ;; → [DOM Element]\n(aser expr) ;; → (div :class \"card\" (h2 \"Hello\"))\n(length expr) ;; → 4 (it's just a list)\n\n;; The expression existed before any of these.\n;; It has no essence until you give it one."))
(~doc-section :title "II. Condemned to be free" :id "condemned"
(p :class "text-stone-600"
"\"Man is condemned to be free,\" Sartre wrote in " (a :href "https://en.wikipedia.org/wiki/Being_and_Nothingness" :class "text-violet-600 hover:underline" "Being and Nothingness") ". Not free as a gift. Free as a sentence. You did not choose to be free. You cannot escape it. Every attempt to deny your freedom — by deferring to authority, convention, or nature — is " (a :href "https://en.wikipedia.org/wiki/Bad_faith_(existentialism)" :class "text-violet-600 hover:underline" "bad faith") ". You are responsible for everything you make of yourself, and the weight of that responsibility is the human condition.")
(p :class "text-stone-600"
"SX condemns you to be free. There is no framework telling you how to structure your application. No router mandating your URL patterns. No state management library imposing its model. No convention-over-configuration file tree that decides where your code goes. You have a parser, an evaluator, and fifty primitives. What you build is your responsibility.")
(p :class "text-stone-600"
"React developers are not free. They are told: components must be pure. State changes must go through hooks. Side effects must live in useEffect. The render cycle must not be interrupted. These are the commandments. Obey them and the framework rewards you with a working application. Disobey them and the framework punishes you with cryptic errors. This is not freedom. This is " (a :href "https://en.wikipedia.org/wiki/Fear_and_Trembling" :class "text-violet-600 hover:underline" "Kierkegaard's") " knight of faith, submitting to the absurd authority of the framework because the alternative — thinking for yourself — is terrifying.")
(p :class "text-stone-600"
"The SX developer has no commandments. " (code "defcomp") " is a suggestion, not a requirement — you can build components with raw lambdas if you prefer. " (code "defmacro") " gives you the power to reshape the language itself. There are no rules of hooks because there are no hooks. There are no lifecycle methods because there is no lifecycle. There is only evaluation: an expression goes in, a value comes out. What the expression contains, how the value is used — that is up to you.")
(p :class "text-stone-600"
"This is not comfortable. Freedom never is. Sartre did not say freedom was pleasant. He said it was inescapable."))
(~doc-section :title "III. Bad faith" :id "bad-faith"
(p :class "text-stone-600"
(a :href "https://en.wikipedia.org/wiki/Bad_faith_(existentialism)" :class "text-violet-600 hover:underline" "Bad faith") " is Sartre's term for the lie you tell yourself to escape freedom. The waiter who plays at being a waiter — performing the role so thoroughly that he forgets he chose it. The woman who pretends not to notice a man's intentions — denying her own awareness to avoid making a decision. Bad faith is not deception of others. It is self-deception about one's own freedom.")
(p :class "text-stone-600"
"\"We have to use React — it's the industry standard.\" Bad faith. You chose React. The industry did not force it on you. There were alternatives. You preferred the comfort of the herd.")
(p :class "text-stone-600"
"\"We need TypeScript — you can't write reliable code without a type system.\" Bad faith. " (a :href "https://en.wikipedia.org/wiki/Lisp_(programming_language)" :class "text-violet-600 hover:underline" "Lisp") " has been writing reliable code without static types since 1958. " (a :href "https://en.wikipedia.org/wiki/Erlang_(programming_language)" :class "text-violet-600 hover:underline" "Erlang") " runs telephone networks on dynamic types. You chose TypeScript because you are afraid of your own code, and the type system is a security blanket.")
(p :class "text-stone-600"
"\"We need a build step — modern web development requires it.\" Bad faith. A " (code "<script>") " tag requires no build step. An s-expression evaluator in 3,000 lines of JavaScript requires no build step. You need a build step because you chose tools that require a build step, and now you have forgotten that the choice was yours.")
(p :class "text-stone-600"
"\"Nobody uses s-expressions for web development.\" Bad faith. " (em "You") " do not use s-expressions for web development. That is a fact about you, not a fact about web development. Transforming your personal preference into a universal law is the quintessential act of bad faith.")
(p :class "text-stone-600"
"SX does not prevent bad faith — nothing can. But it makes bad faith harder. When the entire language is fifty primitives and a page of special forms, you cannot pretend that the complexity is necessary. When there is no build step, you cannot pretend that the build step is inevitable. When the same source runs on server and client, you cannot pretend that the server-client divide is ontological. SX strips away the excuses. What remains is your choices."))
(~doc-section :title "IV. Nausea" :id "nausea"
(p :class "text-stone-600"
"In " (a :href "https://en.wikipedia.org/wiki/Nausea_(novel)" :class "text-violet-600 hover:underline" "Nausea") " (1938), Sartre's Roquentin sits in a park and stares at the root of a chestnut tree. He sees it — really sees it — stripped of all the concepts and categories that normally make it comprehensible. It is not a \"root.\" It is not \"brown.\" It is not \"gnarled.\" It simply " (em "is") " — a brute, opaque, superfluous existence. The nausea is the vertigo of confronting existence without essence.")
(p :class "text-stone-600"
"Open " (code "node_modules") ". Stare at it. 47,000 directories. 1.2 gigabytes. For a to-do app. Each directory contains a " (code "package.json") ", a " (code "README.md") ", a " (code "LICENSE") ", and some JavaScript that wraps some other JavaScript that wraps some other JavaScript. There is no reason for any of it. It is not necessary. It is not justified. It simply accumulated — dependency after dependency, version after version, a brute, opaque, superfluous existence. This is " (code "node_modules") " nausea.")
(p :class "text-stone-600"
"SX has its own nausea. Stare at a page of s-expressions long enough and the same vertigo hits. Parentheses. Symbols. Lists inside lists inside lists. There is nothing behind them — no hidden runtime, no compiled intermediate form, no framework magic. Just parentheses. The s-expression is Roquentin's chestnut root: it simply " (em "is") ". You cannot unsee it.")
(p :class "text-stone-600"
"But SX's nausea is honest. The chestnut root is really there — it exists, bare and exposed. The " (code "node_modules") " nausea is different: it is nausea at something that should not exist, that has no reason to exist, that exists only because of accumulated accidents of dependency resolution. SX's nausea is existential — the dizziness of confronting raw structure. The JavaScript ecosystem's nausea is absurd — the dizziness of confronting unnecessary complexity that no one chose but everyone maintains."))
(~doc-section :title "V. The absurd" :id "absurd"
(p :class "text-stone-600"
(a :href "https://en.wikipedia.org/wiki/Albert_Camus" :class "text-violet-600 hover:underline" "Camus") " defined the " (a :href "https://en.wikipedia.org/wiki/Absurdism" :class "text-violet-600 hover:underline" "absurd") " as the gap between human longing for meaning and the universe's silence. We want the world to make sense. It does not. The absurd is not in us or in the world — it is in the confrontation between the two.")
(p :class "text-stone-600"
"Web development is absurd. We want simple, composable, maintainable software. The industry gives us webpack configurations, framework migrations, and breaking changes in minor versions. We want to write code and run it. The industry gives us transpilers, bundlers, minifiers, tree-shakers, and hot-module-replacers. The gap between what we want and what we get is the absurd.")
(p :class "text-stone-600"
"Writing a Lisp for the web is also absurd — but in a different register. Nobody asked for it. Nobody wants it. The parentheses are off-putting. The ecosystem is nonexistent. The job market is zero. There is no rational justification for building SX when React exists, when Vue exists, when Svelte exists, when the entire weight of the industry points in the other direction.")
(p :class "text-stone-600"
"Camus said there are three responses to the absurd. " (a :href "https://en.wikipedia.org/wiki/The_Myth_of_Sisyphus" :class "text-violet-600 hover:underline" "Suicide") " — giving up. " (a :href "https://en.wikipedia.org/wiki/Leap_of_faith" :class "text-violet-600 hover:underline" "Philosophical suicide") " — leaping into faith, pretending the absurd has been resolved. Or " (em "revolt") " — continuing without resolution, fully aware that the project is meaningless, and doing it anyway.")
(p :class "text-stone-600"
"Most developers commit philosophical suicide. They adopt a framework, declare it The Way, and stop questioning. React is the truth. TypeScript is salvation. The build step is destiny. The absurd disappears — not because it has been resolved, but because they have stopped looking at it.")
(p :class "text-stone-600"
"SX is revolt. It does not resolve the absurd. It does not pretend that s-expressions are the answer, that parentheses will save the web, that the industry will come around. It simply continues — writing components, specifying evaluators, bootstrapping to new targets — with full awareness that the project may never matter to anyone. This is the only honest response to the absurd."))
(~doc-section :title "VI. Sisyphus" :id "sisyphus"
(p :class "text-stone-600"
"\"" (a :href "https://en.wikipedia.org/wiki/The_Myth_of_Sisyphus" :class "text-violet-600 hover:underline" "One must imagine Sisyphus happy") ".\"")
(p :class "text-stone-600"
"Sisyphus pushes a boulder up a hill. It rolls back down. He pushes it up again. Forever. Camus argues that Sisyphus is the absurd hero: he knows the task is pointless, he does it anyway, and in the doing — in the conscious confrontation with futility — he finds something that transcends the futility.")
(p :class "text-stone-600"
"The framework developer is Sisyphus too, but an unconscious one. React 16 to 17 to 18. Class components to hooks to server components. Each migration is the boulder. Each major version is the hill. The developer pushes the codebase up, and the next release rolls it back down. But the framework developer does not " (em "know") " they are Sisyphus. They believe each migration is progress. They believe the boulder will stay at the top this time. This is philosophical suicide — the leap of faith that the next version will be the last.")
(p :class "text-stone-600"
"The SX developer is conscious Sisyphus. The boulder is obvious: writing a Lisp for the web is absurd. The hill is obvious: nobody will use it. But consciousness changes everything. Camus's Sisyphus is happy not because the task has meaning but because " (em "he") " has chosen it. The choice — the revolt — is the meaning. Not the outcome.")
(p :class "text-stone-600"
"One must imagine the s-expressionist happy."))
(~doc-section :title "VII. Thrownness" :id "thrownness"
(p :class "text-stone-600"
(a :href "https://en.wikipedia.org/wiki/Martin_Heidegger" :class "text-violet-600 hover:underline" "Heidegger's") " " (a :href "https://en.wikipedia.org/wiki/Thrownness" :class "text-violet-600 hover:underline" "Geworfenheit") " — thrownness — describes the condition of finding yourself already in a world you did not choose. You did not pick your language, your culture, your body, your historical moment. You were " (em "thrown") " into them. Authenticity is not escaping thrownness but owning it — relating to your situation as yours, rather than pretending it was inevitable or that you could have been elsewhere.")
(p :class "text-stone-600"
"SX is thrown into the web. It did not choose HTTP, the DOM, CSS, JavaScript engines, or browser security models. These are the givens — the facticity of web development. Every web technology is thrown into this same world. The question is how you relate to it.")
(p :class "text-stone-600"
"React relates to the DOM by replacing it — the virtual DOM is a denial of thrownness, an attempt to build a world that is not the one you were thrown into, then reconcile the two. Angular relates to JavaScript by replacing it — TypeScript, decorators, dependency injection, a whole parallel universe layered over the given one. These are inauthentic responses to thrownness: instead of owning the situation, they construct an alternative and pretend it is the real one.")
(p :class "text-stone-600"
"SX owns its thrownness. It runs in the browser's JavaScript engine — not because JavaScript is good, but because the browser is the world it was thrown into. It produces DOM nodes — not because the DOM is elegant, but because the DOM is what exists. It sends HTTP responses — not because HTTP is ideal, but because HTTP is the wire. SX does not build a virtual DOM to escape the real DOM. It does not invent a type system to escape JavaScript's types. It evaluates s-expressions in the given environment and produces what the environment requires.")
(p :class "text-stone-600"
"The s-expression is itself a kind of primordial thrownness. It did not choose to be the minimal recursive data structure. It simply is. Open paren, atoms, close paren. It was not designed by committee, not optimised by industry, not evolved through market pressure. It was " (a :href "https://en.wikipedia.org/wiki/Lisp_(programming_language)#History" :class "text-violet-600 hover:underline" "discovered in 1958") " as a notational convenience and turned out to be the bedrock. SX was thrown into s-expressions the way humans are thrown into bodies — not by choice, but by the nature of what it is."))
(~doc-section :title "VIII. The Other" :id "the-other"
(p :class "text-stone-600"
"Sartre's account of " (a :href "https://en.wikipedia.org/wiki/Being_and_Nothingness#The_Other_and_the_Look" :class "text-violet-600 hover:underline" "the Other") " in Being and Nothingness: I am alone in a park. I am the centre of my world. Then I see another person. Suddenly I am seen. I am no longer just a subject — I am an object in someone else's world. The Other's gaze transforms me. \"Hell is other people,\" Sartre wrote in " (a :href "https://en.wikipedia.org/wiki/No_Exit" :class "text-violet-600 hover:underline" "No Exit") " — not because others are cruel, but because they see you, and their seeing limits your freedom to define yourself.")
(p :class "text-stone-600"
"Every framework exists under the gaze of the Other. React watches what Vue does. Vue watches what Svelte does. Svelte watches what Solid does. Each framework defines itself partly through the Other — \"we are not React,\" \"we are faster than Vue,\" \"we are simpler than Angular.\" The benchmark is the Other. The identity is relational. No framework is free to be purely itself, because the Others are always watching.")
(p :class "text-stone-600"
"SX has no Other. There is no competing s-expression web framework to define itself against. There is no benchmark to win, no market to capture, no conference talk to rebut. This is either pathetic (no ecosystem, no community, no relevance) or liberating (no gaze, no comparison, no borrowed identity). Sartre would say it is both.")
(p :class "text-stone-600"
"But there is another sense of the Other that matters more. The Other " (em "evaluator") ". SX's self-hosting spec means that the language encounters itself as Other. " (code "eval.sx") " is written in SX — the language looking at itself, seeing itself from outside. The bootstrap compiler reads this self-description and produces a working evaluator. The language has been seen by its own gaze, and the seeing has made it real. This is Sartre's intersubjectivity turned reflexive: the subject and the Other are the same entity."))
(~doc-section :title "IX. Authenticity" :id "authenticity"
(p :class "text-stone-600"
"For both Heidegger and Sartre, " (a :href "https://en.wikipedia.org/wiki/Authenticity_(philosophy)" :class "text-violet-600 hover:underline" "authenticity") " means facing your situation — your freedom, your thrownness, your mortality — without evasion. The inauthentic person hides in the crowd, adopts the crowd's values, speaks the crowd's language. Heidegger called this " (a :href "https://en.wikipedia.org/wiki/Heideggerian_terminology#Das_Man" :class "text-violet-600 hover:underline" "das Man") " — the \"They.\" \"They say React is best.\" \"They use TypeScript.\" \"They have build steps.\" The They is not a conspiracy. It is the comfortable anonymity of doing what everyone does.")
(p :class "text-stone-600"
"Authenticity in web development would mean confronting what you are actually doing: arranging symbols so that a machine produces visual output. That is all web development is. Not \"building products.\" Not \"crafting experiences.\" Not \"shipping value.\" Arranging symbols. The frameworks, the methodologies, the Agile ceremonies — all of it is das Man, the They, the comfortable obfuscation of a simple truth.")
(p :class "text-stone-600"
"SX is more authentic than most — not because s-expressions are morally superior, but because they are harder to hide behind. There is no CLI that generates boilerplate. No convention that tells you where files go. No community consensus on the Right Way. You write expressions. You evaluate them. You see what they produce. The gap between what you do and what happens is as small as it can be.")
(p :class "text-stone-600"
"De Beauvoir added something Sartre did not: authenticity requires that you " (a :href "https://en.wikipedia.org/wiki/The_Ethics_of_Ambiguity" :class "text-violet-600 hover:underline" "will the freedom of others") ", not just your own. A language that locks you into one runtime, one vendor, one ecosystem is inauthentic — it denies others the freedom it claims for itself. SX's self-hosting spec is an act of de Beauvoirian ethics: by defining the language in itself, in a format that any reader can parse, any compiler can target, any host can implement, it wills the freedom of every future evaluator. The spec is public. The language is portable. Your freedom to re-implement, to fork, to understand — that freedom is not a side effect. It is the point.")
(p :class "text-stone-600"
"Existence precedes essence. The s-expression exists — bare, parenthesised, indifferent — before any evaluator gives it meaning. What it becomes is up to you. This is not a limitation. It is the only freedom there is."))))
(defcomp ~essays-index-content ()
(~doc-page :title "Essays"
(div :class "space-y-4"
@@ -114,7 +445,7 @@
(p :class "text-stone-600"
"A macro is a function that takes code and returns code. An AI generating macros is writing programs that write programs. With " (code "eval") ", those generated programs can generate more programs at runtime. This is not a metaphor — it is the literal mechanism.")
(p :class "text-stone-600"
"The " (a :href "/essays/godel-escher-bach" :class "text-violet-600 hover:underline" "Gödel numbering") " parallel is not incidental. " (a :href "https://en.wikipedia.org/wiki/Kurt_G%C3%B6del" :class "text-violet-600 hover:underline" "Gödel") " showed that any sufficiently powerful formal system can encode statements about itself. A complete Lisp on the wire is a sufficiently powerful formal system. The web can make statements about itself — components that inspect other components, macros that rewrite the page structure, expressions that generate new expressions based on the current state of the system.")
"The " (a :href "/philosophy/godel-escher-bach" :class "text-violet-600 hover:underline" "Gödel numbering") " parallel is not incidental. " (a :href "https://en.wikipedia.org/wiki/Kurt_G%C3%B6del" :class "text-violet-600 hover:underline" "Gödel") " showed that any sufficiently powerful formal system can encode statements about itself. A complete Lisp on the wire is a sufficiently powerful formal system. The web can make statements about itself — components that inspect other components, macros that rewrite the page structure, expressions that generate new expressions based on the current state of the system.")
(p :class "text-stone-600"
"Consider what this enables for AI:")
(ul :class "space-y-2 text-stone-600 mt-2"

View File

@@ -13,6 +13,7 @@
(dict :label "Protocols" :href "/protocols/wire-format")
(dict :label "Examples" :href "/examples/click-to-load")
(dict :label "Essays" :href "/essays/")
(dict :label "Philosophy" :href "/philosophy/")
(dict :label "Specs" :href "/specs/")
(dict :label "Bootstrappers" :href "/bootstrappers/")
(dict :label "Testing" :href "/testing/")

View File

@@ -74,14 +74,10 @@
:summary "Reactive UI updates without a virtual DOM, diffing library, or build step.")
(dict :label "SX Native" :href "/essays/sx-native"
:summary "Extending SX beyond the browser — native desktop and mobile rendering from the same source.")
(dict :label "The SX Manifesto" :href "/essays/sx-manifesto"
:summary "The design principles behind SX: simplicity, self-hosting, and s-expressions all the way down.")
(dict :label "Tail-Call Optimization" :href "/essays/tail-call-optimization"
:summary "How SX implements proper tail calls via trampolining in a language that doesn't have them.")
(dict :label "Continuations" :href "/essays/continuations"
:summary "First-class continuations in a tree-walking evaluator — theory and implementation.")
(dict :label "Strange Loops" :href "/essays/godel-escher-bach"
:summary "Self-reference, and the tangled hierarchy of a language that defines itself.")
(dict :label "The Reflexive Web" :href "/essays/reflexive-web"
:summary "A web where pages can inspect, modify, and extend their own rendering pipeline.")
(dict :label "Server Architecture" :href "/essays/server-architecture"
@@ -97,6 +93,18 @@
(dict :label "Tools for Fools" :href "/essays/zero-tooling"
:summary "SX was built without a code editor. No IDE, no build tools, no linters, no bundlers. What zero-tooling web development looks like.")))
(define philosophy-nav-items (list
(dict :label "The SX Manifesto" :href "/philosophy/sx-manifesto"
:summary "The design principles behind SX: simplicity, self-hosting, and s-expressions all the way down.")
(dict :label "Strange Loops" :href "/philosophy/godel-escher-bach"
:summary "Self-reference, and the tangled hierarchy of a language that defines itself.")
(dict :label "SX and Wittgenstein" :href "/philosophy/wittgenstein"
:summary "The limits of my language are the limits of my world — Wittgenstein's philosophy and what it means for SX.")
(dict :label "SX and Dennett" :href "/philosophy/dennett"
:summary "Real patterns, intentional stance, and multiple drafts — Dennett's philosophy of mind as a framework for understanding SX.")
(dict :label "S-Existentialism" :href "/philosophy/existentialism"
:summary "Existence precedes essence — Sartre, Camus, and the absurd freedom of writing a Lisp for the web.")))
(define specs-nav-items (list
(dict :label "Architecture" :href "/specs/")
(dict :label "Core" :href "/specs/core")

View File

@@ -274,10 +274,8 @@
"on-demand-css" (~essay-on-demand-css)
"client-reactivity" (~essay-client-reactivity)
"sx-native" (~essay-sx-native)
"sx-manifesto" (~essay-sx-manifesto)
"tail-call-optimization" (~essay-tail-call-optimization)
"continuations" (~essay-continuations)
"godel-escher-bach" (~essay-godel-escher-bach)
"reflexive-web" (~essay-reflexive-web)
"server-architecture" (~essay-server-architecture)
"separation-of-concerns" (~essay-separation-of-concerns)
@@ -286,6 +284,39 @@
"zero-tooling" (~essay-zero-tooling)
:else (~essays-index-content)))
;; ---------------------------------------------------------------------------
;; Philosophy section
;; ---------------------------------------------------------------------------
(defpage philosophy-index
:path "/philosophy/"
:auth :public
:layout (:sx-section
:section "Philosophy"
:sub-label "Philosophy"
:sub-href "/philosophy/"
:sub-nav (~section-nav :items philosophy-nav-items :current "")
:selected "")
:content (~philosophy-index-content))
(defpage philosophy-page
:path "/philosophy/<slug>"
:auth :public
:layout (:sx-section
:section "Philosophy"
:sub-label "Philosophy"
:sub-href "/philosophy/"
:sub-nav (~section-nav :items philosophy-nav-items
:current (find-current philosophy-nav-items slug))
:selected (or (find-current philosophy-nav-items slug) ""))
:content (case slug
"sx-manifesto" (~essay-sx-manifesto)
"godel-escher-bach" (~essay-godel-escher-bach)
"wittgenstein" (~essay-sx-and-wittgenstein)
"dennett" (~essay-sx-and-dennett)
"existentialism" (~essay-s-existentialism)
:else (~philosophy-index-content)))
;; ---------------------------------------------------------------------------
;; CSSX section
;; ---------------------------------------------------------------------------