Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,12 @@ private String applyPathReplacements(String path) {
return replaced;
}

/// The skill's files and the two pointers to it: [#addAgentSkillEntries(Map)].
static boolean isAgentSkillPath(String targetPath) {
return targetPath.startsWith(AGENT_SKILL_TARGET_PREFIX) || CLAUDE_SKILL_STUB_PATH.equals(targetPath)
|| "AGENTS.md".equals(targetPath);
}

private byte[] applyDataReplacements(String targetPath, byte[] sourceData) throws IOException {
if (!isTextFile(targetPath)) {
return sourceData;
Expand All @@ -1511,10 +1517,19 @@ private byte[] applyDataReplacements(String targetPath, byte[] sourceData) throw
// Ahead of the replacements below, which the template's hints get too.
content = (content.endsWith("\n") ? content : content + "\n") + readResourceToString(template.SETTINGS);
}
// The agent skill names the demo applications (Wayline, Savor, ...) on purpose,
// so an agent can go and read them; renaming the template's own name inside it
// would turn "read Wayline's map code" into a pointer at a demo that does not
// exist. It still gets the generic placeholders below.
boolean agentSkillFile = isAgentSkillPath(targetPath);
content = StringUtil.replaceAll(content, "com.example.myapp", packageName);
content = StringUtil.replaceAll(content, template.SOURCE_PACKAGE, packageName);
if (!agentSkillFile) {
content = StringUtil.replaceAll(content, template.SOURCE_PACKAGE, packageName);
}
content = StringUtil.replaceAll(content, "MyAppName", appName);
content = StringUtil.replaceAll(content, template.SOURCE_MAIN_CLASS, appName);
if (!agentSkillFile) {
content = StringUtil.replaceAll(content, template.SOURCE_MAIN_CLASS, appName);
}
content = StringUtil.replaceAll(content, "myappname", toLowerCaseInvariant(appName));
// The name in capitals is how an environment variable spells a setting
// that starts with it: myappname.payments.key is read from
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: codename-one
description: Build and modify Codename One cross-platform mobile apps (Java 17, Maven or Gradle, ParparVM/Android/iOS/JavaScript). Use when the project contains a `codenameone_settings.properties` (in `common/` for Maven, at the root for Gradle), a `settings.gradle.kts` applying the `com.codenameone` plugin, depends on `com.codenameone:codenameone-core`, edits CSS files under `src/main/css/`, calls `cn1:run`, `cn1:test`, `cn1:build` or `./gradlew run`, references `com.codename1.ui.*` / `com.codename1.testing.*`, works in the `backend/` project (`cn1:backend`, `./gradlew runBackend`, `com.codename1.backend.*`, `@RestController`, `@Component`, `@Transactional`), or when the user asks to build a UI, write screen tests, generate screenshots, build a server or full-stack feature, or compare to Swing/HTML/Android.
description: Build and modify Codename One cross-platform apps (Java 17, Maven or Gradle; iOS, Android, desktop, web) and their Codename One Backend. Use when the project has `codenameone_settings.properties`, applies the `com.codenameone` Gradle plugin or depends on `codenameone-core`; when editing `src/main/css/` or code using `com.codename1.*`; when running `cn1:run`, `cn1:test`, `cn1:build`, `cn1:backend` or `./gradlew run`; when the user asks for a UI, screen tests, screenshots, a server or a full-stack feature; when porting or running existing Android, Swing, JavaFX, Flutter/Dart or Unity code (`src/main/android|desktop|flutter|unity`, `import-*-project`, `transcode-flutter`); or when asking how a Codename One app is best structured (the Wayline, Savor, Parley and Skirmish demos).
metadata:
type: skill
---
Expand Down
6 changes: 5 additions & 1 deletion scripts/initializr/common/src/main/resources/skill/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: codename-one
description: Build and modify Codename One cross-platform mobile apps (Java 17, Maven or Gradle, ParparVM/Android/iOS/JavaScript). Use when the project contains a `codenameone_settings.properties` (in `common/` for Maven, at the root for Gradle), a `settings.gradle.kts` applying the `com.codenameone` plugin, depends on `com.codenameone:codenameone-core`, edits CSS files under `src/main/css/`, calls `cn1:run`, `cn1:test`, `cn1:build` or `./gradlew run`, references `com.codename1.ui.*` / `com.codename1.testing.*`, works in the `backend/` project (`cn1:backend`, `./gradlew runBackend`, `com.codename1.backend.*`, `@RestController`, `@Component`, `@Transactional`, `@Scheduled`), or when the user asks to build a UI, write screen tests, generate screenshots, build a server or full-stack feature, or compare to Swing/HTML. Also use when the project has Dart under `common/src/main/flutter/`, runs the `transcode-flutter` goal, references `com.codename1.flutter.*` / `FlutterUI`, or the user asks to port or embed Flutter/Dart code.
description: Build and modify Codename One cross-platform apps (Java 17, Maven or Gradle; iOS, Android, desktop, web) and their Codename One Backend. Use when the project has `codenameone_settings.properties`, applies the `com.codenameone` Gradle plugin or depends on `codenameone-core`; when editing `src/main/css/` or code using `com.codename1.*`; when running `cn1:run`, `cn1:test`, `cn1:build`, `cn1:backend` or `./gradlew run`; when the user asks for a UI, screen tests, screenshots, a server or a full-stack feature; when porting or running existing Android, Swing, JavaFX, Flutter/Dart or Unity code (`src/main/android|desktop|flutter|unity`, `import-*-project`, `transcode-flutter`); or when asking how a Codename One app is best structured (the Wayline, Savor, Parley and Skirmish demos).
metadata:
type: skill
---
Expand Down Expand Up @@ -31,6 +31,8 @@ This skill teaches you how to write code for a Codename One (CN1) cross-platform
- `references/html-css-cheatsheet.md` — Converting common HTML/CSS snippets to CN1 components + CSS.
- `references/android-to-cn1.md` — Porting Android (XML + Kotlin/Java) screens to Codename One.
- `references/react-to-cn1.md` — Bringing a **React / JSX + CSS design** (e.g. a Claude-generated bundle: `*.jsx` + `tokens.css` + `styles.css`) into Codename One: the component/hook/CSS mapping, the `tokens.css` -> `theme.css` token workflow, dark-mode re-skinning, and the **render-on-desktop-then-inspect** loop. Read this when the user hands you a React/HTML design to rebuild in CN1.
- `references/demos.md` — The four full-stack demo applications (Wayline ride hailing, Savor food delivery, Parley encrypted messenger, Skirmish 3D card game): where their source is, which one to read for which feature, and the structural patterns they all share. **Read this before inventing an app structure, networking layer, live-update channel or theme layout** -- copy how a demo does it.
- `references/compatibility.md` — The build-time compatibility tools: run an existing **Android** app (`src/main/android`), **Swing** or **JavaFX** app (`src/main/desktop`), **Flutter** code (`src/main/flutter`) or **Unity 2D** project (`src/main/unity`) on every Codename One target without rewriting it, the `import-*-project` goals, how to mix ported and new code, limits, and sample inputs. Read this first whenever the user has an existing app in one of those frameworks.
- `references/flutter-to-cn1.md` — Bringing **Dart / Flutter widget source** into Codename One. Unlike the other porting guides this is mostly not a rewrite: the `transcode-flutter` Maven goal compiles Dart widgets to Java at build time (no Dart SDK involved), and `FlutterUI.wrap` / `FlutterUI.runApp` mount the result. Read this when the user has Dart or Flutter code, asks to embed a Flutter screen in a CN1 app, or asks whether a Flutter app can be ported.
- `references/testing-and-screenshots.md` — `AbstractTest`, `TestUtils`, `screenshotTest`, the `cn1:test` Maven goal, the screenshot tolerance algorithm.
- `references/mockup-comparison.md` — Building a screen to **match a designer mockup**: `tools/CompareToMockup.java` scores a render against a mockup image and prints a similarity % (with partial/region masking so device chrome doesn't sabotage the score), and `tools/DesignImport.java` turns a Figma/Sketch/Adobe XD file **or an HTML/React design's `tokens.css`/`styles.css`** (e.g. a Claude-generated mockup) into a starter `theme.css` + tokens + layout map. Read this when the user gives you a mockup, a Figma/Sketch/XD file, an HTML/CSS design bundle, or asks "how close is this screen to the design".
Expand Down Expand Up @@ -378,6 +380,8 @@ If you cannot run the simulator (e.g. headless environment), **say so explicitly
| "I have HTML/CSS, convert it" | `references/html-css-cheatsheet.md` |
| "I have a React/JSX design (jsx + tokens.css), rebuild it in CN1" / "match this Claude design" | `references/react-to-cn1.md` |
| "I have Android XML/Kotlin/Java, convert it" | `references/android-to-cn1.md` |
| "Run my existing Android / Swing / JavaFX / Flutter / Unity app" / `import-*-project` / `src/main/android`, `desktop`, `flutter`, `unity` | `references/compatibility.md` |
| "How should I structure this app" / "show me a real example" / best practice for networking, live updates, maps, chat, payments, games | `references/demos.md` (then read the demo's source) |
| "Generate a client for this OpenAPI spec / `.proto` / GraphQL schema" / `@RestClient`, `@GrpcClient`, `@GraphQLClient` | `references/api-clients.md` |
| "Write a test for this screen" / "Compare to a baseline" | `references/testing-and-screenshots.md` |
| "Match this mockup" / "Compare to a Figma/Sketch/XD design" / "Import this HTML/CSS (Claude) design's tokens" / "How close is this screen to the design" | `references/mockup-comparison.md` |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Bringing existing code in: the compatibility tools

Before you rewrite an existing application in Codename One, check whether it can
be **built as it is**. Codename One has build-time compatibility tools for four
ecosystems. Each one takes the original sources in a directory under
`common/src/main/` (Gradle: `src/main/`), turns them into ordinary Codename One
code during the build, and runs the result on every target -- iOS, Android,
desktop and web. Nothing interprets the original framework at run time.

| You have | Put sources in | Import goal (Maven) | Runtime / tool | Deep reference |
| --- | --- | --- | --- | --- |
| A classic Android app (Activities, XML layouts, `res/`, Java/Kotlin) | `src/main/android` | `mvn cn1:import-android-project -Dcn1.android.import=<path>` | `codenameone-android-compat` (the `android.*` API over CN1 components) | `references/android-to-cn1.md`, developer guide "Running Android applications" |
| A Swing / AWT / SwingX app | `src/main/desktop` | `mvn cn1:import-desktop-project -Dcn1.desktop.import=<path>` | Swing compatibility layer | `references/swing-comparison.md`, developer guide "Running Swing and JavaFX applications" |
| A JavaFX app (incl. FXML and JavaFX CSS) | `src/main/desktop` | same goal as Swing | JavaFX compatibility layer; FXML and CSS compiled at build time | developer guide "Running Swing and JavaFX applications" |
| Flutter / Dart widget code | `src/main/flutter` | `mvn cn1:import-flutter-project -Dcn1.flutter.import=<path>` | `transcode-flutter` goal compiles Dart to Java; `FlutterUI.wrap` / `FlutterUI.runApp` | `references/flutter-to-cn1.md` |
| A Unity 2D project | `src/main/unity` | `mvn cn1:import-unity-project -Dcn1.unity.import=<path>` | C# assembly translated to Java; needs the .NET SDK at build time | developer guide "Unity" chapter |

Gradle projects pick up the same directories automatically (the plugin adds the
runtime and the build steps when the directory exists). The import goals are
Maven goals; in a Gradle project copy the sources into the directory by hand.

## How to work with them

1. **Import, then build.** The build is the coverage check: an API the layer does
not implement is a **build error** naming the original class/member and source
line, not a run-time surprise. Read the errors as the porting to-do list.
2. **Fix gaps with Codename One code, not by stubbing the layer.** Replace an
unsupported call with the CN1 equivalent (see `ui-components.md`,
`java-api-subset.md`), or isolate desktop/phone-only behaviour behind a check.
3. **Mix freely.** The ported code and new Codename One code live in one app:
an Android `View` exposes its CN1 component via `getPeer()` (see `android.view.View` in `maven/android-compat`);
`SwingInterop.asComponent` / `FxInterop.asComponent` wrap Swing or JavaFX UI
as a `com.codename1.ui.Component`; `FlutterUI.wrap` returns a `Container`.
This is how to migrate a screen at a time.
4. **Verify behaviour, not just the build.** Run it in the simulator and drive
the flows (see `mcp-agent-control.md`). Translation succeeding does not mean
every callback is honoured -- Flutter in particular is experimental.

## Limits to tell the user up front

- No binary drop-in: third-party jars that use `java.awt`, `javax.swing`,
`javafx` or Android APIs are not relocated and fail the compliance check.
- No reflection-driven frameworks, class loaders, `ServiceLoader`, OSGi.
- Android: Jetpack Compose is not covered.
- Desktop coordinates are logical pixels scaled to the device density.

## Samples to learn from

Small, complete inputs that CI builds through each tool (in the Codename One
repository, `https://github.com/codenameone/CodenameOne/tree/master/scripts/...`):

- `android-compat-samples/gallery` -- an Android Studio project (Java + Kotlin, `res/`).
- `desktop-compat-samples/swing-gallery`, `desktop-compat-samples/javafx-gallery`.
- `flutter-apps/field_notes`, `flutter-apps/pet_adoption` -- Flutter apps ported with the transcoder.
- `unity-compat-samples/*` -- Unity 2D scenes and games.

For idiomatic *native* Codename One code to evolve toward, see `references/demos.md`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# The demo applications: where to learn idiomatic Codename One

Codename One ships four complete, production-shaped applications. Each is an app
**and** its server, written by the Codename One team, tested end to end, and kept
building against the current framework. When you are unsure how something is
"meant" to be done -- a screen, a navigation pattern, a live channel, a REST
contract, a test, a theme -- **read how a demo does it before inventing a
pattern.** Copy the shape, not the domain.

## Where the source is

- **If this project was generated from one of these templates in the Initializr**,
the demo *is* this project: its packages were renamed to yours, but the
structure below is what you have on disk, and the demo's main class is named
after your app. Read it locally.
- Otherwise read it on GitHub (no clone needed; fetch the raw file you want):
`https://github.com/codenameone/CodenameOne/tree/master/scripts/<demo>`, raw
files at `https://raw.githubusercontent.com/codenameone/CodenameOne/master/scripts/<demo>/<path>`.
- Each demo has an implementor's guide in the developer guide
(`docs/developer-guide/<Demo>-Implementors-Guide.asciidoc` in the same repository).
It explains *why* the code is laid out the way it is -- read it before making a
structural change modeled on a demo.

All four share this layout, which is itself the first best practice (Skirmish adds a
`rules` module, the deterministic game simulation the app, server and tests all compile):

| Module | Holds |
| --- | --- |
| `shared` | The contract: DTOs and `@RestClient` interfaces. The app's build generates the client, the server's build generates the interfaces it implements, so a change one side missed is a compile error. |
| `common` | The application. One codebase for simulator, desktop, Android, iOS and web -- no platform modules. |
| `backend` | The Codename One Backend server (`@RestController`, entities in `domain`, migration scripts in `src/main/resources/db/migration`, runs on SQLite/PostgreSQL/MySQL/MariaDB). |

Run any of them with `CN1_PROFILE=dev backend/server.sh run` and, in another
terminal, `mvn verify -Psimulator -DskipTests -Dcodename1.platform=javase`. The
README of each lists the demo accounts.

## Which demo to read for what

| Demo | What it is | Read it for |
| --- | --- | --- |
| `scripts/wayline` | Ride hailing: rider, driver, admin | Role-based start screens, maps and live markers (`map/`), bottom sheets, wallet and card entry (`pay/`), admin dashboards and charts (`admin/`, `ui/Chart.java`), the reference implementation of the shared-contract full-stack pattern |
| `scripts/savor` | Food delivery: customer, merchant, courier, admin | Catalog/menu browsing, cart and checkout (`customer/`), merchant order queues and menu editing (`merchant/`), two state machines (order + delivery) mirrored between `shared` enums and the server |
| `scripts/parley` | End-to-end encrypted messenger with calls | Chat UI and media (`chat/`, `ui/ChatForm.java`), crypto with core APIs (`crypto/`), WebRTC calls (`com.codename1.webrtc`, `ui/CallScreen.java`), local store (`store/`), push and WebSocket delivery |
| `scripts/skirmish` | Real-time 3D card battler | Games: `GameView`/3D rendering (`battle/`), a deterministic `rules` module shared by app, server and tests, replays, in-app purchases and rewarded ads (`engage/`), matchmaking over sockets, in-app editors (`forge/`) |

## Patterns the app demos share (copy these)

Wayline, Savor and Parley follow all of these. Skirmish is a game and differs:
its socket is `net/GameLink.java` rather than `live/LiveChannel.java`, and it has
no `Prefs`, `Telemetry` or l10n bundles.

- **Thin entry class.** `<pkg>/<App>.java` extends `Lifecycle`; configuration in
`AppConfig`, preferences in `Prefs`, opt-in analytics in `Telemetry`.
- **One networking layer.** `net/Net.java` + `net/Api.java` wrap the generated
`@RestClient`s, `net/Session.java` holds the signed-in state; screens never
build URLs or parse JSON themselves.
- **Live updates through one channel.** `live/LiveChannel.java` owns the
WebSocket and fans events out on the EDT; screens subscribe rather than poll.
- **UI helpers instead of repeated code.** `ui/Ui.java`, `ui/Layouts.java`,
`ui/Nav.java`, `ui/Look.java`, `ui/Skeleton.java` (loading placeholders),
`ui/BottomSheet.java`. Look for an existing helper before adding a component.
- **Theme driven by variables.** `common/src/main/css/theme.css` opens with a
block of variables (colors, corner radius) everything else is drawn from; dark
mode and color schemes swap those, not individual rules.
- **Localized from day one.** All text in `common/src/main/l10n` bundles,
including an RTL language (Hebrew), so layouts are checked mirrored.
- **Tested end to end.** `run-e2e.sh` starts the server on the `test` profile
and drives the app in the simulator; screenshots land in `target/e2e-shots`.
Backend tests run with `-Dcodename1.platform=backend test`.

When you borrow from a demo, keep its conventions consistent with the code
already in this project; do not paste a demo's domain classes wholesale.
Loading
Loading