diff --git a/README.md b/README.md
index df5adff08..3c7c9844d 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[](https://www.npmjs.com/package/livecodes)
[](https://www.npmjs.com/package/livecodes)
[](https://www.jsdelivr.com/package/npm/livecodes)
-[](https://livecodes.io/docs/languages/)
+[](https://livecodes.io/docs/languages/)
[](https://livecodes.io/docs/)
[](https://livecodes.io/docs/llms.txt)
[](https://livecodes.io/docs/llms-full.txt)
diff --git a/docs/docs/languages/dart.mdx b/docs/docs/languages/dart.mdx
new file mode 100644
index 000000000..dd342ee48
--- /dev/null
+++ b/docs/docs/languages/dart.mdx
@@ -0,0 +1,115 @@
+# Dart
+
+[Dart](https://dart.dev/) is a client-optimized, statically typed programming language developed by Google, with a focus on building fast apps on any platform.
+
+Dart in LiveCodes is compiled to JavaScript in the browser, with no server. It uses the Dart team's own client-side toolchain — DDC, the analyzer and a subset of `pub`, the same one that powers [DartPad](https://dartpad.dev/) — packaged as [`@live-codes/dart-wasm`](https://www.npmjs.com/package/@live-codes/dart-wasm).
+
+:::info
+
+For Flutter support in LiveCodes, see [Flutter](./flutter.mdx).
+
+:::
+
+## Usage
+
+Demo:
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const dartConfig = {
+ activeEditor: 'script',
+ script: {
+ language: 'dart',
+ content: `void main() {\n print('Hello, World!');\n}`,
+ },
+ mode: 'simple',
+ editor: 'auto',
+ tools: {
+ status: 'full',
+ active: 'console',
+ },
+};
+
+
+
+The compiled JavaScript runs in the context of the [result page](../features/result.mdx), so a Dart program has the page, its DOM and the markup and styles from the other editors.
+
+### Accessing the DOM
+
+`dart:js_interop` ships with the SDK, so the program can reach the page directly — no packages and no network needed:
+
+```ts
+import 'dart:js_interop';
+
+@JS('document')
+external Document get document;
+
+extension type Document(JSObject _) implements JSObject {
+ external Element? querySelector(String selectors);
+}
+
+extension type Element(JSObject _) implements JSObject {
+ external set textContent(String value);
+}
+
+void main() {
+ document.querySelector('#name')?.textContent = 'Dart';
+}
+```
+
+What the program prints goes to the console.
+
+Templates, collections and pattern matching behave as expected:
+
+```ts
+void main() {
+ final fibonacci = [0, 1];
+ while (fibonacci.length < 10) {
+ fibonacci.add(fibonacci[fibonacci.length - 1] + fibonacci[fibonacci.length - 2]);
+ }
+ print('Fibonacci: $fibonacci');
+
+ final squares = {for (var i = 1; i <= 5; i++) i: i * i};
+ for (final entry in squares.entries) {
+ print('${entry.key}² = ${entry.value}');
+ }
+}
+```
+
+## Language Info
+
+### Name
+
+`dart`
+
+### Aliases / Extensions
+
+`dartlang`, `dart`
+
+### Editor
+
+`script`
+
+## Compiler
+
+The Dart team's client-side toolchain: DDC (the Dart development compiler), using the [`dartpad`](https://pub.dev/packages/dartpad) package.
+
+### Version
+
+DartPad SDK 0.0.9
+
+## Code Formatting
+
+Dart's official formatter (the [`dart_style`](https://pub.dev/packages/dart_style) package behind `dart format`).
+
+## Starter Template
+
+https://livecodes.io/?template=dart
+
+## Links
+
+- [Dart official website](https://dart.dev/)
+- [Dart documentation](https://dart.dev/guides)
+- [DartPad](https://dartpad.dev/)
+- [@live-codes/dart-wasm](https://www.npmjs.com/package/@live-codes/dart-wasm)
+- [Flutter](./flutter.mdx) in LiveCodes
diff --git a/docs/docs/languages/flutter.mdx b/docs/docs/languages/flutter.mdx
new file mode 100644
index 000000000..8c0492d65
--- /dev/null
+++ b/docs/docs/languages/flutter.mdx
@@ -0,0 +1,111 @@
+# Flutter
+
+[Flutter](https://flutter.dev/) is Google's open-source framework for building natively compiled, multi-platform applications from a single codebase.
+
+Flutter in LiveCodes is compiled in the browser, with no server, using the same client-side toolchain as [Dart](./dart.mdx) — packaged as [`@live-codes/dart-wasm`](https://www.npmjs.com/package/@live-codes/dart-wasm). The compiled app then boots the Flutter engine in the result page.
+
+:::info
+
+For Dart language support in LiveCodes, see [Dart](./dart.mdx).
+
+:::
+
+## Usage
+
+Demo:
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const flutterConfig = {
+ activeEditor: 'script',
+ script: {
+ language: 'flutter',
+ content: `import 'package:flutter/material.dart';\n\nvoid main() {\n runApp(\n const Center(\n child: Text('Hello, World!', textDirection: TextDirection.ltr),\n ),\n );\n}`,
+ },
+ mode: 'simple',
+ editor: 'auto',
+};
+
+
+
+The app renders in the context of the [result page](../features/result.mdx), so it fills the result pane and responds to user interaction, just like any other Flutter web app.
+
+A stateful counter is the usual way to see a rebuild:
+
+```ts
+import 'package:flutter/material.dart';
+
+void main() {
+ runApp(const CounterApp());
+}
+
+class CounterApp extends StatefulWidget {
+ const CounterApp({super.key});
+
+ @override
+ State createState() => _CounterAppState();
+}
+
+class _CounterAppState extends State {
+ int _count = 0;
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ home: Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text('$_count', style: const TextStyle(fontSize: 56)),
+ const SizedBox(height: 12),
+ ElevatedButton(
+ onPressed: () => setState(() => _count++),
+ child: const Text('Increment'),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
+```
+
+## Language Info
+
+### Name
+
+`flutter`
+
+### Extensions
+
+`flutter`
+
+### Editor
+
+`script`
+
+## Compiler
+
+The Dart team's client-side toolchain (DDC), using the [`dartpad`](https://pub.dev/packages/dartpad) package and the [CanvasKit](https://pub.dev/packages/canvas_kit) renderer.
+
+### Version
+
+DartPad SDK 0.0.9
+
+## Code Formatting
+
+Dart's official formatter (the [`dart_style`](https://pub.dev/packages/dart_style) package behind `dart format`).
+
+## Starter Template
+
+https://livecodes.io/?template=flutter
+
+## Links
+
+- [Flutter official website](https://flutter.dev/)
+- [Flutter documentation](https://docs.flutter.dev/)
+- [Introduction to widgets](https://docs.flutter.dev/ui)
+- [@live-codes/dart-wasm](https://www.npmjs.com/package/@live-codes/dart-wasm)
+- [Dart](./dart.mdx) in LiveCodes
diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx
index 6116778a2..a6857f45b 100644
--- a/docs/src/components/LanguageSliders.tsx
+++ b/docs/src/components/LanguageSliders.tsx
@@ -98,6 +98,8 @@ export default function Sliders() {
{ name: 'cobol-wasm', title: 'COBOL (Wasm)' },
{ name: 'fortran', title: 'Fortran' },
{ name: 'd-wasm', title: 'D (Wasm)' },
+ { name: 'dart', title: 'Dart' },
+ { name: 'flutter', title: 'Flutter' },
{ name: 'v-wasm', title: 'V (Wasm)' },
{ name: 'rust-wasm', title: 'Rust (Wasm)' },
{ name: 'swift-wasm', title: 'Swift (Wasm)' },
diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx
index 9b7916baf..5ee78f5f2 100644
--- a/docs/src/components/TemplateList.tsx
+++ b/docs/src/components/TemplateList.tsx
@@ -93,6 +93,8 @@ const templates = [
{ name: 'minizinc', title: 'MiniZinc Starter', thumbnail: 'minizinc.png' },
{ name: 'blockly', title: 'Blockly Starter', thumbnail: 'blockly.svg' },
{ name: 'diagrams', title: 'Diagrams Starter', thumbnail: 'diagrams.svg' },
+ { name: 'dart', title: 'Dart Starter', thumbnail: 'dart.svg' },
+ { name: 'flutter', title: 'Flutter Starter', thumbnail: 'flutter.svg' },
];
export default function TemplateList() {
diff --git a/e2e/specs/starter.spec.ts b/e2e/specs/starter.spec.ts
index e284e5bec..8cb8f858d 100644
--- a/e2e/specs/starter.spec.ts
+++ b/e2e/specs/starter.spec.ts
@@ -1837,4 +1837,58 @@ test.describe('Starter Templates from URL', () => {
const counterText = await getResult().innerText('text=You clicked');
expect(counterText).toBe('You clicked 3 times.');
});
+
+ test('Dart Starter', async ({ page, getTestUrl }) => {
+ // the Dart toolchain (DDC, the analyzer and a subset of pub) is downloaded on the first run
+ test.slow();
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=New');
+ await app.click('text=Dart Starter');
+
+ await waitForEditorFocus(app);
+ await waitForResultUpdate();
+
+ // the button stays disabled until the compiled program has run and wired it up
+ await expect(getResult().locator('#counter-button')).toBeEnabled({ timeout: 280_000 });
+
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+
+ await expect(getResult().locator('h1')).toHaveText('Hello, Dart!');
+ await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
+ });
+
+ test('Flutter Starter', async ({ page, getTestUrl }) => {
+ // the Flutter toolchain and the engine are downloaded on the first run
+ test.slow();
+
+ await page.goto(getTestUrl());
+
+ const { app, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=New');
+ await app.click('text=Flutter Starter');
+
+ await waitForEditorFocus(app);
+ await waitForResultUpdate();
+
+ // the app renders to a canvas, so the engine booting is asserted through the line its main()
+ // prints
+ await app.click('#tools-pane-titles > .console');
+ await app.waitForFunction(
+ () =>
+ [...document.querySelectorAll('#console-container .luna-console-log-item')].some((item) =>
+ item.textContent?.includes('Hello from Flutter!'),
+ ),
+ undefined,
+ { timeout: 280_000 },
+ );
+ });
});
diff --git a/functions/vendors/templates.js b/functions/vendors/templates.js
index 739552b50..f0ed0b6c1 100644
--- a/functions/vendors/templates.js
+++ b/functions/vendors/templates.js
@@ -91,5 +91,7 @@ export const starterTemplates = {
"prolog": "Prolog Starter",
"minizinc": "MiniZinc Starter",
"blockly": "Blockly Starter",
- "diagrams": "Diagrams Starter"
+ "diagrams": "Diagrams Starter",
+ "dart": "Dart Starter",
+ "flutter": "Flutter Starter"
}
\ No newline at end of file
diff --git a/scripts/build.js b/scripts/build.js
index 60cf2fc2d..ba90d931b 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -239,6 +239,9 @@ const iifeBuild = () =>
'languages/fanak/lang-fanak-script.ts',
'languages/vb-wasm/lang-vb-wasm-script.ts',
'languages/zig-wasm/lang-zig-wasm-script.ts',
+ 'languages/dart/lang-dart-compiler.ts',
+ 'languages/dart/lang-dart-script.ts',
+ 'languages/flutter/lang-flutter-script.ts',
'languages/dot/lang-dot-compiler.ts',
'languages/ejs/lang-ejs-compiler.ts',
'languages/elm/lang-elm-compiler.ts',
diff --git a/server/php/inc/starter-templates.json b/server/php/inc/starter-templates.json
index bc6c15a79..8b7ff493e 100644
--- a/server/php/inc/starter-templates.json
+++ b/server/php/inc/starter-templates.json
@@ -91,5 +91,7 @@
"prolog": "Prolog Starter",
"minizinc": "MiniZinc Starter",
"blockly": "Blockly Starter",
- "diagrams": "Diagrams Starter"
+ "diagrams": "Diagrams Starter",
+ "dart": "Dart Starter",
+ "flutter": "Flutter Starter"
}
\ No newline at end of file
diff --git a/src/livecodes/UI/command-menu-actions.ts b/src/livecodes/UI/command-menu-actions.ts
index 544e84566..7f4985c64 100644
--- a/src/livecodes/UI/command-menu-actions.ts
+++ b/src/livecodes/UI/command-menu-actions.ts
@@ -348,6 +348,8 @@ export const getCommandMenuActions = ({
'minizinc',
'blockly',
'diagrams',
+ 'dart',
+ 'flutter',
).map((template) => ({
id: 'Starter template: ' + template,
title: window.deps.translateString('commandMenu.template', 'Template') + ': ' + template,
diff --git a/src/livecodes/assets/templates/dart.svg b/src/livecodes/assets/templates/dart.svg
new file mode 100644
index 000000000..39594efac
--- /dev/null
+++ b/src/livecodes/assets/templates/dart.svg
@@ -0,0 +1,22 @@
+
+
diff --git a/src/livecodes/assets/templates/flutter.svg b/src/livecodes/assets/templates/flutter.svg
new file mode 100644
index 000000000..efe70706b
--- /dev/null
+++ b/src/livecodes/assets/templates/flutter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html
index e1fa33fbc..6001d4241 100644
--- a/src/livecodes/html/language-info.html
+++ b/src/livecodes/html/language-info.html
@@ -638,6 +638,35 @@
D (Wasm)
+
+
Dart
+
+ Dart is compiled to JavaScript by the Dart team's client-side toolchain (DDC) — the same one
+ that powers DartPad — running entirely in the browser. The compiled bundle then runs in the
+ result page. No server is involved.
+
+ Flutter is compiled to JavaScript with the same client-side toolchain as Dart, and the Flutter
+ engine is then booted in the result page, where the app renders. No server is involved.
+