diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/AnalysisService/AnalysisService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/AnalysisService/AnalysisService.md
new file mode 100644
index 000000000..60c9ac8a7
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/AnalysisService/AnalysisService.md
@@ -0,0 +1,5 @@
+---
+title: Analysis Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/BuildService/BuildService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/BuildService/BuildService.md
new file mode 100644
index 000000000..ba605bf9b
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/BuildService/BuildService.md
@@ -0,0 +1,5 @@
+---
+title: Build Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/CallHierarchyService/CallHierarchyService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CallHierarchyService/CallHierarchyService.md
new file mode 100644
index 000000000..a2d6fa57f
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CallHierarchyService/CallHierarchyService.md
@@ -0,0 +1,5 @@
+---
+title: Call Hierarchy Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeActionService/CodeActionService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeActionService/CodeActionService.md
new file mode 100644
index 000000000..52a048fee
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeActionService/CodeActionService.md
@@ -0,0 +1,5 @@
+---
+title: Code Action Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeLensService/CodeLensService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeLensService/CodeLensService.md
new file mode 100644
index 000000000..36834b476
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/CodeLensService/CodeLensService.md
@@ -0,0 +1,5 @@
+---
+title: Code Lens Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/DefinitionService/DefinitionService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/DefinitionService/DefinitionService.md
new file mode 100644
index 000000000..9ff13328c
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/DefinitionService/DefinitionService.md
@@ -0,0 +1,5 @@
+---
+title: Definition Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/DocumentSymbolService/DocumentSymbolService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/DocumentSymbolService/DocumentSymbolService.md
new file mode 100644
index 000000000..7bf370a42
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/DocumentSymbolService/DocumentSymbolService.md
@@ -0,0 +1,5 @@
+---
+title: Document Symbol Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/ExecutionService/ExecutionService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ExecutionService/ExecutionService.md
new file mode 100644
index 000000000..e51cc304b
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ExecutionService/ExecutionService.md
@@ -0,0 +1,5 @@
+---
+title: Execution Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/HoverService/HoverService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/HoverService/HoverService.md
new file mode 100644
index 000000000..11a97f542
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/HoverService/HoverService.md
@@ -0,0 +1,5 @@
+---
+title: Hover Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/ImplementationService/ImplementationService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ImplementationService/ImplementationService.md
new file mode 100644
index 000000000..7cc809307
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ImplementationService/ImplementationService.md
@@ -0,0 +1,5 @@
+---
+title: Implementation Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/InlayHintService/InlayHintService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/InlayHintService/InlayHintService.md
new file mode 100644
index 000000000..b7b28fddd
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/InlayHintService/InlayHintService.md
@@ -0,0 +1,5 @@
+---
+title: Inlay Hint Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md
new file mode 100644
index 000000000..e3ead2524
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/LanguageServerProtocol.md
@@ -0,0 +1,65 @@
+---
+title: "VScode and the Language Server Protocol"
+keywords:
+ - LSP
+ - VScode
+ - "Visual Studio Code"
+ - "Language Server Protocol"
+---
+
+#### Synopsis
+
+Recipes for creating an IDE for your language based on the Language Server Protocol using ((util::LanguageServer)) and ((util::IDEServices))
+
+#### Syntax
+
+#### Types
+
+#### Function
+
+#### Description
+
+Rascal's VScode extension comes with a high-level [Language Server Protocol API]((org.rascalmpl.rascal-lsp)) builtin. The library module ((util::LanguageServer)) can be used to rapidly develop an IDE for your own domain specific language or programming language.
+
+You can work in small steps:
+1. First create a ((ParsingService)) and then ((RegisterYourLanguage)). This gives your users:
+ * ((SyntaxHighlighting)) which can be further [configured]((SyntaxHighlighting)).
+ * Parse error diagnostics and/or error recovery (see ((ParsingService)))
+2. Then you can **optionally** and **independently** add editor services one-by-one:
+ * the ((SelectionRangeService)) provides an easy and quick way to select the right pieces of DSL code for the user.
+ * the ((DocumentSymbolService)) provides a linked outline view and symbol based search in the editor.
+ * the ((HoverService)) provides quick (on-demand) documentation in the editor with a tooltip. See also later ((AnalysisService)) and ((BuildService)) for pre-computing documentation information.
+ * the ((ReferencesSevice)) and
+ * ((DefinitionService)) and
+ * ((ImplementationService)) provide quick (on-demand) links to either all references, all definitions of a symbol, or all implementations of a symbol in the editor (with a hyperlink). See also later ((AnalysisService)) and ((BuildService)) for pre-computing reference, definition and implementation information.
+ * the ((AnalysisService)) services provides errors and warnings for the user as diagnostics in the IDE (e.g. type checking), while the user is typing in the editor.
+ * the ((BuildService)) triggers a compiler or another language processor. It also produces errors and warnings for the user, but only when a file has been saved.
+ * ((ExecutionService)) provides an execution mechanism for your own editor commands that can be triggered by the user:
+ * Using ((AnalysisService)) or ((BuildService)) you can attach them to error messages to provide _quick fixes_.
+ * Using ((CodeLensService)) or ((InlayHintService)) which both provides information "in between the lines" of your DSL code, which actionable hyperlinks to your ((ExecutionService)) commands.
+ * Using ((CodeActionService)) which provides a low-key lightbulb menu of context-specific actions (like quick-fixes and refactoring)
+ * ((CallHierarchyService)) provides an on-demand, lazy browser for the "call graph" of a PL or DSL.
+ * ((RenameService)) offers language-specific renaming to your users.
+
+So start with the ((ParsingService)) and ((RegisterYourLanguage)), then pick which IDE feature you'd like to provide to your users first, and just go with that.
+
+#### Examples
+
+#### Benefits
+
+* There are only two small API modules relevant for constructing full featured IDEs:
+ * ((util::LanguageServer)) for building an LSP server that connects to the VScode client.
+ * ((util::IDEServices)) for programmatically calling IDE effects (like opening editors and starting web views).
+* There is no need for a "second level" (starting up another VS code instance) to test your new extension. All you need is to ((RegisterYourLanguage)) and your language will be added to your IDE here and now.
+* Your services code "sees" always the code that the user sees in their editor. Even if the file is unsaved, or the file comes from `aVeryWeirdURIScheme:///what?`, all of Rascal's IO features are rerouted implicitly to see the editor contents.
+* Your LSP services are based on the metaprogramming facilities of Rascal, and IDE construction is just a form of meta-programming (code in -> UI information out).
+* The Rascal LSP API functions are pure, and work with only immutable data-types. This makes it easy to test and/or debug independently of any editor client. Managing editor state and implementing the asynchronous LSP protocol is hidden under-the-hood.
+* Your LSP services once made for VScode, will work for any IDE client we port the [LSP bridge]((org.rascalmpl.rascal-lsp)) to.
+* You do not have to write a full type-checker or a full compiler, to start giving your users valuable features like error checking, overviews and hyperlinks. Start small. Dream big.
+* All changes to DSL files are applied via collecting ((((TextEdits-FileSystemChange))))s, which is a kind of `diff` format. If you stick with this protocol rather then writing to disk yourself, then the IDE will integrate all changes into the undo/redo stack, and can also provide confirmation dialogs and/or previews.
+* Later you can decide to deploy your own VScode extension with no changes to your ((util::LanguageServer)) services code.
+
+#### Pitfalls
+
+* It is easy to add many useful commands and features for yours users, but all of them have to have a clear and predictable semantics and all of them must be maintained in the future. It makes sense to create services "on demand", as your users ask for them. Too many options is confusing. Also not every DSL needs every programming language feature, even though it is easy to construct it with Rascal and the ((util::LanguageServer)) API.
+* In VScode, if your ((ExecutionService)) changes any DSL files on a project, which are not in an open editor, then editors are opened for each file and it is up to the user to "save" them and commit to the changes. It's the same for ((RenameService)) and any other side-effect applied to code files you build into your Rascal code.
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/ParsingService/ParsingService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ParsingService/ParsingService.md
new file mode 100644
index 000000000..e26e1d89e
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ParsingService/ParsingService.md
@@ -0,0 +1,91 @@
+---
+title: Parsing Service
+sidebar_position: 1
+---
+
+#### Synopsis
+
+A parser is the first and foremost thing you need for constructing an LSP server/IDE.
+
+#### Examples
+
+Type in a ((Rascal:SyntaxDefinition)), also known as a context-free grammar, for your language.
+
+Here is an example that defines a very small programming language called "Pico". We will use
+this language throughout all recipes for the ((LanguageServerProtocol)).
+
+```rascal-include
+demo::lang::Pico::Syntax
+```
+
+It's important that you import the `ParseTree` module to be able to call the ((ParseTree-parse)) function:
+```rascal-commands
+import ParseTree;
+```
+
+and then you can write your own parser function that wraps the `#start[Program]` non-terminal:
+```rascal-commands,continue
+import demo::lang::Pico::Syntax;
+start[Program] parsePico(str contents, loc origin)
+ = parse(#start[Program], contents, origin);
+```
+
+The parse function must take a `start` non-terminal as parameter (so not just `#Program`), because otherwise
+spaces, newlines and comments before and after the main `Program` content will lead to parse errors.
+
+With the above function every parse error will lead to an error diagnostic in the editor, _and_
+syntax highlighting only works if there is no parse error. To help your users a bit, you can
+activate parse error recovery:
+
+```rascal-commands
+import ParseTree;
+import demo::lang::Pico::Syntax;
+start[Program] parsePicoWithRecovery(str contents, loc origin)
+ = parse(#start[Program], contents, origin, allowRecovery=true);
+```
+Now syntax highlighting will indicate which part of the file has been recognized and
+which part of the file has not. The parse errors will still appear in the Diagnostics view.
+
+
+```rascal-prepare
+import ParseTree;
+import demo::lang::Pico::Syntax;
+start[Program] parsePico(str contents, loc origin)
+ = parse(#start[Program], contents, origin);
+```
+
+It is always a good idea to test your parser in the terminal:
+```rascal-shell,continue
+parsePico("begin declare a: natural; a := 42 end", |demo:///|)
+```
+And to find out what a parse error looks like:
+```rascal-shell,continue,errors
+parsePico("begin declare a: natural; a = 42 end", |demo:///|)
+```
+
+Or you could write a test function for it, for future reference:
+```rascal-commands,continue
+test bool testPicoParser() {
+ return start[Program] _ := parsePico("begin declare a: natural; a := 42 end", |demo:///|);
+}
+test bool testErrorPicoParser() {
+ try {
+ parsePico("begin declare a: natural; a = 4$2 end", |demo:///|);
+ return false;
+ }
+ catch ParseError(_): {
+ return true;
+ }
+}
+```
+
+In general a ((ParsingService)) is simply a function that satisfies the ((util::LanguageServer-Parser)) signature.
+
+Now let's move on to [registering your language with the IDE]((RegisterYourLanguage)) and
+run your own language server.
+
+#### Benefits
+
+* you can always test any service function in the terminal. This is highly recommended because simple errors and output can sometimes be hard to find in the IDE.
+* you can always write Rascal test functions to add to the stability of your LSP services.
+* the ((ParseTree-Tree))s produced by your ((ParsingService)) will be the input of all other services later.
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/ReferencesSevice/ReferencesSevice.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ReferencesSevice/ReferencesSevice.md
new file mode 100644
index 000000000..fcb8692df
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/ReferencesSevice/ReferencesSevice.md
@@ -0,0 +1,5 @@
+---
+title: References Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/RegisterYourLanguage/RegisterYourLanguage.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/RegisterYourLanguage/RegisterYourLanguage.md
new file mode 100644
index 000000000..ac086145b
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/RegisterYourLanguage/RegisterYourLanguage.md
@@ -0,0 +1,78 @@
+---
+title: Register your language
+sidebar_position: 2
+---
+
+#### Synopsis
+
+Start a new VScode extension for your language
+
+#### Description
+
+We assume you have already written a ((ParsingService)) function. Now think of:
+* a name for your language;
+* a file extension for its files.
+
+```rascal-module
+With the following shell commands you register your language with the IDE:
+```rascal-module
+module MyLanguageServer
+
+import util::LanguageServer; // <1>
+import demo::lang::Pico::Syntax; // <2>
+
+start[Program] myParsingService(str s, loc l) { // <3>
+ return parse(#start[Program], s, l);
+}
+
+// highlight-start
+set[LanguageService] myLanguageServices() { // <4>
+ parser(myParsingService);
+}
+// highlight-end
+
+void main() { // <5>
+ // highlight-next-line
+ registerLanguage( // <6>
+ // highlight-next-line
+ language( // <7>
+ pathConfig(), // <8>
+ "Pico", // <9>
+ {"pico"}, // <10>
+ "MyLanguageServer", // <11>
+ "myLanguageServices" // <12>
+ )
+) ;
+}
+```
+
+1. Load the LSP API we need later
+2. Load the ((Rascal:SyntaxDefinition)) needed for our ((ParsingService))
+3. Define a ((ParsingService)) (could also be already define in the imported module)
+4. Collect all relevant language services. The function _must not have positional parameters_ and return a `set[LanguageService]`. You can keep adding new services here to the set, and keep the other code the same.
+5. Having a `main` function is not obligatory, but when you deploy the extension later as an independent extension you will need it anyway.
+6. The call to ((registerLanguage)) does the final job of extending the current IDE with your own extension. A whole new Rascal runtime environment will be started just for your extension. Modules will be loaded, and the services will be connected to LSP callbacks, etc.
+7. The ((util::LanguageServer-language)) constructor provides five pieces of meta data:
+8. ((util::PathConfig::pathConfig)) is used to configure the Rascal runtime environment for loading your services. This comes in handy when you have third-party dependencies.
+9. This is the UI facing name of your language.
+10. These are the file extensions that activate the current IDE extension.
+11. This is the top module to import into the Rascal runtime environment for this extension.
+12. This is the name of the function in the top module which provides a `set[LanguageService]` when called with no arguments.
+
+Then you simply call `main()` and you can open an editor with the file extension `pico`.
+The first time the parser will be generated and cached, and when it is finished ((SyntaxHighlighting)) will show you the success of the parse.
+
+That's it!
+
+Now you can continue, for example, with ((SyntaxHighlighting)) or ((HoverService)) as two of
+the ((LanguageServerProtocol)) features to try out.
+
+#### Benefits
+
+* repeated calls to ((registerLanguage)) re-initialize your language extension from scratch
+
+#### Pitfalls
+
+* language extensions are not refreshed automatically if you change their implementation. You have to keep calling ((registerLanguage)) for this
+* (Accidental) console output, logging and unexpected error messages appear in VScode `OUTPUT` tabs, but these tabs are not automatically floating to the top. It's better to debug your services in the terminal.
+
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/RenameService/RenameService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/RenameService/RenameService.md
new file mode 100644
index 000000000..27b01ed87
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/RenameService/RenameService.md
@@ -0,0 +1,5 @@
+---
+title: Rename Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/SelectionRangeService/SelectionRangeService.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/SelectionRangeService/SelectionRangeService.md
new file mode 100644
index 000000000..e3de52dfc
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/SelectionRangeService/SelectionRangeService.md
@@ -0,0 +1,5 @@
+---
+title: Selection Range Service
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/LanguageServerProtocol/SyntaxHighlighting/SyntaxHighlighting.md b/courses/Recipes/UserInterfaces/LanguageServerProtocol/SyntaxHighlighting/SyntaxHighlighting.md
new file mode 100644
index 000000000..96923a610
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/LanguageServerProtocol/SyntaxHighlighting/SyntaxHighlighting.md
@@ -0,0 +1,5 @@
+---
+title: Syntax Highlighting
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md b/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md
new file mode 100644
index 000000000..2df905aa5
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/SalixRecipes/SalixRecipes.md
@@ -0,0 +1,5 @@
+---
+title: Constructing web-based user-interfaces with Salix
+---
+
+(((TODO)))
\ No newline at end of file
diff --git a/courses/Recipes/UserInterfaces/UserInterfaces.md b/courses/Recipes/UserInterfaces/UserInterfaces.md
new file mode 100644
index 000000000..70fa211b6
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/UserInterfaces.md
@@ -0,0 +1,47 @@
+---
+title: User Interfaces
+keywords:
+ - userinterfaces
+ - visualization
+ - UX
+ - UI
+ - HTML
+ - HTML5
+ - Servlets
+ - WebServer
+---
+
+#### Synopsis
+
+Recipes for writing Rascal programs that create interactive _visual_ user interfaces.
+
+#### Syntax
+
+#### Types
+
+#### Function
+
+#### Description
+
+These recipes are useful if have one of the following intentions for your programming language or DSL:
+* creating a software visualization tool (interactive or not)
+* creating an interactive or even live programming environment
+* creating an full-featured editor
+* creating a coupled visualization (code <-> visual)
+* creating visual statistical overviews and reports of your empirical data (extracted from code)
+* creating visual modeling tools
+* etc.
+
+These recipes fall into three major technological categories:
+* ((VanillaHTML5)) recipes explain how to generate and serve HTML5 content directly from Rascal into your IDE web view or into your Desktop browser.
+* ((SalixRecipes)) explain how to use the [Salix]((org.rascalmpl.salix-core)) framework to build user interfaces for the browser (or the IDE web view) in Rascal.
+* ((LanguageServerProtocol)) recipes explain how to construct a full featured IDE with Visual Studio Code and the Language Server Protocol.
+
+#### Examples
+
+#### Benefits
+
+
+
+#### Pitfalls
+
diff --git a/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md b/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md
new file mode 100644
index 000000000..88e9ee29e
--- /dev/null
+++ b/courses/Recipes/UserInterfaces/VanillaHTML5/VanillaHTML5.md
@@ -0,0 +1,149 @@
+---
+title: Vanilla HTML5 user interfaces
+keywords:
+ - HTML5
+ - JavaScript
+ - WebServer
+ - Content
+---
+
+#### Synopsis
+
+Creating interactive visual content for the browser using Rascal's HTML and HTTP low-level API support.
+
+#### Syntax
+
+#### Types
+
+#### Function
+
+#### Description
+
+To start with a simple "webserver" in Rascal, all you really need is to import ((module:Content)) and
+write a server function:
+
+```rascal-shell
+import Content;
+// A server in Rascal terms is a function that takes an HTTP Request and produces an HTTP Response:
+Response myWebServer(Request q) = response("Hello \World\");
+// Let's test the server locally to see what the `plain` utility function produces as Response:
+myWebServer(get("index.html"))
+// and the REPL will spin-up an actual server by itself like this:
+content("myServer", myWebServer)
+```
+
+There are handy shorthands in ((module:Content)) like ((plainText)) and ((Library:Content-html)) and ((Library:Content-file)) to directly
+stream strings, html and files to the web client.
+
+The HTTP ((module:Content)) servers that start from the REPL automatically are also managed automatically. If you use the same tag, the server is reloaded.
+Also inactive servers are removed and their data is garbage collected after 30 minutes of inactivity.
+
+#### Examples
+
+**Generating HTML as text** is done using the ((StringTemplate)) recipe. For example:
+```rascal-prepare
+import Content;
+```
+
+```rascal-commands,continue
+words = ["aap", "noot", "mies"];
+str generateList(list[str] words)
+ = "\
+ '
";
+```
+
+```rascal-shell,continue
+// this is the generated content as plain/text mimetype
+plainText(generateList(words))
+// this is the generated content as plain/html mimetype
+html(generateList(words))
+```
+
+**Generating abstract HTML** is done using ((lang::html::AST)) algebraic data-type for HTML. For example:
+```rascal-shell,continue
+import lang::html::AST;
+import lang::html::IO;
+```
+
+```rascal-shell,continue
+HTMLElement generateUL(list[str] words) = ul([li([text(w)]) | w <- words]);
+// and we can see the generated HTML
+plainText(writeHTMLString(generateUL(words)))
+// or view the HTML as rendered by the browser
+html(writeHTMLString(generateUL(words)));
+```
+
+**Interactive content** is not much more complicated to setup, but it does require JavaScript programming.
+We stay with the Request/Response system. Next to the request for the main page we
+we also receive asynchronous http requests (via the "fetch" function in JavaScript). In this next server definition we use ((Declarations-Function)) overloading to handle
+each request URL with a different function body:
+
+```rascal-commands,continue
+// In this demo we use a simple integer to demonstrate server-side data and state:
+int counter = 0;
+// The first overload serves the main page, which includes a call to `fetch` the new counter state (in JavaScript):
+Response myInteractiveServer(get("/"))
+ = response("\
+ ' \
+ ' \
Counter: \