kaplay-ui 1.0.0-alpha.13 → 1.0.0-alpha.14
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 +108 -83
- package/dist/uiplugin.js +207 -75
- package/dist/uiplugin.umd.cjs +1 -1
- package/package.json +1 -1
- package/src/index.ts +213 -47
package/README.md
CHANGED
|
@@ -17,6 +17,19 @@ For now it helps you build Game Objects like text buttons and labels — without
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
+
## ✨ _What this plugin currently provides_
|
|
21
|
+
|
|
22
|
+
When installed, this plugin extends the KAPLAY context (`k`) with:
|
|
23
|
+
|
|
24
|
+
- `k.addTextButton()` – interactive buttons with centered text
|
|
25
|
+
- `k.addLabel()` – lightweight, non-interactive text labels
|
|
26
|
+
|
|
27
|
+
Each helper returns a regular KAPLAY game object enhanced with
|
|
28
|
+
**convenience methods** for changing size, position, colors, text, and more
|
|
29
|
+
after creation.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
20
33
|
## 📦 Installation
|
|
21
34
|
|
|
22
35
|
### Prerelease (new v1 work)
|
|
@@ -29,11 +42,9 @@ This gives you the latest `1.0.0‑alpha.*` builds.
|
|
|
29
42
|
|
|
30
43
|
---
|
|
31
44
|
|
|
32
|
-
## 🚀
|
|
45
|
+
## 🚀 Quick start (_1.0.0-alpha.\*_)
|
|
33
46
|
|
|
34
|
-
**Kaplay
|
|
35
|
-
|
|
36
|
-
The `kaplayUI` plugin is exported from the package root:
|
|
47
|
+
The **Kaplay-UI** plugin is exported as `kaplayUI` from the package root:
|
|
37
48
|
|
|
38
49
|
```ts
|
|
39
50
|
import kaplay from "kaplay";
|
|
@@ -47,130 +58,144 @@ const k = kaplay({
|
|
|
47
58
|
You now have access to the UI helpers via your `k` instance:
|
|
48
59
|
|
|
49
60
|
```ts
|
|
50
|
-
const btn = k.addTextButton("
|
|
51
|
-
|
|
61
|
+
const btn = k.addTextButton("Start");
|
|
62
|
+
btn.onClick(() => {
|
|
63
|
+
k.go("game");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const lbl = k.addLabel("Score: 0");
|
|
67
|
+
lbl.setLabelText("Score: 1");
|
|
52
68
|
```
|
|
53
69
|
|
|
54
70
|
---
|
|
55
71
|
|
|
56
72
|
## 🧩 Game Objects (_**1.0.0‑alpha.\***_)
|
|
57
73
|
|
|
58
|
-
### 🔤
|
|
59
|
-
|
|
60
|
-
Creates a button-like GameObj with centered text and some convenient defaults.
|
|
74
|
+
### 🔤 Text Button — `addTextButton()`
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
Creates a clickable button with centered text and default visuals.
|
|
63
77
|
|
|
64
78
|
```ts
|
|
65
|
-
addTextButton(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
79
|
+
const btn = k.addTextButton("Start", {
|
|
80
|
+
width: 200,
|
|
81
|
+
height: 80,
|
|
82
|
+
});
|
|
69
83
|
```
|
|
70
84
|
|
|
71
|
-
|
|
85
|
+
Buttons support runtime updates such as:
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
| `posY` | `0` |
|
|
80
|
-
| `outline` | `3` |
|
|
81
|
-
| `txtSize` | `22` |
|
|
87
|
+
```ts
|
|
88
|
+
btn.setSize(300, 100);
|
|
89
|
+
btn.setButtonColor([255, 120, 120]);
|
|
90
|
+
btn.setButtonText("Go!");
|
|
91
|
+
btn.setButtonTextSize(24);
|
|
92
|
+
```
|
|
82
93
|
|
|
83
|
-
|
|
94
|
+
Perfect for menus, dialogs, and in‑game actions.
|
|
95
|
+
|
|
96
|
+
---
|
|
84
97
|
|
|
85
|
-
|
|
86
|
-
| ---------------------- | :-------------- |
|
|
87
|
-
| `button anchor` | `"topleft"` |
|
|
88
|
-
| `button color` | `200, 200, 200` |
|
|
89
|
-
| `button outline color` | `92, 91, 91` |
|
|
90
|
-
| `text anchor` | `"center"` |
|
|
91
|
-
| `text color` | `0, 0, 0` |
|
|
98
|
+
### 🏷️ Label — `addLabel()`
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
Creates a lightweight background + text container for HUD elements or titles.
|
|
94
101
|
|
|
95
102
|
```ts
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
const label = k.addLabel("Score: 0");
|
|
104
|
+
```
|
|
98
105
|
|
|
99
|
-
|
|
100
|
-
const btn2 = k.addTextButton("Play!", { posX: 300, posY: 200 });
|
|
106
|
+
Update it dynamically:
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
```ts
|
|
109
|
+
label.setLabelText("Score: 10");
|
|
110
|
+
label.setLabelTextColor([255, 255, 0]);
|
|
111
|
+
label.setOpacity(0.9);
|
|
106
112
|
```
|
|
107
113
|
|
|
114
|
+
Ideal for HUDs, counters, status text, and overlays.
|
|
115
|
+
|
|
108
116
|
---
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
## 🎨 Customization
|
|
111
119
|
|
|
112
|
-
|
|
120
|
+
kaplay-ui is designed to be **customized imperatively**, without hiding
|
|
121
|
+
or abstracting away KAPLAY’s core APIs.
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
### ✅ Option-based customization (at creation)
|
|
124
|
+
|
|
125
|
+
Both helpers accept an optional `opts` object for common configuration:
|
|
115
126
|
|
|
116
127
|
```ts
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
const btn = k.addTextButton("Options", {
|
|
129
|
+
width: 250,
|
|
130
|
+
height: 70,
|
|
131
|
+
posX: 100,
|
|
132
|
+
posY: 200,
|
|
133
|
+
radius: 8,
|
|
134
|
+
});
|
|
121
135
|
```
|
|
122
136
|
|
|
123
|
-
|
|
137
|
+
---
|
|
124
138
|
|
|
125
|
-
|
|
126
|
-
| --------- | ------- |
|
|
127
|
-
| `width` | `160` |
|
|
128
|
-
| `height` | `96` |
|
|
129
|
-
| `txtSize` | `22` |
|
|
139
|
+
### ✅ Runtime customization (after creation)
|
|
130
140
|
|
|
131
|
-
|
|
141
|
+
Each UI element exposes helper methods for updating its appearance and layout:
|
|
132
142
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
| `label anchor` | `"topleft"` |
|
|
139
|
-
| `text color` | `255, 255, 255` |
|
|
140
|
-
| `text anchor` | `"center"` |
|
|
143
|
+
```ts
|
|
144
|
+
btn.setPosition(150, 220);
|
|
145
|
+
btn.setButtonColor([80, 160, 255]);
|
|
146
|
+
btn.setButtonTextColor([255, 255, 255]);
|
|
147
|
+
```
|
|
141
148
|
|
|
142
|
-
|
|
149
|
+
This makes it easy to animate, react to state changes, or reuse UI elements.
|
|
143
150
|
|
|
144
|
-
|
|
145
|
-
// Basic label
|
|
146
|
-
const lbl2 = k.addLabel("Score: 0");
|
|
151
|
+
---
|
|
147
152
|
|
|
148
|
-
|
|
149
|
-
const lbl3 = k.addLabel("Start", { width: 100, height: 50 });
|
|
153
|
+
### ✅ Full KAPLAY access
|
|
150
154
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const scoreLabel = k.addLabel(`Score: ${score}`);
|
|
155
|
+
UI elements are **regular KAPLAY game objects**, so you can still use all
|
|
156
|
+
standard KAPLAY features:
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
```ts
|
|
159
|
+
btn.use(k.opacity(0.8));
|
|
160
|
+
btn.onHover(() => btn.setScale(1.1));
|
|
161
|
+
label.use(k.rotate(5));
|
|
159
162
|
```
|
|
160
163
|
|
|
161
|
-
|
|
164
|
+
kaplay-ui never locks you into a restricted UI model.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 🧠 Design philosophy
|
|
169
|
+
|
|
170
|
+
kaplay-ui is intentionally simple:
|
|
171
|
+
|
|
172
|
+
- ✅ No retained UI trees
|
|
173
|
+
- ✅ No layout engine
|
|
174
|
+
- ✅ No reactive framework
|
|
175
|
+
- ✅ Just KAPLAY game objects + helpers
|
|
176
|
+
|
|
177
|
+
You stay in control of how and when UI updates happen.
|
|
162
178
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 📚 Documentation
|
|
182
|
+
|
|
183
|
+
- Full API documentation is available via **JSDocs**
|
|
184
|
+
- All helpers are strongly typed and editor-friendly
|
|
185
|
+
- Hover over methods in your editor to explore options
|
|
168
186
|
|
|
169
187
|
---
|
|
170
188
|
|
|
171
189
|
## 🛣️ Roadmap
|
|
172
190
|
|
|
173
|
-
|
|
191
|
+
Future components may include:
|
|
192
|
+
|
|
193
|
+
- Toggles
|
|
194
|
+
- Sliders
|
|
195
|
+
- Panels / containers
|
|
196
|
+
|
|
197
|
+
See the roadmap here:
|
|
198
|
+
👉 <https://github.com/jbakchr/kaplay-ui/blob/v1/ROADMAP.md>
|
|
174
199
|
|
|
175
200
|
---
|
|
176
201
|
|
package/dist/uiplugin.js
CHANGED
|
@@ -1,62 +1,48 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/helpers/color-utils.ts
|
|
2
2
|
function e(e, t, n) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
e.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
if (Array.isArray(n)) {
|
|
4
|
+
t.use(e.color([
|
|
5
|
+
n[0],
|
|
6
|
+
n[1],
|
|
7
|
+
n[2]
|
|
8
|
+
]));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (typeof n == "string") {
|
|
12
|
+
t.use(e.color(n));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (typeof n == "object" && "r" in n) {
|
|
16
|
+
t.use(e.color(e.rgb(n.r, n.g, n.b)));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
t.use(e.color(n));
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
e.rect(n, r),
|
|
31
|
-
e.pos(0, 0),
|
|
32
|
-
e.color(0, 0, 0),
|
|
33
|
-
e.opacity(.7),
|
|
34
|
-
e.anchor("topleft")
|
|
35
|
-
]);
|
|
21
|
+
function t(e, t, n, r) {
|
|
22
|
+
if (typeof r == "string") {
|
|
23
|
+
t.use(e.outline(n, e.rgb(r)));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(r)) {
|
|
27
|
+
t.use(e.outline(n, e.rgb(r[0], r[1], r[2])));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
36
30
|
}
|
|
37
31
|
//#endregion
|
|
38
|
-
//#region src/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
...n
|
|
43
|
-
};
|
|
44
|
-
return e.make([
|
|
45
|
-
e.text(t, { size: o }),
|
|
46
|
-
e.color(0, 0, 0),
|
|
47
|
-
e.pos(r, i),
|
|
48
|
-
e.anchor(a)
|
|
49
|
-
]);
|
|
32
|
+
//#region src/helpers/layout-utils.ts
|
|
33
|
+
var n = new Set(["anchor", "rect"]);
|
|
34
|
+
function r(e) {
|
|
35
|
+
return n.has(e);
|
|
50
36
|
}
|
|
51
37
|
//#endregion
|
|
52
38
|
//#region src/helpers/pos-utils.ts
|
|
53
|
-
function
|
|
39
|
+
function i(e) {
|
|
54
40
|
return {
|
|
55
41
|
cX: e.width / 2,
|
|
56
42
|
cY: e.height / 2
|
|
57
43
|
};
|
|
58
44
|
}
|
|
59
|
-
function
|
|
45
|
+
function a(e, t, n, r, i) {
|
|
60
46
|
switch (t.anchor) {
|
|
61
47
|
case "bot":
|
|
62
48
|
n.use(e.pos(0 * r, -1 * i));
|
|
@@ -89,43 +75,189 @@ function i(e, t, n, r, i) {
|
|
|
89
75
|
}
|
|
90
76
|
}
|
|
91
77
|
//#endregion
|
|
92
|
-
//#region src/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
78
|
+
//#region src/components/label.ts
|
|
79
|
+
function o(t, n) {
|
|
80
|
+
let { width: r, height: o, radius: s, posX: c, posY: l, opacity: u, lblColor: d } = {
|
|
81
|
+
width: 160,
|
|
82
|
+
height: 96,
|
|
83
|
+
radius: 0,
|
|
84
|
+
posX: 0,
|
|
85
|
+
posY: 0,
|
|
86
|
+
opacity: .7,
|
|
87
|
+
lblColor: [
|
|
88
|
+
0,
|
|
89
|
+
0,
|
|
90
|
+
0
|
|
91
|
+
],
|
|
92
|
+
...n
|
|
93
|
+
}, f = t.make([
|
|
94
|
+
t.rect(r, o, { radius: s }),
|
|
95
|
+
t.pos(c, l),
|
|
96
|
+
t.opacity(u),
|
|
97
|
+
t.anchor("topleft"),
|
|
98
|
+
{
|
|
99
|
+
setSize(e, n) {
|
|
100
|
+
f.width = e, f.height = n;
|
|
101
|
+
let { cX: r, cY: o } = i(f);
|
|
102
|
+
a(t, f, f.children[0], r, o);
|
|
103
|
+
},
|
|
104
|
+
setRadius(e) {
|
|
105
|
+
f.radius = e;
|
|
106
|
+
},
|
|
107
|
+
setPosition(e, t) {
|
|
108
|
+
f.pos.x = e, f.pos.y = t;
|
|
109
|
+
},
|
|
110
|
+
setOpacity(e) {
|
|
111
|
+
f.opacity = e;
|
|
112
|
+
},
|
|
113
|
+
setLabelColor(n) {
|
|
114
|
+
e(t, f, n);
|
|
115
|
+
},
|
|
116
|
+
setLabelText(e) {
|
|
117
|
+
let t = f.children[0];
|
|
118
|
+
t.text = e;
|
|
119
|
+
},
|
|
120
|
+
setLabelTextColor(n) {
|
|
121
|
+
let r = f.children[0];
|
|
122
|
+
e(t, r, n);
|
|
123
|
+
},
|
|
124
|
+
setLabelTextSize(e) {
|
|
125
|
+
let t = f.children[0];
|
|
126
|
+
t.textSize = e;
|
|
127
|
+
},
|
|
128
|
+
setLabelAnchor(e) {
|
|
129
|
+
f.anchor = e;
|
|
130
|
+
let { cX: n, cY: r } = i(f);
|
|
131
|
+
a(t, f, f.children[0], n, r);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
]);
|
|
135
|
+
return e(t, f, d), f;
|
|
100
136
|
}
|
|
101
137
|
//#endregion
|
|
102
|
-
//#region src/
|
|
103
|
-
function s(
|
|
104
|
-
let
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
138
|
+
//#region src/components/button.ts
|
|
139
|
+
function s(n, r, o) {
|
|
140
|
+
let { width: s, height: c, posX: l, posY: u, radius: d, outline: f, btnColor: p, outlineColor: m } = {
|
|
141
|
+
width: 150,
|
|
142
|
+
height: 60,
|
|
143
|
+
posX: 0,
|
|
144
|
+
posY: 0,
|
|
145
|
+
radius: 10,
|
|
146
|
+
outline: 3,
|
|
147
|
+
btnColor: [
|
|
148
|
+
200,
|
|
149
|
+
200,
|
|
150
|
+
200
|
|
151
|
+
],
|
|
152
|
+
outlineColor: "#5c5b5b",
|
|
153
|
+
...r
|
|
154
|
+
}, h = n.make([
|
|
155
|
+
n.rect(s, c, { radius: d }),
|
|
156
|
+
n.pos(l, u),
|
|
157
|
+
n.anchor(o),
|
|
158
|
+
n.area(),
|
|
159
|
+
{
|
|
160
|
+
setSize(e, t) {
|
|
161
|
+
h.width = e, h.height = t;
|
|
162
|
+
let { cX: r, cY: o } = i(h);
|
|
163
|
+
a(n, h, h.children[0], r, o);
|
|
164
|
+
},
|
|
165
|
+
setPosition(e, t) {
|
|
166
|
+
h.pos.x = e, h.pos.y = t;
|
|
167
|
+
},
|
|
168
|
+
setRadius(e) {
|
|
169
|
+
h.radius = e;
|
|
170
|
+
},
|
|
171
|
+
setOutline(e) {
|
|
172
|
+
t(n, h, e, m);
|
|
173
|
+
},
|
|
174
|
+
setButtonText(e) {
|
|
175
|
+
let t = h.children[0];
|
|
176
|
+
t.text = e;
|
|
177
|
+
},
|
|
178
|
+
setButtonTextSize(e) {
|
|
179
|
+
let t = h.children[0];
|
|
180
|
+
t.textSize = e;
|
|
181
|
+
},
|
|
182
|
+
setButtonColor(t) {
|
|
183
|
+
e(n, h, t);
|
|
184
|
+
},
|
|
185
|
+
setButtonOutlineColor(e) {
|
|
186
|
+
t(n, h, f, e);
|
|
187
|
+
},
|
|
188
|
+
setAnchor(e) {
|
|
189
|
+
h.anchor = e;
|
|
190
|
+
let { cX: t, cY: r } = i(h);
|
|
191
|
+
a(n, h, h.children[0], t, r);
|
|
192
|
+
},
|
|
193
|
+
setButtonTextColor(t) {
|
|
194
|
+
let r = h.children[0];
|
|
195
|
+
e(n, r, t);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
]);
|
|
199
|
+
return e(n, h, p), t(n, h, f, m), h;
|
|
200
|
+
}
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/components/text.ts
|
|
203
|
+
function c(t, n, r, i, a, o) {
|
|
204
|
+
let { txtSize: s, txtColor: c } = {
|
|
205
|
+
txtSize: 22,
|
|
206
|
+
...r
|
|
207
|
+
}, l = t.make([
|
|
208
|
+
t.text(n, { size: s }),
|
|
209
|
+
t.pos(i, a),
|
|
210
|
+
t.anchor(o)
|
|
211
|
+
]);
|
|
212
|
+
return e(t, l, c), l;
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/elements/label.ts
|
|
216
|
+
function l(e, t, n) {
|
|
217
|
+
let s = {
|
|
218
|
+
txtColor: [
|
|
219
|
+
255,
|
|
220
|
+
255,
|
|
221
|
+
255
|
|
222
|
+
],
|
|
223
|
+
...n
|
|
224
|
+
}, l = o(e, s), { cX: u, cY: d } = i(l), f = c(e, t, s, u, d, "center");
|
|
225
|
+
return l.add(f), e.add(l), l.onUse((t) => {
|
|
226
|
+
if (r(t)) {
|
|
227
|
+
let { cX: t, cY: n } = i(l);
|
|
228
|
+
a(e, l, f, t, n);
|
|
109
229
|
}
|
|
110
|
-
}),
|
|
111
|
-
t.setCursor("pointer");
|
|
112
|
-
}), c.onHoverEnd(() => {
|
|
113
|
-
t.setCursor("default");
|
|
114
|
-
}), c;
|
|
230
|
+
}), l;
|
|
115
231
|
}
|
|
116
232
|
//#endregion
|
|
117
|
-
//#region src/elements/
|
|
118
|
-
function
|
|
119
|
-
let o =
|
|
120
|
-
|
|
233
|
+
//#region src/elements/text-button.ts
|
|
234
|
+
function u(e, t, n) {
|
|
235
|
+
let o = {
|
|
236
|
+
txtColor: [
|
|
237
|
+
0,
|
|
238
|
+
0,
|
|
239
|
+
0
|
|
240
|
+
],
|
|
241
|
+
...n
|
|
242
|
+
}, l = s(e, o, "topleft"), { cX: u, cY: d } = i(l), f = c(e, t, o, u, d, "center");
|
|
243
|
+
return l.add(f), e.add(l), l.onUse((t) => {
|
|
244
|
+
if (r(t)) {
|
|
245
|
+
let { cX: t, cY: n } = i(l);
|
|
246
|
+
a(e, l, f, t, n);
|
|
247
|
+
}
|
|
248
|
+
}), l.onHover(() => {
|
|
249
|
+
e.setCursor("pointer");
|
|
250
|
+
}), l.onHoverEnd(() => {
|
|
251
|
+
e.setCursor("default");
|
|
252
|
+
}), l;
|
|
121
253
|
}
|
|
122
254
|
//#endregion
|
|
123
255
|
//#region src/index.ts
|
|
124
|
-
function
|
|
256
|
+
function d(e) {
|
|
125
257
|
return {
|
|
126
|
-
addTextButton: (t, n = {}) =>
|
|
127
|
-
addLabel: (t, n = {}) =>
|
|
258
|
+
addTextButton: (t, n = {}) => u(e, t, n),
|
|
259
|
+
addLabel: (t, n = {}) => l(e, t, n)
|
|
128
260
|
};
|
|
129
261
|
}
|
|
130
262
|
//#endregion
|
|
131
|
-
export {
|
|
263
|
+
export { d as default };
|
package/dist/uiplugin.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t():typeof define==`function`&&define.amd?define([],t):(e=typeof globalThis<`u`?globalThis:e||self,e.uiPlugin=t())})(this,function(){function e(e,t,n){
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?module.exports=t():typeof define==`function`&&define.amd?define([],t):(e=typeof globalThis<`u`?globalThis:e||self,e.uiPlugin=t())})(this,function(){function e(e,t,n){if(Array.isArray(n)){t.use(e.color([n[0],n[1],n[2]]));return}if(typeof n==`string`){t.use(e.color(n));return}if(typeof n==`object`&&`r`in n){t.use(e.color(e.rgb(n.r,n.g,n.b)));return}t.use(e.color(n))}function t(e,t,n,r){if(typeof r==`string`){t.use(e.outline(n,e.rgb(r)));return}if(Array.isArray(r)){t.use(e.outline(n,e.rgb(r[0],r[1],r[2])));return}}var n=new Set([`anchor`,`rect`]);function r(e){return n.has(e)}function i(e){return{cX:e.width/2,cY:e.height/2}}function a(e,t,n,r,i){switch(t.anchor){case`bot`:n.use(e.pos(0*r,-1*i));break;case`botleft`:n.use(e.pos(1*r,-1*i));break;case`botright`:n.use(e.pos(-1*r,-1*i));break;case`center`:n.use(e.pos(0*r,0*i));break;case`left`:n.use(e.pos(1*r,0*i));break;case`right`:n.use(e.pos(-1*r,0*i));break;case`top`:n.use(e.pos(0*r,1*i));break;case`topleft`:n.use(e.pos(1*r,1*i));break;case`topright`:n.use(e.pos(-1*r,1*i));break;default:break}}function o(t,n){let{width:r,height:o,radius:s,posX:c,posY:l,opacity:u,lblColor:d}={width:160,height:96,radius:0,posX:0,posY:0,opacity:.7,lblColor:[0,0,0],...n},f=t.make([t.rect(r,o,{radius:s}),t.pos(c,l),t.opacity(u),t.anchor(`topleft`),{setSize(e,n){f.width=e,f.height=n;let{cX:r,cY:o}=i(f);a(t,f,f.children[0],r,o)},setRadius(e){f.radius=e},setPosition(e,t){f.pos.x=e,f.pos.y=t},setOpacity(e){f.opacity=e},setLabelColor(n){e(t,f,n)},setLabelText(e){let t=f.children[0];t.text=e},setLabelTextColor(n){let r=f.children[0];e(t,r,n)},setLabelTextSize(e){let t=f.children[0];t.textSize=e},setLabelAnchor(e){f.anchor=e;let{cX:n,cY:r}=i(f);a(t,f,f.children[0],n,r)}}]);return e(t,f,d),f}function s(n,r,o){let{width:s,height:c,posX:l,posY:u,radius:d,outline:f,btnColor:p,outlineColor:m}={width:150,height:60,posX:0,posY:0,radius:10,outline:3,btnColor:[200,200,200],outlineColor:`#5c5b5b`,...r},h=n.make([n.rect(s,c,{radius:d}),n.pos(l,u),n.anchor(o),n.area(),{setSize(e,t){h.width=e,h.height=t;let{cX:r,cY:o}=i(h);a(n,h,h.children[0],r,o)},setPosition(e,t){h.pos.x=e,h.pos.y=t},setRadius(e){h.radius=e},setOutline(e){t(n,h,e,m)},setButtonText(e){let t=h.children[0];t.text=e},setButtonTextSize(e){let t=h.children[0];t.textSize=e},setButtonColor(t){e(n,h,t)},setButtonOutlineColor(e){t(n,h,f,e)},setAnchor(e){h.anchor=e;let{cX:t,cY:r}=i(h);a(n,h,h.children[0],t,r)},setButtonTextColor(t){let r=h.children[0];e(n,r,t)}}]);return e(n,h,p),t(n,h,f,m),h}function c(t,n,r,i,a,o){let{txtSize:s,txtColor:c}={txtSize:22,...r},l=t.make([t.text(n,{size:s}),t.pos(i,a),t.anchor(o)]);return e(t,l,c),l}function l(e,t,n){let s={txtColor:[255,255,255],...n},l=o(e,s),{cX:u,cY:d}=i(l),f=c(e,t,s,u,d,`center`);return l.add(f),e.add(l),l.onUse(t=>{if(r(t)){let{cX:t,cY:n}=i(l);a(e,l,f,t,n)}}),l}function u(e,t,n){let o={txtColor:[0,0,0],...n},l=s(e,o,`topleft`),{cX:u,cY:d}=i(l),f=c(e,t,o,u,d,`center`);return l.add(f),e.add(l),l.onUse(t=>{if(r(t)){let{cX:t,cY:n}=i(l);a(e,l,f,t,n)}}),l.onHover(()=>{e.setCursor(`pointer`)}),l.onHoverEnd(()=>{e.setCursor(`default`)}),l}function d(e){return{addTextButton:(t,n={})=>u(e,t,n),addLabel:(t,n={})=>l(e,t,n)}}return d});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { KAPLAYCtx } from "kaplay";
|
|
|
2
2
|
|
|
3
3
|
// Types
|
|
4
4
|
import {
|
|
5
|
+
ButtonComponent,
|
|
5
6
|
LabelComponent,
|
|
6
7
|
LabelOptions,
|
|
7
|
-
TextButtonElement,
|
|
8
8
|
TextButtonOptions,
|
|
9
9
|
} from "./types";
|
|
10
10
|
|
|
@@ -12,31 +12,73 @@ import {
|
|
|
12
12
|
import { createLabel, createTextButton } from "./elements";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* # KAPLAY
|
|
15
|
+
* # KAPLAY-UI Plugin
|
|
16
16
|
*
|
|
17
|
-
* A
|
|
18
|
-
*
|
|
17
|
+
* A lightweight UI helper plugin that extends the KAPLAY context (`k`)
|
|
18
|
+
* with convenience methods for creating common, reusable UI components
|
|
19
|
+
* such as text buttons and labels.
|
|
19
20
|
*
|
|
20
|
-
*
|
|
21
|
+
* This plugin focuses on *simple, code-driven UI composition* by providing
|
|
22
|
+
* sensible defaults while still allowing full runtime control over layout,
|
|
23
|
+
* styling, and text.
|
|
21
24
|
*
|
|
22
|
-
*
|
|
23
|
-
* - `addTextButton(txt, opts?) → TextButtonElement`
|
|
24
|
-
* - `addLabel(txt, opts?) → LabelComponent`
|
|
25
|
+
* ---
|
|
25
26
|
*
|
|
26
|
-
* ##
|
|
27
|
+
* ## What this plugin does
|
|
28
|
+
* When included via `kaplay({ plugins: [...] })`, this plugin augments
|
|
29
|
+
* the existing KAPLAY context with the following helper methods:
|
|
30
|
+
*
|
|
31
|
+
* - `k.addTextButton(txt, opts?) → ButtonComponent`
|
|
32
|
+
* Creates an interactive button with centered text and exposes methods
|
|
33
|
+
* for updating size, position, colors, radius, outline, anchor, and text
|
|
34
|
+
* properties at runtime.
|
|
35
|
+
*
|
|
36
|
+
* - `k.addLabel(txt, opts?) → LabelComponent`
|
|
37
|
+
* Creates a non-interactive text label with a background surface and
|
|
38
|
+
* exposes methods for dynamically updating layout, appearance, and text.
|
|
39
|
+
*
|
|
40
|
+
* These helpers eliminate the need to manually wire up common UI primitives
|
|
41
|
+
* while still returning fully controllable game objects.
|
|
42
|
+
*
|
|
43
|
+
* ---
|
|
44
|
+
*
|
|
45
|
+
* ## Design philosophy
|
|
46
|
+
* - No layout system or retained UI tree
|
|
47
|
+
* - No reactivity framework
|
|
48
|
+
* - No hidden state
|
|
49
|
+
*
|
|
50
|
+
* UI elements are regular KAPLAY game objects with small, focused helper
|
|
51
|
+
* methods attached for convenience.
|
|
52
|
+
*
|
|
53
|
+
* ---
|
|
54
|
+
*
|
|
55
|
+
* ## Usage
|
|
27
56
|
*
|
|
28
57
|
* @example
|
|
29
58
|
* import kaplay from "kaplay";
|
|
30
|
-
* import kaplayUI from "kaplay-ui"
|
|
59
|
+
* import kaplayUI from "kaplay-ui";
|
|
31
60
|
*
|
|
32
61
|
* const k = kaplay({
|
|
33
|
-
*
|
|
34
|
-
* })
|
|
62
|
+
* plugins: [kaplayUI],
|
|
63
|
+
* });
|
|
35
64
|
*
|
|
36
|
-
* const
|
|
37
|
-
*
|
|
65
|
+
* const btn = k.addTextButton("Start");
|
|
66
|
+
* btn.onClick(() => console.log("Game starting…"));
|
|
67
|
+
*
|
|
68
|
+
* const label = k.addLabel("Score: 0");
|
|
69
|
+
* label.setPosition(20, 20);
|
|
70
|
+
*
|
|
71
|
+
* ---
|
|
72
|
+
*
|
|
73
|
+
* @returns {{
|
|
74
|
+
* addTextButton: Function,
|
|
75
|
+
* addLabel: Function
|
|
76
|
+
* }}
|
|
77
|
+
* Kaplay merges the returned object into the `k` context, making the
|
|
78
|
+
* UI helpers available as `k.addTextButton()` and `k.addLabel()`.
|
|
79
|
+
*
|
|
80
|
+
* The plugin itself does not create or return UI elements directly.
|
|
38
81
|
*/
|
|
39
|
-
|
|
40
82
|
export default function kaplayUI(k: KAPLAYCtx): {
|
|
41
83
|
/**
|
|
42
84
|
* # Text Button
|
|
@@ -45,93 +87,217 @@ export default function kaplayUI(k: KAPLAYCtx): {
|
|
|
45
87
|
* This helper provides sensible defaults for size, layout, and styling<br>
|
|
46
88
|
* so you can quickly add text-based buttons to your KAPLAY game or UI.
|
|
47
89
|
*
|
|
90
|
+
* ---
|
|
91
|
+
*
|
|
48
92
|
* ## Parameters
|
|
49
93
|
*
|
|
50
|
-
* ### Required
|
|
94
|
+
* ### Required Parameters
|
|
51
95
|
* - `txt` {string}
|
|
96
|
+
* Initial text label displayed at the center of the button.
|
|
52
97
|
*
|
|
53
|
-
* ### Default Parameter Values for
|
|
98
|
+
* ### Default Parameter Values for `opts`
|
|
54
99
|
* - `opts.width`: `150`
|
|
55
100
|
* - `opts.height`: `60`
|
|
56
|
-
* - `opts.radius`: `10`
|
|
57
101
|
* - `opts.posX`: `0`
|
|
58
102
|
* - `opts.posY`: `0`
|
|
103
|
+
* - `opts.radius`: `10`
|
|
59
104
|
* - `opts.outline`: `3`
|
|
105
|
+
* - `opts.btnColor`: `[200, 200, 200]`
|
|
106
|
+
* - `opts.outlineColor`: `"#5c5b5b"`
|
|
107
|
+
* - `opts.txtSize`: `20`
|
|
108
|
+
* - `opts.txtColor`: `[0, 0, 0]`
|
|
109
|
+
* ---
|
|
60
110
|
*
|
|
61
111
|
* ## Default Styling
|
|
62
112
|
* The button object is created with:
|
|
63
113
|
* - `k.anchor("topleft")`
|
|
64
|
-
* - `k.color(200, 200, 200)`
|
|
65
|
-
* - `k.outline(opts.outline, k.rgb(92, 91, 91))`
|
|
66
114
|
* - `k.area()`
|
|
67
115
|
*
|
|
68
|
-
*
|
|
116
|
+
* The button text is created with:
|
|
117
|
+
* - `k.anchor("center")`
|
|
118
|
+
*
|
|
119
|
+
* ---
|
|
120
|
+
*
|
|
121
|
+
* ## Button Instance Methods
|
|
122
|
+
* The returned `ButtonComponent` exposes the following mutator methods,
|
|
123
|
+
* allowing the button to be updated after creation:
|
|
124
|
+
*
|
|
125
|
+
* ### Layout & Geometry
|
|
126
|
+
* - `setSize(w: number, h: number): void`
|
|
127
|
+
* Update the button width and height.
|
|
128
|
+
*
|
|
129
|
+
* - `setPosition(x: number, y: number): void`
|
|
130
|
+
* Move the button to a new position.
|
|
131
|
+
*
|
|
132
|
+
* - `setAnchor(a: Anchor): void`
|
|
133
|
+
* Change the anchor used for positioning.
|
|
134
|
+
*
|
|
135
|
+
* - `setRadius(r: number): void`
|
|
136
|
+
* Update the corner radius.
|
|
137
|
+
*
|
|
138
|
+
* - `setOutline(t: number): void`
|
|
139
|
+
* Set the outline thickness.
|
|
140
|
+
*
|
|
141
|
+
* ### Text
|
|
142
|
+
* - `setButtonText(txt: string): void`
|
|
143
|
+
* Replace the button label.
|
|
144
|
+
*
|
|
145
|
+
* - `setButtonTextSize(size: number): void`
|
|
146
|
+
* Change the font size of the button text.
|
|
147
|
+
*
|
|
148
|
+
* - `setButtonTextColor(color: KaplayColor): void`
|
|
149
|
+
* Update the text color.
|
|
150
|
+
*
|
|
151
|
+
* ### Colors
|
|
152
|
+
* - `setButtonColor(color: KaplayColor): void`
|
|
153
|
+
* Change the button fill color.
|
|
154
|
+
*
|
|
155
|
+
* - `setButtonOutlineColor(color: KaplayRGB): void`
|
|
156
|
+
* Change the outline stroke color.
|
|
157
|
+
*
|
|
158
|
+
* ---
|
|
159
|
+
*
|
|
160
|
+
* @param {string} txt
|
|
69
161
|
* Required text label to be displayed at the center of the button.
|
|
70
162
|
*
|
|
71
163
|
* @param {TextButtonOptions} [opts={}]
|
|
72
164
|
* Optional configuration object used to customize the button.
|
|
73
165
|
*
|
|
74
|
-
* @returns {
|
|
75
|
-
* A
|
|
166
|
+
* @returns {ButtonComponent}
|
|
167
|
+
* A clickable button instance with runtime mutation helpers attached.
|
|
168
|
+
*
|
|
169
|
+
* ---
|
|
76
170
|
*
|
|
77
171
|
* @example
|
|
78
|
-
* // Basic usage
|
|
172
|
+
* // Basic usage
|
|
79
173
|
* const playBtn = addTextButton("Play");
|
|
80
174
|
* playBtn.onClick(() => console.log("Play clicked!"));
|
|
81
175
|
*
|
|
82
176
|
* @example
|
|
83
|
-
* //
|
|
84
|
-
* const
|
|
177
|
+
* // Runtime mutation
|
|
178
|
+
* const btn = addTextButton("Start");
|
|
179
|
+
* btn.setSize(300, 120);
|
|
180
|
+
* btn.setButtonColor([255, 100, 100]);
|
|
181
|
+
* btn.setButtonText("Go!");
|
|
85
182
|
*
|
|
86
183
|
* @example
|
|
87
|
-
* //
|
|
88
|
-
* const
|
|
184
|
+
* // Visual-only updates
|
|
185
|
+
* const optionsBtn = addTextButton("Options", { radius: 2 });
|
|
186
|
+
* optionsBtn.setButtonOutlineColor([0, 0, 0]);
|
|
187
|
+
* optionsBtn.setButtonTextSize(24);
|
|
89
188
|
*/
|
|
90
|
-
addTextButton(txt: string, opts?: TextButtonOptions):
|
|
189
|
+
addTextButton(txt: string, opts?: TextButtonOptions): ButtonComponent;
|
|
190
|
+
|
|
91
191
|
/**
|
|
92
192
|
* # Label
|
|
93
|
-
*
|
|
94
193
|
* Creates a simple text container with a background and layout box.
|
|
95
194
|
*
|
|
96
195
|
* Labels are lightweight UI elements used to display non-interactive text
|
|
97
196
|
* such as titles, descriptions, or dynamic info (scores, status, etc.).
|
|
98
197
|
*
|
|
198
|
+
* ---
|
|
199
|
+
*
|
|
99
200
|
* ## Parameters
|
|
100
201
|
*
|
|
101
|
-
* ### Required
|
|
202
|
+
* ### Required Parameters
|
|
102
203
|
* - `txt` {string}
|
|
204
|
+
* Initial label text content.
|
|
103
205
|
*
|
|
104
|
-
* ### Default Parameter Values for
|
|
206
|
+
* ### Default Parameter Values for `opts`
|
|
105
207
|
* - `opts.width`: `160`
|
|
106
208
|
* - `opts.height`: `96`
|
|
209
|
+
* - `opts.posX`: `0`
|
|
210
|
+
* - `opts.posY`: `0`
|
|
211
|
+
* - `opts.opacity`: `0.7`
|
|
107
212
|
* - `opts.txtSize`: `22`
|
|
108
213
|
*
|
|
109
|
-
*
|
|
214
|
+
* ---
|
|
110
215
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
216
|
+
* ## Default Styling
|
|
217
|
+
* The label background ("base") includes:
|
|
113
218
|
* - `k.color(0, 0, 0)`
|
|
114
|
-
* - `k.opacity(0.7)`
|
|
115
219
|
* - `k.anchor("topleft")`
|
|
116
220
|
*
|
|
117
|
-
*
|
|
118
|
-
* - `k.anchor("center")
|
|
119
|
-
* - `k.color(255, 255, 255)
|
|
221
|
+
* The centered label text includes:
|
|
222
|
+
* - `k.anchor("center")`
|
|
223
|
+
* - `k.color(255, 255, 255)`
|
|
224
|
+
*
|
|
225
|
+
* ---
|
|
226
|
+
*
|
|
227
|
+
* ## Label Instance Methods
|
|
228
|
+
* The returned `LabelComponent` exposes helper methods that allow
|
|
229
|
+
* the label to be updated dynamically at runtime.
|
|
230
|
+
*
|
|
231
|
+
* ### Layout & Geometry
|
|
232
|
+
* - `setSize(w: number, h: number): void`
|
|
233
|
+
* Update the label width and height.
|
|
234
|
+
*
|
|
235
|
+
* - `setPosition(x: number, y: number): void`
|
|
236
|
+
* Move the label to a new position.
|
|
237
|
+
*
|
|
238
|
+
* - `setRadius(r: number): void`
|
|
239
|
+
* Update the background corner radius.
|
|
240
|
+
*
|
|
241
|
+
* - `setLabelAnchor(anchor: Anchor): void`
|
|
242
|
+
* Change the anchor used for positioning the label.
|
|
243
|
+
*
|
|
244
|
+
* ### Appearance
|
|
245
|
+
* - `setOpacity(o: number): void`
|
|
246
|
+
* Set label background opacity (0–1).
|
|
247
|
+
*
|
|
248
|
+
* - `setLabelColor(c: KaplayColor): void`
|
|
249
|
+
* Change the background color of the label.
|
|
250
|
+
*
|
|
251
|
+
* ### Text
|
|
252
|
+
* - `setLabelText(txt: string): void`
|
|
253
|
+
* Replace the label text.
|
|
254
|
+
*
|
|
255
|
+
* - `setLabelTextSize(size: number): void`
|
|
256
|
+
* Change the font size of the label text.
|
|
257
|
+
*
|
|
258
|
+
* - `setLabelTextColor(c: KaplayColor): void`
|
|
259
|
+
* Update the label text color.
|
|
260
|
+
*
|
|
261
|
+
* ---
|
|
262
|
+
*
|
|
263
|
+
* @param {string} txt
|
|
264
|
+
* Required text content for the label.
|
|
120
265
|
*
|
|
121
266
|
* @param {LabelOptions} [opts={}]
|
|
122
|
-
* Optional configuration object used to customize the
|
|
267
|
+
* Optional configuration object used to customize the label.
|
|
123
268
|
*
|
|
124
|
-
* @returns {
|
|
125
|
-
* A
|
|
269
|
+
* @returns {LabelComponent}
|
|
270
|
+
* A non-interactive label element with runtime mutation helpers attached.
|
|
271
|
+
*
|
|
272
|
+
* ---
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* // Basic usage
|
|
276
|
+
* const label = addLabel("Score: 0");
|
|
277
|
+
* label.setPosition(20, 20);
|
|
126
278
|
*
|
|
127
279
|
* @example
|
|
128
|
-
*
|
|
280
|
+
* // Dynamic text updates (e.g. score counter)
|
|
281
|
+
* let score = 0;
|
|
129
282
|
* const scoreLabel = addLabel(`Score: ${score}`);
|
|
130
283
|
*
|
|
131
284
|
* k.wait(2, () => {
|
|
132
285
|
* score++;
|
|
133
|
-
* scoreLabel.
|
|
134
|
-
* })
|
|
286
|
+
* scoreLabel.setLabelText(`Score: ${score}`);
|
|
287
|
+
* });
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* // Runtime appearance updates
|
|
291
|
+
* const title = addLabel("Game Over", { txtSize: 36 });
|
|
292
|
+
* title.setLabelColor([40, 40, 40]);
|
|
293
|
+
* title.setLabelTextColor([255, 80, 80]);
|
|
294
|
+
* title.setOpacity(0.9);
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* // Layout adjustment after creation
|
|
298
|
+
* const hudLabel = addLabel("Paused");
|
|
299
|
+
* hudLabel.setSize(200, 60);
|
|
300
|
+
* hudLabel.setLabelAnchor("center");
|
|
135
301
|
*/
|
|
136
302
|
addLabel(txt: string, opts?: LabelOptions): LabelComponent;
|
|
137
303
|
} {
|
|
@@ -139,8 +305,8 @@ export default function kaplayUI(k: KAPLAYCtx): {
|
|
|
139
305
|
addTextButton: (
|
|
140
306
|
txt: string,
|
|
141
307
|
opts: TextButtonOptions = {},
|
|
142
|
-
):
|
|
143
|
-
addLabel: (txt, opts: LabelOptions = {}): LabelComponent =>
|
|
308
|
+
): ButtonComponent => createTextButton(k, txt, opts),
|
|
309
|
+
addLabel: (txt: string, opts: LabelOptions = {}): LabelComponent =>
|
|
144
310
|
createLabel(k, txt, opts),
|
|
145
311
|
};
|
|
146
312
|
}
|