kaplay-ui 0.20.1 → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,245 +1,230 @@
1
- ![WIP](https://img.shields.io/badge/status-WIP-yellow)
2
- <br>_🚧 This package is a work in progress! 🚧_
3
- _Expect breaking changes and incomplete features._
1
+ <p align="center">
2
+ <img src="assets/kaplay-ui-logo.png" alt="kaplay-ui logo" width="400" >
3
+ </p>
4
4
 
5
- # KAPLAY UI - A UI Component Library for KAPLAY
5
+ # KAPLAY UI Plugin
6
6
 
7
- _A simple and customizable component UI library for [KAPLAY](https://kaplayjs.com/)._
7
+ A lightweight UI helper plugin for the https://kaplayjs.com/ game library, providing ready‑to‑use UI components such as text‑based buttons.
8
8
 
9
- ## 🚀 Introduction
9
+ This plugin simplifies the creation of UI elements using familiar KAPLAY primitives, offering sensible defaults while remaining flexible and composable.
10
10
 
11
- Kaplay UI is a component library designed specifically for KAPLAY. It will provide ready-made UI components to help you build better user interfaces for your KAPLAY games with minimal effort.
11
+ ---
12
12
 
13
- - [Installation](#installation)
14
- - [Usage](#usage)
15
- - [License](#license)
13
+ ## ✨ Features
16
14
 
17
- ## Installation
15
+ - 🎛️ **Text Button** — easily create a button with centered text
16
+ - 🧩 Designed to feel like native KAPLAY components
17
+ - 🎨 Comes with built‑in sizing, positioning, and outline defaults
18
+ - 🔧 Fully customizable through the normal KAPLAY component system
18
19
 
19
- You can install Kaplay UI via npm:
20
+ ---
20
21
 
21
- ```bash
22
- npm install kaplay-ui
23
- ```
24
-
25
- ## Usage
22
+ ## 📦 Installation
26
23
 
27
- ### Inputs
24
+ You can install the plugin using your preferred package manager:
28
25
 
29
- All inputs are imported from the <code>/inputs</code> folder.
30
-
31
- ```javascript
32
- import {} from "kaplay-ui/inputs";
26
+ ```sh
27
+ npm install kaplay-ui
33
28
  ```
34
29
 
35
- #### Checkbox
36
-
37
- To make a checkbox, one must use the exported <code>makeCheckbox()</code> function.
38
-
39
- ##### Example
40
-
41
- An example usage of a checkbox.
42
-
43
- ```javascript
44
- import kaplay from "kaplay";
45
- import "kaplay/global";
46
-
47
- import { makeCheckbox } from "kaplay-ui/inputs";
48
-
49
- kaplay();
30
+ or:
50
31
 
51
- const checkBox = makeCheckbox();
52
-
53
- add(checkBox);
32
+ ```sh
33
+ pnpm add kaplay-ui
54
34
  ```
55
35
 
56
- ##### State
57
-
58
- A cehckbox has the following state:
59
-
60
- | state | Type | Default | State change by |
61
- | --------- | --------- | ------- | ----------------- |
62
- | `checked` | `boolean` | false | Click on checkbox |
63
-
64
- ##### Parameters
65
-
66
- A checkbox can take the following parameters:
67
-
68
- | Parameter | Type | Default | Required | Description |
69
- | --------- | -------- | ------- | -------- | ------------------- |
70
- | `x` | `number` | 0 | ❌ No | Checkbox x position |
71
- | `y` | `number` | 0 | ❌ No | Checkbox x position |
72
- | `width` | `number` | 25 | ❌ No | Checkbox width |
73
- | `height` | `number` | 25 | ❌ No | Checkbox height |
36
+ or:
74
37
 
75
- <br>
38
+ yarn add kaplay-ui
76
39
 
77
- #### Switch
40
+ ````
78
41
 
79
- To make a text button, one must use the exported <code>makeSwitch()</code> function.
42
+ ---
80
43
 
81
- ##### Example
44
+ ## 🚀 Usage
45
+ Import and register the plugin when initializing your KAPLAY game:
82
46
 
83
- An example usage of a text button.
84
-
85
- ```javascript
47
+ ```js
86
48
  import kaplay from "kaplay";
87
- import "kaplay/global";
88
-
89
- import { makeSwitch } from "kaplay-ui/inputs";
49
+ import kaplayUI from "kaplay-ui";
90
50
 
91
- kaplay();
51
+ const k = kaplay({
52
+ plugins: [kaplayUI],
53
+ });
54
+ ````
92
55
 
93
- const switchBtn = makeSwitch();
56
+ You now have access to the UI helpers via your `k` instance:
94
57
 
95
- add(switchBtn);
58
+ ```js
59
+ const btn = k.addTextButton("Play", 200, 100);
96
60
  ```
97
61
 
98
- ##### State
99
-
100
- A cehckbox has the following state:
101
-
102
- | state | Type | Default | State change by |
103
- | ---------- | --------- | ------- | --------------- |
104
- | `switched` | `boolean` | false | Click on switch |
105
-
106
- ##### Parameters
107
-
108
- A switch can take the following parameters:
62
+ ---
109
63
 
110
- | Parameter | Type | Default | Required | Description |
111
- | --------- | -------- | ------- | -------- | ----------------- |
112
- | `x` | `number` | 0 | ❌ No | Switch x position |
113
- | `y` | `number` | 0 | ❌ No | Switch x position |
114
- | `width` | `number` | 50 | ❌ No | Switch width |
115
- | `height` | `number` | 25 | ❌ No | Switch height |
64
+ ## 🔘 `addTextButton()`
116
65
 
117
- <br>
66
+ Creates a button-like GameObj with centered text and some convenient defaults.
118
67
 
119
- #### Text Button
68
+ ### **Signature**
120
69
 
121
- To make a text button, one must use the exported <code>makeTextButton()</code> function.
122
-
123
- ##### Example
124
-
125
- An example usage of a text button.
126
-
127
- ```javascript
128
- import kaplay from "kaplay";
129
- import "kaplay/global";
130
-
131
- import { makeTextButton } from "kaplay-ui/inputs";
132
-
133
- kaplay();
134
-
135
- const txtBtn = makeTextButton("Start");
136
-
137
- add(txtBtn);
70
+ ```ts
71
+ addTextButton(
72
+ txt?: string,
73
+ width?: number,
74
+ height?: number
75
+ ): GameObj
138
76
  ```
139
77
 
140
- ##### Parameters
141
-
142
- A text button can take the following parameters:
78
+ ### **Default values**
143
79
 
144
- | Parameter | Type | Default | Required | Description |
145
- | ------------ | -------- | ------- | -------- | ---------------------------------- |
146
- | `text` | `string` | N/A | ✅ Yes | The text to display on the button. |
147
- | `x` | `number` | 0 | ❌ No | Button x position |
148
- | `y` | `number` | 0 | ❌ No | Button y position |
149
- | `width` | `number` | 100 | ❌ No | Button width |
150
- | `height` | `number` | 50 | ❌ No | Button height |
151
- | `btnRadius` | `number` | 8 | ❌ No | Button radius |
152
- | `btnOutline` | `number` | 1 | ❌ No | Button outline |
153
- | `txtSize` | `number` | 15 | ❌ No | Text size |
80
+ | Parameter | Default |
81
+ | --------- | ---------- |
82
+ | `txt` | `"Button"` |
83
+ | `width` | `200` |
84
+ | `height` | `100` |
154
85
 
155
- <br>
86
+ ### **Default styling**
156
87
 
157
- #### Text input
88
+ When created, the button includes:
158
89
 
159
- To make a toggle, one must use the exported <code>makeTextInput()</code> function.
90
+ - `k.outline(3)`
91
+ - `k.pos(0, 0)`
92
+ - `k.anchor("topleft")`
93
+ - `k.area()` — for click/hover detection
160
94
 
161
- ##### Example
162
-
163
- An example usage of a toggle.
164
-
165
- ```javascript
166
- import kaplay from "kaplay";
167
- import "kaplay/global";
95
+ ### **Example**
168
96
 
169
- import { makeTextInput } from "kaplay-ui/inputs";
97
+ ```js
98
+ // Default button
99
+ const btn1 = k.addTextButton();
170
100
 
171
- kaplay();
101
+ // Custom label
102
+ const btn2 = k.addTextButton("Start");
172
103
 
173
- const txtInput = makeTextInput();
104
+ // Custom size
105
+ const btn3 = k.addTextButton("Start", 150, 75);
174
106
 
175
- add(txtInput);
107
+ // Add interactivity
108
+ btn2.onClick(() => {
109
+ console.log("Button clicked!");
110
+ });
176
111
  ```
177
112
 
178
- ##### Parameters
113
+ ---
179
114
 
180
- A text input can take the following parameters:
115
+ ## 🧱 How It Works
181
116
 
182
- | Parameter | Type | Default | Required | Description |
183
- | ---------- | --------- | ------- | -------- | ------------------------------ |
184
- | `x` | `number` | 0 | ❌ No | x position |
185
- | `y` | `number` | 0 | ❌ No | y position |
186
- | `width` | `number` | 400 | ❌ No | width |
187
- | `txtSize` | `number` | 15 | ❌ No | Input text size |
188
- | `pad` | `number` | 10 | ❌ No | Padding |
189
- | `hasFocus` | `boolean` | true | ❌ No | If text input has focus or not |
117
+ Internally, the plugin creates a GameObj composed of:
190
118
 
191
- <br>
119
+ - A rectangle-like button base
120
+ - Centered text using KAPLAY's built‑in text component
121
+ - A combined area for input events
192
122
 
193
- #### Toggle
123
+ This keeps your UI elements fully compatible with:
194
124
 
195
- To make a toggle, one must use the exported <code>makeToggle()</code> function.
125
+ - `onClick()`
126
+ - `onHover()`
127
+ - `color()`, `scale()`, etc.
128
+ - Layout within scenes or parent objects
196
129
 
197
- ##### Example
130
+ ---
198
131
 
199
- An example usage of a toggle.
132
+ ## 📱 Mobile‑Friendly UI Demo
200
133
 
201
- ```javascript
202
- import kaplay from "kaplay";
203
- import "kaplay/global";
204
-
205
- import { makeToggle } from "kaplay-ui/inputs";
206
-
207
- kaplay();
134
+ This example shows how to build a touch‑friendly UI using `addTextButton()` on mobile devices. It uses responsive scaling and KAPLAY’s `stretch` and `letterbox` features to adapt to different screen sizes.
208
135
 
209
- const toggle = makeToggle();
136
+ ### **Example**
210
137
 
211
- add(toggle);
138
+ ```js
139
+ import kaplay from "kaplay";
140
+ import kaplayUI from "kaplay-ui";
141
+
142
+ const k = kaplay({
143
+ width: 480, // required when using letterbox/stretch
144
+ height: 270,
145
+ background: [25, 25, 25],
146
+ plugins: [kaplayUI],
147
+
148
+ stretch: true, // resize canvas on mobile
149
+ letterbox: true, // preserve aspect ratio
150
+ });
151
+
152
+ function uiScale() {
153
+ return Math.min(k.width() / 400, 1.4);
154
+ }
155
+
156
+ function centerX(width) {
157
+ return k.center().x - width / 2;
158
+ }
159
+
160
+ k.scene("mobile-menu", () => {
161
+ const scale = uiScale();
162
+
163
+ k.add([
164
+ k.text("Mobile Menu", { size: 36 * scale }),
165
+ k.anchor("center"),
166
+ k.pos(k.center().x, 70 * scale),
167
+ ]);
168
+
169
+ const btnWidth = 260 * scale;
170
+ const btnHeight = 90 * scale;
171
+
172
+ const startBtn = k.addTextButton("Start", btnWidth, btnHeight);
173
+ startBtn.pos = k.vec2(centerX(btnWidth), 150 * scale);
174
+ startBtn.onClick(() => k.go("mobile-game"));
175
+ startBtn.onHover(() => (startBtn.color = k.rgb(140, 220, 140)));
176
+ startBtn.onHoverEnd(() => (startBtn.color = k.WHITE));
177
+
178
+ const settingsBtn = k.addTextButton("Settings", btnWidth, btnHeight);
179
+ settingsBtn.pos = k.vec2(centerX(btnWidth), 280 * scale);
180
+ settingsBtn.onClick(() => k.go("settings"));
181
+ settingsBtn.onHover(() => (settingsBtn.color = k.rgb(140, 160, 240)));
182
+ settingsBtn.onHoverEnd(() => (settingsBtn.color = k.WHITE));
183
+ });
184
+
185
+ k.scene("mobile-game", () => {
186
+ const scale = uiScale();
187
+
188
+ k.add([
189
+ k.text("Game Scene", { size: 28 * scale }),
190
+ k.anchor("center"),
191
+ k.pos(k.center().x, 90 * scale),
192
+ ]);
193
+
194
+ const backBtn = k.addTextButton("Back", 200 * scale, 80 * scale);
195
+ backBtn.pos = k.vec2(centerX(200 * scale), k.height() - 120 * scale);
196
+ backBtn.onClick(() => k.go("mobile-menu"));
197
+ backBtn.onHover(() => (backBtn.scale = 1.1 * scale));
198
+ backBtn.onHoverEnd(() => (backBtn.scale = scale));
199
+ });
200
+
201
+ k.scene("settings", () => {
202
+ const scale = uiScale();
203
+
204
+ k.add([
205
+ k.text("Settings", { size: 32 * scale }),
206
+ k.anchor("center"),
207
+ k.pos(k.center().x, 70 * scale),
208
+ ]);
209
+
210
+ const backBtn = k.addTextButton("Back", 200 * scale, 80 * scale);
211
+ backBtn.pos = k.vec2(centerX(200 * scale), k.height() - 140 * scale);
212
+ backBtn.onClick(() => k.go("mobile-menu"));
213
+ });
214
+
215
+ k.go("mobile-menu");
212
216
  ```
213
217
 
214
- ##### State
215
-
216
- A cehckbox has the following state:
217
-
218
- | state | Type | Default | State change by |
219
- | --------- | --------- | ------- | --------------- |
220
- | `toggled` | `boolean` | false | Click on toggle |
221
-
222
- ##### Parameters
223
-
224
- A toggle can take the following parameters:
225
-
226
- | Parameter | Type | Default | Required | Description |
227
- | --------- | -------- | ------- | -------- | ----------------- |
228
- | `x` | `number` | 0 | ❌ No | Toggle x position |
229
- | `y` | `number` | 0 | ❌ No | Toggle y position |
230
- | `width` | `number` | 50 | ❌ No | Toggle width |
231
- | `height` | `number` | 25 | ❌ No | Toggle height |
232
-
233
- <br>
234
-
235
- ## License
236
-
237
- This project is licensed under the MIT License - see the LICENSE file for details.
218
+ ### ✔ Features demonstrated
238
219
 
239
- <br>
220
+ - Responsive UI scaling
221
+ - Touch‑friendly hit areas
222
+ - Hover animations for mobile
223
+ - Auto‑centered vertical layout
224
+ - Scene navigation
240
225
 
241
- ## Contact
226
+ ---
242
227
 
243
- Have questions or suggestions? Reach out via:
228
+ ## 📄 License
244
229
 
245
- - GitHub Issues
230
+ MIT free for personal and commercial use.
package/ROADMAP.md ADDED
@@ -0,0 +1,162 @@
1
+ # 📘 **KAPLAY‑UI — Updated Development Roadmap (v1)**
2
+
3
+ _(Reflecting current progress as of Phase 2 Step 2.4)_
4
+
5
+ This roadmap tracks the incremental development of the **Container** UI element and the overall plugin architecture for `kaplay-ui`.
6
+ It replaces the old roadmap and reflects the precise, step-based structure we are now following.
7
+
8
+ ---
9
+
10
+ # 🌱 **Phase 0 — Planning & API Definition (Completed)**
11
+
12
+ ### **0.1 – Folder Structure Setup** ✔
13
+
14
+ - Create `src/components/container/` directory
15
+ - Add `index.ts`, `container.types.ts`, `container.logic.ts`, `container.styles.ts`
16
+
17
+ ### **0.2 – Public API Definition** ✔
18
+
19
+ - Define developer experience (“DX sentence”)
20
+ - Draft ideal usage examples
21
+ - Decide initial required options (`width`, `height`)
22
+ - Decide return type (GameObj + UI helpers)
23
+ - Write full API Contract
24
+
25
+ ---
26
+
27
+ # 🧱 **Phase 1 — Minimal Functional Container (Completed)**
28
+
29
+ ### **1.1 – Type Definitions** ✔
30
+
31
+ - Create `UIContainerOptions`
32
+ - Create `UIContainerReturn`
33
+
34
+ ### **1.2 – Factory Scaffolding** ✔
35
+
36
+ - Add `createContainer()` factory
37
+ - Export from plugin via `k.addContainer()`
38
+ - Add placeholder logic/style hookups
39
+
40
+ ### **1.3 – Minimal Functional Implementation** ✔
41
+
42
+ - Create Kaplay rect
43
+ - Apply width/height
44
+ - Return real container GameObj
45
+ - Implement minimal `addChild()` (no positioning yet)
46
+
47
+ ---
48
+
49
+ # 🎨 **Phase 2 — Core Container Functionality (In Progress)**
50
+
51
+ ## ✔ Completed Steps
52
+
53
+ ### **2.1 – Add Basic Styling Support** ✔
54
+
55
+ - Introduce `defaultContainerStyles`
56
+ - Add `container.styles` field
57
+ - Add placeholder `setStyle()` method
58
+
59
+ ### **2.2 – Add Anchor Support (Scaffolding)** ✔
60
+
61
+ - Add `anchor?: string` to options
62
+ - Add `container.anchor` property
63
+ - Add `setAnchor()` method
64
+ - Add `applyAnchor()` placeholder
65
+ - Call anchor logic in `initContainerLogic()`
66
+
67
+ ## 🔄 **Current Step (Next to Implement)**
68
+
69
+ ### **2.3 – Apply Styles & Anchors Visually (NOT STARTED YET)**
70
+
71
+ This will include:
72
+
73
+ - Applying background color to the rect
74
+ - Applying borderWidth, borderColor, radius
75
+ - Applying padding to internal GameObj positioning
76
+ - Applying anchor visually via Kaplay’s `.anchor()` component
77
+ - Ensuring container size + style reflect options
78
+
79
+ ## ⏳ **Upcoming Step (Depends on Step 2.3)**
80
+
81
+ ### **2.4 – Implement Basic Child Positioning & Padding**
82
+
83
+ - Children positioned relative to container origin
84
+ - Apply padding offsets
85
+ - Children follow container movement
86
+ - Simple update loop to sync child positions
87
+
88
+ ---
89
+
90
+ # 📦 **Phase 3 — Layout Engine (Future)**
91
+
92
+ ### **3.1 – Layout Modes: none, vertical, horizontal**
93
+
94
+ ### **3.2 – Spacing support**
95
+
96
+ ### **3.3 – Auto-size based on children**
97
+
98
+ ### **3.4 – Alignment (start, center, end)**
99
+
100
+ ---
101
+
102
+ # ✨ **Phase 4 — Advanced Features (Future)**
103
+
104
+ ### **4.1 – Borders, shadows, hover states**
105
+
106
+ ### **4.2 – Themes & preset styles**
107
+
108
+ ### **4.3 – z-index / UI layers**
109
+
110
+ ### **4.4 – Optional clipping / scroll masking**
111
+
112
+ ---
113
+
114
+ # 📚 **Phase 5 — Docs & Testing**
115
+
116
+ ### **5.1 – Full README examples**
117
+
118
+ ### **5.2 – API documentation**
119
+
120
+ ### **5.3 – Unit tests for container behavior**
121
+
122
+ ### **5.4 – Interactive demo in `/test/game.ts`**
123
+
124
+ ---
125
+
126
+ # 🚀 **Phase 6 — v0.1.0 Release**
127
+
128
+ ### **6.1 – Code cleanup & final polish**
129
+
130
+ ### **6.2 – Publish `kaplay-ui` to npm**
131
+
132
+ ### **6.3 – Announce first usable Container component**
133
+
134
+ ---
135
+
136
+ # 🧭 **Where We Are Right Now**
137
+
138
+ As of your last message, you are here:
139
+
140
+ ### ⭐ **Phase 2 → Step 2.4 complete**
141
+
142
+ Meaning the next step to do together is:
143
+
144
+ # 👉 **Phase 2 Step 3 — Apply Styles & Anchors Visually**
145
+
146
+ This is where your container becomes:
147
+
148
+ - visually styled
149
+ - anchored correctly
150
+ - padded properly
151
+ - a _real_ UI element, not just a rectangle
152
+
153
+ ---
154
+
155
+ # If you'd like, I can now:
156
+
157
+ - Create a “live” ROADMAP.md file matching this structure
158
+ - Move you into Phase 2 Step 3
159
+ - Review your existing code to ensure everything matches the roadmap
160
+ - Add future sections (Buttons, Sliders, Text, etc.)
161
+
162
+ Just tell me what you'd like to do next.
Binary file
package/index.html ADDED
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>KAPLAY Plugin Template (TypeScript)</title>
7
+ </head>
8
+
9
+ <body>
10
+ <script src="./test/game.ts" type="module"></script>
11
+ </body>
12
+ </html>
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "kaplay-ui",
3
- "version": "0.20.1",
3
+ "version": "1.0.0-alpha.1",
4
4
  "description": "UI components for KAPLAY",
5
- "main": "index.js",
5
+ "type": "module",
6
+ "main": "src/index.ts",
7
+ "scripts": {
8
+ "dev": "vite dev",
9
+ "build": "vite build"
10
+ },
6
11
  "repository": {
7
12
  "type": "git",
8
13
  "url": "git+https://github.com/jbakchr/kaplay-ui.git"
@@ -19,7 +24,11 @@
19
24
  },
20
25
  "homepage": "https://github.com/jbakchr/kaplay-ui#readme",
21
26
  "dependencies": {
22
- "kaplay": "^3001.0.10"
27
+ "kaplay": "^3001.0.19"
23
28
  },
24
- "type": "module"
29
+ "devDependencies": {
30
+ "@types/node": "^25.5.0",
31
+ "vite": "^8.0.2",
32
+ "vite-plugin-dts": "^4.5.4"
33
+ }
25
34
  }
@@ -0,0 +1 @@
1
+ export * from "./text-button";
@@ -0,0 +1,24 @@
1
+ import type { KAPLAYCtx } from "kaplay";
2
+
3
+ import { makeButtonText } from "../../texts/index";
4
+
5
+ export function createTextButton(
6
+ k: KAPLAYCtx,
7
+ txt: string,
8
+ width: number,
9
+ height: number,
10
+ ) {
11
+ const btn = k.add([
12
+ k.rect(width, height),
13
+ k.outline(3),
14
+ k.pos(0, 0),
15
+ k.anchor("topleft"),
16
+ k.area(),
17
+ ]);
18
+
19
+ const btnTxt = makeButtonText(k, btn, txt);
20
+
21
+ btn.add(btnTxt);
22
+
23
+ return btn;
24
+ }
@@ -0,0 +1,31 @@
1
+ // src/components/container/container.logic.ts
2
+
3
+ import type { KAPLAYCtx } from "kaplay";
4
+ import type { UIContainerOptions, UIContainerReturn } from "./container.types";
5
+
6
+ /**
7
+ * Placeholder for the internal container logic.
8
+ * Will create the actual Kaplay GameObj in Phase 1 Step 3.
9
+ */
10
+ export function initContainerLogic(
11
+ _k: KAPLAYCtx,
12
+ container: UIContainerReturn,
13
+ opts: UIContainerOptions,
14
+ ) {
15
+ console.warn("initContainerLogic() placeholder running.");
16
+
17
+ // NEW: anchor preparation
18
+ applyAnchor(container, opts);
19
+ }
20
+
21
+ /**
22
+ * Placeholder function for applying anchor behavior.
23
+ *
24
+ * The real implementation will come in Phase 2 Step 3.
25
+ */
26
+ export function applyAnchor(
27
+ _container: UIContainerReturn,
28
+ _opts: UIContainerOptions,
29
+ ) {
30
+ console.warn("applyAnchor() not implemented yet.");
31
+ }
@@ -0,0 +1,22 @@
1
+ // src/components/container/container.styles.ts
2
+
3
+ /**
4
+ * Default styles for all UI Containers.
5
+ *
6
+ * These values will later be applied visually (Phase 2 Step 3),
7
+ * but for now they simply exist as the container's internal style model.
8
+ */
9
+ export const defaultContainerStyles = {
10
+ backgroundColor: "rgba(0, 0, 0, 0.4)", // translucent dark background
11
+ borderColor: "rgba(255, 255, 255, 0.1)", // subtle border
12
+ borderWidth: 0,
13
+ radius: 0,
14
+ };
15
+
16
+ /**
17
+ * Placeholder: in the future, this will apply the
18
+ * default styles to the actual Kaplay GameObj.
19
+ */
20
+ export function applyDefaultContainerStyles(_container: any) {
21
+ // Implementation will come later in Phase 2 Step 3.
22
+ }
@@ -0,0 +1,45 @@
1
+ // src/components/container/container.types.ts
2
+
3
+ /**
4
+ * UIContainerOptions (initial minimal version)
5
+ *
6
+ * Only width and height are required at this stage.
7
+ *
8
+ * Phase 2 Step 3 introduces padding:
9
+ *
10
+ * padding?: number
11
+ *
12
+ * Padding is optional. Default = 0.
13
+ * Padding represents empty space INSIDE the container.
14
+ * Children added to the container are offset by the padding
15
+ * on all sides (top, left, right, bottom).
16
+ *
17
+ * Example:
18
+ * const panel = k.addContainer({
19
+ * width: 300,
20
+ * height: 200,
21
+ * padding: 16,
22
+ * });
23
+ */
24
+ export interface UIContainerOptions {
25
+ width: number;
26
+ height: number;
27
+
28
+ anchor?: string; // "center" and so on
29
+
30
+ // Added in Phase 2 Step 3:
31
+ padding?: number;
32
+ }
33
+
34
+ /**
35
+ * UIContainerReturn (initial minimal version)
36
+ *
37
+ * The container will eventually merge this with a Kaplay GameObj.
38
+ */
39
+ export interface UIContainerReturn {
40
+ uiWidth: number;
41
+ uiHeight: number;
42
+ addChild(child: any): void;
43
+ anchor: string;
44
+ setAnchor(anchor: string): void;
45
+ }
@@ -0,0 +1,47 @@
1
+ // src/components/container/index.ts
2
+
3
+ import type { KAPLAYCtx } from "kaplay";
4
+ import type { UIContainerOptions } from "./container.types";
5
+ import { initContainerLogic } from "./container.logic";
6
+ import {
7
+ defaultContainerStyles,
8
+ applyDefaultContainerStyles,
9
+ } from "./container.styles";
10
+
11
+ /**
12
+ * Factory function for creating a UI Container.
13
+ * Phase 2 Step 1: Add styling scaffolding.
14
+ */
15
+ export function createContainer(k: KAPLAYCtx, opts: UIContainerOptions) {
16
+ const container = {
17
+ uiWidth: opts.width,
18
+ uiHeight: opts.height,
19
+
20
+ addChild: (_child: any) => {
21
+ console.warn("addChild() not implemented yet.");
22
+ },
23
+
24
+ styles: {
25
+ ...defaultContainerStyles,
26
+ },
27
+
28
+ setStyle(_newStyles: any) {
29
+ console.warn("setStyle() not implemented yet.");
30
+ },
31
+
32
+ // NEW: store anchor
33
+ anchor: opts.anchor ?? "topleft",
34
+
35
+ // NEW: runtime anchor setter
36
+ setAnchor(newAnchor: string) {
37
+ this.anchor = newAnchor;
38
+ console.warn("setAnchor() not implemented yet.");
39
+ },
40
+ };
41
+
42
+ // placeholder logic and style application
43
+ initContainerLogic(k, container, opts);
44
+ applyDefaultContainerStyles(container);
45
+
46
+ return container as any;
47
+ }
@@ -0,0 +1 @@
1
+ export * from "./buttons";
@@ -0,0 +1 @@
1
+ export * from "./text-button/text-button";
@@ -0,0 +1,24 @@
1
+ import type {
2
+ GameObj,
3
+ KAPLAYCtx,
4
+ PosComp,
5
+ RectComp,
6
+ OutlineComp,
7
+ AnchorComp,
8
+ AreaComp,
9
+ } from "kaplay";
10
+
11
+ export function makeButtonText(
12
+ k: KAPLAYCtx,
13
+ btn: GameObj<PosComp | RectComp | OutlineComp | AnchorComp | AreaComp>,
14
+ txt: string,
15
+ ) {
16
+ const btnTxt = k.make([
17
+ k.text(txt),
18
+ k.color(0, 0, 0),
19
+ k.pos(btn.width / 2, btn.height / 2),
20
+ k.anchor("center"),
21
+ ]);
22
+
23
+ return btnTxt;
24
+ }
package/src/index.ts ADDED
@@ -0,0 +1,59 @@
1
+ import type { KAPLAYCtx, GameObj } from "kaplay";
2
+
3
+ import { createTextButton } from "./components";
4
+
5
+ /**
6
+ * # KAPLAY UI Plugin
7
+ * _Add UI Game Objects to your game._
8
+ *
9
+ * ## Features
10
+ * - Text Button (`addTextButton()`)
11
+ */
12
+ export default function kaplayUI(k: KAPLAYCtx) {
13
+ return {
14
+ /**
15
+ * # Text button
16
+ * Creates a clickable game object containing a button with centered text.
17
+ *
18
+ * This helper provides sensible defaults for size, layout, and styling so you can
19
+ * quickly add UI buttons to your KAPLAY game.
20
+ *
21
+ * ## Default Parameter Values
22
+ * | Name | Default |
23
+ * |:---------|:-------------|
24
+ * | `txt` | `"Button"` |
25
+ * | `width` | `200` |
26
+ * | `height` | `100` |
27
+ *
28
+ * ## Default Styling
29
+ * The button object is created with:
30
+ * - `k.outline(3)`
31
+ * - `k.pos(0, 0)`
32
+ * - `k.anchor("topleft")`
33
+ * - `k.area()`
34
+ *
35
+ * @param {string} [txt="Button"]
36
+ * The text label displayed at the center of the button.
37
+ *
38
+ * @param {number} [width=200]
39
+ * Width of the button in pixels.
40
+ *
41
+ * @param {number} [height=100]
42
+ * Height of the button in pixels.
43
+ *
44
+ * @returns {GameObj}
45
+ * A KAPLAY Game Object representing the button with centered text.
46
+ *
47
+ * @example
48
+ * const btn = addTextButton();
49
+ * const playBtn = addTextButton("Play");
50
+ * const wideBtn = addTextButton("Play", 150);
51
+ * const smallBtn = addTextButton("Play", 150, 75);
52
+ */
53
+ addTextButton: (
54
+ txt: string = "Button",
55
+ width: number = 200,
56
+ height: number = 100,
57
+ ): GameObj => createTextButton(k, txt, width, height),
58
+ };
59
+ }
package/test/game.ts ADDED
@@ -0,0 +1,9 @@
1
+ import kaplay from "kaplay";
2
+ import kaplayUI from "../src/index";
3
+
4
+ const k = kaplay({
5
+ plugins: [kaplayUI],
6
+ debugKey: "d",
7
+ });
8
+
9
+ const txtBtn = k.addTextButton("Hello");
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "skipLibCheck": true,
8
+ /* Bundler mode */
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "isolatedModules": true,
12
+ "moduleDetection": "force",
13
+ "noEmit": true,
14
+ /* Linting */
15
+ "strict": true,
16
+ "noUnusedLocals": true,
17
+ "noUnusedParameters": true,
18
+ "noFallthroughCasesInSwitch": true
19
+ },
20
+ "include": ["src"]
21
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { resolve } from "path";
2
+ import { defineConfig } from "vite";
3
+ import dts from "vite-plugin-dts";
4
+
5
+ export default defineConfig({
6
+ build: {
7
+ lib: {
8
+ entry: resolve(__dirname, "src/index.ts"),
9
+ name: "uiPlugin",
10
+ fileName: "uiplugin",
11
+ },
12
+ },
13
+ plugins: [dts({ rollupTypes: true, tsconfigPath: "./tsconfig.json" })],
14
+ });
Binary file
package/inputs/index.js DELETED
@@ -1,226 +0,0 @@
1
- import "kaplay/global";
2
-
3
- import cbIcon from "../assets/cb-icon.png";
4
-
5
- /**
6
- * Makes button with centered text
7
- * @param {string} txt - Button text to display
8
- * @param {number} x - The x postion to set (default is 0).
9
- * @param {number} y - The x postion to set (default is 0)
10
- * @param {number} width - Width of button (default is 100)
11
- * @param {number} height - Height of button (default is 50)
12
- * @param {number} btnRadius - Border radius of button (default is 8)
13
- * @param {number} btnOutline - Button outline (default is 1)
14
- * @param {number} txtSize - Text size of button (default is 15)
15
- * @returns {GameObj}
16
- */
17
- export const makeTextButton = (
18
- txt,
19
- x = 0,
20
- y = 0,
21
- width = 100,
22
- height = 50,
23
- btnRadius = 8,
24
- btnOutline = 1,
25
- txtSize = 15
26
- ) => {
27
- // Make button
28
- const btn = make([
29
- rect(width, height, { radius: btnRadius }),
30
- pos(x, y),
31
- area(),
32
- scale(1),
33
- outline(btnOutline),
34
- color(255, 255, 255),
35
- ]);
36
-
37
- // Make button text
38
- const btnText = make([
39
- text(txt, { size: txtSize }),
40
- pos(width / 2, height / 2),
41
- anchor("center"),
42
- color(0, 0, 0),
43
- ]);
44
-
45
- // Add text to button
46
- btn.add(btnText);
47
-
48
- return btn;
49
- };
50
-
51
- /**
52
- * Makes toggle
53
- * @param {number} x - The x postion to set (default is 0)
54
- * @param {number} y - The x postion to set (default is 0)
55
- * @param {number} width - Toggle width (default is 50)
56
- * @param {number} height - Toggle height (default is 25)
57
- * @returns {GameObj}
58
- */
59
- export const makeToggle = (x = 0, y = 0, width = 50, height = 25) => {
60
- // Toggle base
61
- const toggle = make([
62
- rect(width, height, { radius: height / 2 }),
63
- pos(x, y),
64
- color(169, 169, 169),
65
- area(),
66
- {
67
- toggled: false,
68
- },
69
- ]);
70
-
71
- // Toggle button
72
- const toggleBtn = make([
73
- circle(height * 0.4),
74
- color(WHITE),
75
- pos(height / 2, height / 2),
76
- ]);
77
-
78
- // Add button to toggleBase
79
- toggle.add(toggleBtn);
80
-
81
- toggle.onClick(() => {
82
- if (toggle.toggled) {
83
- toggle.use(color(169, 169, 169));
84
- toggleBtn.use(pos(height / 2, height / 2));
85
- toggle.toggled = false;
86
- } else {
87
- toggle.use(color(148, 188, 236));
88
- toggleBtn.use(pos(width - height / 2, height / 2));
89
- toggle.toggled = true;
90
- }
91
- });
92
-
93
- return toggle;
94
- };
95
-
96
- /**
97
- * Makes checkbox
98
- * @param {number} x - The x postion to set (default is 0)
99
- * @param {number} y - The x postion to set (default is 0)
100
- * @param {number} width - Checkbox width (default is 25)
101
- * @param {number} height - Checkbox height (default is 25)
102
- * @returns {GameObj}
103
- */
104
- export const makeCheckbox = (x = 0, y = 0, width = 25, height = 25) => {
105
- loadSprite("cb", cbIcon);
106
-
107
- const checkbox = make([
108
- rect(width, height, { radius: 4 }),
109
- pos(x, y),
110
- color(255, 255, 255),
111
- outline(1),
112
- area(),
113
- {
114
- checked: false,
115
- },
116
- ]);
117
-
118
- const checkedIcon = make([sprite("cb", { width, height }), area()]);
119
-
120
- checkbox.onClick(() => {
121
- if (checkbox.checked) {
122
- checkbox.use(color(255, 255, 255));
123
- checkbox.remove(checkedIcon);
124
- checkbox.checked = false;
125
- } else {
126
- checkbox.use(color(148, 188, 236));
127
- checkbox.add(checkedIcon);
128
- checkbox.checked = true;
129
- }
130
- });
131
-
132
- return checkbox;
133
- };
134
-
135
- /**
136
- * Makes switch
137
- * @param {number} x - Switch x postion (default is 0)
138
- * @param {number} y - Switch y postion (default is 0)
139
- * @param {number} width - Switch width (default is 50)
140
- * @param {number} height - Switch height (default is 25)
141
- * @returns {GameObj}
142
- */
143
- export const makeSwitch = (x = 0, y = 0, width = 50, height = 25) => {
144
- // Make switch base
145
- const switchBase = make([
146
- rect(width, height),
147
- pos(x, y),
148
- opacity(0),
149
- area(),
150
- {
151
- switched: false,
152
- },
153
- ]);
154
-
155
- // Make switch line
156
- const switchLine = make([
157
- rect(width, height / 2, { radius: height / 4 }),
158
- color(169, 169, 169),
159
- pos(0, height / 2 - height / 4),
160
- area(),
161
- ]);
162
-
163
- // Make switch circle
164
- const switchCircle = make([circle(height / 2), pos(height / 2, height / 2)]);
165
-
166
- // On click
167
- switchBase.onClick(() => {
168
- if (switchBase.switched) {
169
- switchLine.use(color(169, 169, 169));
170
- switchCircle.use(color(255, 255, 255));
171
- switchCircle.use(pos(height / 2, height / 2));
172
- switchBase.switched = false;
173
- } else {
174
- switchLine.use(color(148, 188, 236));
175
- switchCircle.use(color(24, 118, 210));
176
- switchCircle.use(pos(width - switchCircle.radius, height / 2));
177
- switchBase.switched = true;
178
- }
179
- });
180
-
181
- // Add line and circle
182
- switchBase.add(switchLine);
183
- switchBase.add(switchCircle);
184
-
185
- return switchBase;
186
- };
187
-
188
- /**
189
- * Makes text input
190
- * @param {number} x - Text input x postion (default is 0)
191
- * @param {number} y - Text input y postion (default is 0)
192
- * @param {number} width - Text input width (default is 400)
193
- * @param {number} txtSize - Text input text size (default is 15)
194
- * @param {number} pad - Text input padding (default is 10)
195
- * @param {boolean} hasFocus - Text input focus (default is true)
196
- * @returns {GameObj}
197
- */
198
- export const makeTextInput = (
199
- x = 0,
200
- y = 0,
201
- width = 400,
202
- txtSize = 15,
203
- pad = 10,
204
- hasFocus = true
205
- ) => {
206
- // Text input container
207
- const inputBase = make([
208
- rect(width, txtSize + pad * 2),
209
- pos(x, y),
210
- area(),
211
- outline(1),
212
- ]);
213
-
214
- // Text input
215
- const input = make([
216
- text("", { width: width - pad * 2, size: txtSize }),
217
- textInput(hasFocus),
218
- color(BLACK),
219
- pos(pad, pad),
220
- area(),
221
- ]);
222
-
223
- inputBase.add(input);
224
-
225
- return inputBase;
226
- };
File without changes