kaplay-ui 1.0.0-alpha.13 → 1.0.0-alpha.15

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
@@ -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
- ## 🚀 Usage (_1.0.0-alpha.\*_)
45
+ ## 🚀 Quick start (_1.0.0-alpha.\*_)
33
46
 
34
- **Kaplay UI** exports a plugin for adding UI Game Objects.
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("Play");
51
- const label = k.addLabel("Score: 0");
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
- ### 🔤 **Text Button** (`addTextButton()`)
59
-
60
- Creates a button-like GameObj with centered text and some convenient defaults.
74
+ ### 🔤 Text Button `addTextButton()`
61
75
 
62
- #### _**Signature**_
76
+ Creates a clickable button with centered text and default visuals.
63
77
 
64
78
  ```ts
65
- addTextButton(
66
- txt: string,
67
- opts?: object
68
- ): GameObj
79
+ const btn = k.addTextButton("Start", {
80
+ width: 200,
81
+ height: 80,
82
+ });
69
83
  ```
70
84
 
71
- #### _**Default `opts` parameter values**_
85
+ Buttons support runtime updates such as:
72
86
 
73
- | Parameter | Default |
74
- | --------- | :------ |
75
- | `width` | `200` |
76
- | `height` | `100` |
77
- | `radius` | `10` |
78
- | `posX` | `0` |
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
- #### _**Default styling**_
94
+ Perfect for menus, dialogs, and in‑game actions.
95
+
96
+ ---
84
97
 
85
- | Comps | Values |
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
- #### _**Examples**_
100
+ Creates a lightweight background + text container for HUD elements or titles.
94
101
 
95
102
  ```ts
96
- // Basic button
97
- const btn1 = k.addTextButton("Play!");
103
+ const label = k.addLabel("Score: 0");
104
+ ```
98
105
 
99
- // Custom button
100
- const btn2 = k.addTextButton("Play!", { posX: 300, posY: 200 });
106
+ Update it dynamically:
101
107
 
102
- // Add interactivity
103
- btn2.onClick(() => {
104
- console.log("Button clicked!");
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
- ### 🏷️ **Label** (`addLabel()`)
118
+ ## 🎨 Customization
111
119
 
112
- A lightweight text-based UI element ideal for HUD counters, tooltips, status text, or titles.
120
+ kaplay-ui is designed to be **customized imperatively**, without hiding
121
+ or abstracting away KAPLAY’s core APIs.
113
122
 
114
- #### _**Signature**_
123
+ ### ✅ Option-based customization (at creation)
124
+
125
+ Both helpers accept an optional `opts` object for common configuration:
115
126
 
116
127
  ```ts
117
- addLabel(
118
- txt: string,
119
- opts?: object
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
- #### _**Default `opts` values**_
137
+ ---
124
138
 
125
- | Parameter | Default |
126
- | --------- | ------- |
127
- | `width` | `160` |
128
- | `height` | `96` |
129
- | `txtSize` | `22` |
139
+ ### Runtime customization (after creation)
130
140
 
131
- #### _**Default styling**_
141
+ Each UI element exposes helper methods for updating its appearance and layout:
132
142
 
133
- | Comps | Values |
134
- | --------------- | :-------------- |
135
- | `label pos` | `0, 0` |
136
- | `label color` | `0, 0,0 ` |
137
- | `label opacity` | `0.7` |
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
- #### _**Examples**_
149
+ This makes it easy to animate, react to state changes, or reuse UI elements.
143
150
 
144
- ```ts
145
- // Basic label
146
- const lbl2 = k.addLabel("Score: 0");
151
+ ---
147
152
 
148
- // Custom label
149
- const lbl3 = k.addLabel("Start", { width: 100, height: 50 });
153
+ ### Full KAPLAY access
150
154
 
151
- // Update label text example
152
- let score = 0;
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
- k.wait(2, () => {
156
- score++;
157
- scoreLabel.children[0].text = `Score: ${score}`;
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
- #### _**Common use cases**_
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
- - HUD overlays
164
- - Score counters
165
- - Time and health displays
166
- - UI section headings
167
- - Tooltips and indicators
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
- _See evolving roadmap at: https://github.com/jbakchr/kaplay-ui/blob/v1/ROADMAP.md_
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
 
@@ -0,0 +1 @@
1
+ export { }
package/dist/uiplugin.js CHANGED
@@ -1,62 +1,48 @@
1
- //#region src/components/button/index.ts
1
+ //#region src/helpers/color-utils.ts
2
2
  function e(e, t, n) {
3
- let { width: r, height: i, radius: a, posX: o, posY: s, outline: c } = {
4
- width: 150,
5
- height: 60,
6
- radius: 10,
7
- posX: 0,
8
- posY: 0,
9
- outline: 3,
10
- ...t
11
- };
12
- return e.make([
13
- e.rect(r, i, { radius: a }),
14
- e.pos(o, s),
15
- e.color(200, 200, 200),
16
- e.outline(c, e.rgb(92, 91, 91)),
17
- e.anchor(n),
18
- e.area()
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
- //#endregion
22
- //#region src/components/label/index.ts
23
- function t(e, t) {
24
- let { width: n, height: r } = {
25
- width: 160,
26
- height: 96,
27
- ...t
28
- };
29
- return e.make([
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/components/text/index.ts
39
- function n(e, t, n, r, i, a) {
40
- let { txtSize: o } = {
41
- txtSize: 22,
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 r(e) {
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 i(e, t, n, r, i) {
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/helpers/layout-utils.ts
93
- var a = new Set([
94
- "anchor",
95
- "pos",
96
- "area"
97
- ]);
98
- function o(e) {
99
- return a.has(e);
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/elements/text-button/index.ts
103
- function s(t, a, s) {
104
- let c = e(t, s, "topleft"), { cX: l, cY: u } = r(c), d = n(t, a, s, l, u, "center");
105
- return c.add(d), t.add(c), c.onUse((e) => {
106
- if (o(e)) {
107
- let { cX: e, cY: n } = r(c);
108
- i(t, c, d, e, n);
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
- }), c.onHover(() => {
111
- t.setCursor("pointer");
112
- }), c.onHoverEnd(() => {
113
- t.setCursor("default");
114
- }), c;
230
+ }), l;
115
231
  }
116
232
  //#endregion
117
- //#region src/elements/label/index.ts
118
- function c(e, i, a) {
119
- let o = t(e, a), { cX: s, cY: c } = r(o), l = n(e, i, a, s, c, "center");
120
- return l.use(e.color(255, 255, 255)), o.add(l), e.add(o), o;
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 l(e) {
256
+ function d(e) {
125
257
  return {
126
- addTextButton: (t, n = {}) => s(e, t, n),
127
- addLabel: (t, n = {}) => c(e, 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 { l as default };
263
+ export { d as default };
@@ -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){let{width:r,height:i,radius:a,posX:o,posY:s,outline:c}={width:150,height:60,radius:10,posX:0,posY:0,outline:3,...t};return e.make([e.rect(r,i,{radius:a}),e.pos(o,s),e.color(200,200,200),e.outline(c,e.rgb(92,91,91)),e.anchor(n),e.area()])}function t(e,t){let{width:n,height:r}={width:160,height:96,...t};return e.make([e.rect(n,r),e.pos(0,0),e.color(0,0,0),e.opacity(.7),e.anchor(`topleft`)])}function n(e,t,n,r,i,a){let{txtSize:o}={txtSize:22,...n};return e.make([e.text(t,{size:o}),e.color(0,0,0),e.pos(r,i),e.anchor(a)])}function r(e){return{cX:e.width/2,cY:e.height/2}}function i(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}}var a=new Set([`anchor`,`pos`,`area`]);function o(e){return a.has(e)}function s(t,a,s){let c=e(t,s,`topleft`),{cX:l,cY:u}=r(c),d=n(t,a,s,l,u,`center`);return c.add(d),t.add(c),c.onUse(e=>{if(o(e)){let{cX:e,cY:n}=r(c);i(t,c,d,e,n)}}),c.onHover(()=>{t.setCursor(`pointer`)}),c.onHoverEnd(()=>{t.setCursor(`default`)}),c}function c(e,i,a){let o=t(e,a),{cX:s,cY:c}=r(o),l=n(e,i,a,s,c,`center`);return l.use(e.color(255,255,255)),o.add(l),e.add(o),o}function l(e){return{addTextButton:(t,n={})=>s(e,t,n),addLabel:(t,n={})=>c(e,t,n)}}return l});
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
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "kaplay-ui",
3
- "version": "1.0.0-alpha.13",
3
+ "version": "1.0.0-alpha.15",
4
4
  "description": "UI components for KAPLAY",
5
5
  "type": "module",
6
- "main": "src/index.ts",
6
+ "main": "./dist/uiplugin.js",
7
+ "types": "./dist/uiplugin.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/uiplugin.js",
11
+ "require": "./dist/uiplugin.umd.cjs",
12
+ "types": "./dist/uiplugin.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
7
18
  "scripts": {
8
19
  "dev": "vite dev",
9
- "build": "vite build"
20
+ "build": "vite build",
21
+ "prepublishOnly": "npm run build"
10
22
  },
11
23
  "repository": {
12
24
  "type": "git",
package/docs/_config.yml DELETED
@@ -1,4 +0,0 @@
1
- theme: jekyll-theme-minimal
2
- title: "KAPLAY UI"
3
- description: "UI Plugin for KAPLAY"
4
- markdown: kramdown
@@ -1,23 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
-
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
-
8
- <title>{{ page.title }} - {{ site.title }}</title>
9
-
10
- <!-- Load custom stylesheet -->
11
- <link rel="stylesheet" href="{{ '/assets/style.css' | relative_url }}" />
12
- </head>
13
-
14
- <body>
15
- <!-- KAPLAY-style header -->
16
- <header class="kaplay-header">
17
- <img src="{{ '/assets/logo.png' | relative_url }}" class="kaplay-logo" />
18
- </header>
19
-
20
- <!-- Main content -->
21
- <main class="page-content">{{ content }}</main>
22
- </body>
23
- </html>
@@ -1,23 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
-
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
-
8
- <title>{{ page.title }} - {{ site.title }}</title>
9
-
10
- <!-- Load custom stylesheet -->
11
- <link rel="stylesheet" href="{{ '/assets/style.css' | relative_url }}" />
12
- </head>
13
-
14
- <body>
15
- <!-- KAPLAY-style header -->
16
- <header class="kaplay-header">
17
- <img src="{{ '/assets/logo.png' | relative_url }}" class="kaplay-logo" />
18
- </header>
19
-
20
- <!-- Main content -->
21
- <main class="page-content">{{ content }}</main>
22
- </body>
23
- </html>
@@ -1,6 +0,0 @@
1
- # Design Decisions
2
-
3
- This md and the subfolders below it documents to design decision defaults of:
4
-
5
- - [Label](https://github.com/jbakchr/kaplay-ui/blob/v1/docs/design-decisions/label/label-defaults.md)
6
- - [Text Button](https://github.com/jbakchr/kaplay-ui/blob/v1/docs/design-decisions/text-button/text-button-defaults.md)
@@ -1,219 +0,0 @@
1
- # Label Design Decisions
2
-
3
- This document provides why the current defaults for the `addLabel()` Game Objects are what they are for:
4
-
5
- 1. [Background color](#-most-common-background-colors-for-labels-in-games)
6
- 2. [Width and Height](#-the-most-common-label-sizes-in-games)
7
-
8
- ## 🎨 Most Common Background Colors for Labels in Games
9
-
10
- ### **1. Dark, Semi-Transparent Background (Most Common Overall)**
11
-
12
- Examples:
13
-
14
- - `rgba(0, 0, 0, 0.5)`
15
- - `rgba(0, 0, 0, 0.7)`
16
-
17
- Why it's common:
18
-
19
- - Works on almost every scene background (bright, dark, colorful).
20
- - Makes white or light text extremely readable.
21
- - Gives a “HUD” feel found in many genres.
22
-
23
- Where it's used:
24
-
25
- - Health bars
26
- - Tooltips
27
- - HUD counters
28
- - Inventory labels
29
-
30
- This is the single most widely used choice in modern 2D games.
31
-
32
- ---
33
-
34
- ### **2. Solid Black or Near‑Black Background**
35
-
36
- Examples:
37
-
38
- - `rgb(0, 0, 0)`
39
- - `rgb(20, 20, 20)`
40
-
41
- Why:
42
-
43
- - Maximum contrast
44
- - Minimalistic
45
- - Fits sci-fi, retro, and clean UI styles
46
-
47
- Often used for:
48
-
49
- - Menu labels
50
- - Title bars
51
- - Status text
52
-
53
- Good when opacity effects aren’t needed.
54
-
55
- ---
56
-
57
- ### **3. Light Background With Dark Text**
58
-
59
- Examples:
60
-
61
- - `rgb(255, 255, 255)` with black text
62
- - `rgb(240, 240, 240)` for softer look
63
-
64
- Why:
65
-
66
- - Works well for “window”-style UI
67
- - Mimics desktop/UI patterns
68
- - Very readable for high-contrast HUDs
69
-
70
- Used in:
71
-
72
- - Casual games
73
- - Puzzle games
74
- - Mobile UX-inspired UI
75
-
76
- This is less common than dark backgrounds but still widely used.
77
-
78
- ---
79
-
80
- ### **4. Colored Background Matching the Game’s Theme**
81
-
82
- Examples:
83
-
84
- - Blue, red, or green surfaces
85
- - Faded color fills like `rgba(50, 100, 200, 0.8)`
86
-
87
- Why:
88
-
89
- - Looks more “stylized” or thematic
90
- - Helps differentiate label purposes (e.g., warning = red)
91
- - Used in highly themed menus and fantasy games
92
-
93
- Common in:
94
-
95
- - JRPG-style menus
96
- - Crafting systems
97
- - Quest logs
98
-
99
- ---
100
-
101
- ### **5. No Background (Text Only)**
102
-
103
- While not literally a “background color,” this is a very common choice:
104
-
105
- - Pure text HUD
106
- - Floating damage numbers
107
- - Dialogue text overlays
108
-
109
- Games often use this when:
110
-
111
- - Text doesn’t compete with backgrounds
112
- - The look should be minimal
113
-
114
- You can easily support this in `addLabel()` by letting `background: null`.
115
-
116
- ---
117
-
118
- ## ⭐ If you want the safest, most universal choice…
119
-
120
- #### → **Use a dark semi-transparent background with light text.**
121
-
122
- Something like:
123
-
124
- ```ts
125
- background: rgba(0, 0, 0, 0.5),
126
- color: rgb(255, 255, 255)
127
- ```
128
-
129
- This works cleanly on:
130
-
131
- - Dark levels
132
- - Bright levels
133
- - High-motion action scenes
134
- - Stylized or pixel art environments
135
-
136
- And it's easy for players to read instantly.
137
-
138
- ---
139
-
140
- ## 🎮 The Most Common Label Sizes in Games
141
-
142
- Even though no source gives explicit “standard label dimensions,” we _can_ derive the common ranges from:
143
-
144
- - Typical **pixel-art game resolutions** such as **320×180**, **640×360**, **1280×720** (all frequently used) [\[screwloose....github.io\]](https://screwloose-games.github.io/documentation/content/guides/art/pixel_art/pixel_art_guide.html)
145
- - Common **sprite and tile sizes** (16×16, 32×32, 64×64) which UI assets usually align to [\[aipixelart.net\]](https://aipixelart.net/node/267)
146
- - Observed dimensions in **pixel-art UI packs** on itch.io (buttons, panels, labels etc. typically in the 32–128px height range) [\[itch.io\]](https://itch.io/game-assets/tag-gui/tag-pixel-art)
147
-
148
- From these, we can determine practical label sizes used in real games.
149
-
150
- ---
151
-
152
- ### 📐 **Typical Label Widths**
153
-
154
- #### **Small labels (HUD counters, score, ammo):**
155
-
156
- - **96px – 160px** wide
157
- - Fits single short text like “SCORE: 0”, “HP”, “XP”, “TIME”
158
-
159
- #### **Medium labels (section titles, longer stat text):**
160
-
161
- - **160px – 256px** wide
162
- - Fits text strings like “OBJECTIVE COMPLETE”, “CURRENT QUEST”
163
-
164
- #### **Large labels (UI titles, menu headings):**
165
-
166
- - **256px – 384px** wide
167
- - Used for things like “INVENTORY”, “SETTINGS”, “PAUSED”
168
-
169
- These sizes map cleanly into 16px/32px multiples recommended for pixel-art alignment.
170
-
171
- ---
172
-
173
- ### 📏 **Typical Label Heights**
174
-
175
- Based on common UI asset proportions:
176
-
177
- - **Text-only HUD label:**
178
- **24–32px** tall (for 8–16px font sizes)
179
-
180
- - **Label with padding + background panel:**
181
- **32–48px** tall is most standard
182
-
183
- - **Chunkier RPG or fantasy labels:**
184
- **48–64px** tall in many itch.io GUI packs [\[itch.io\]](https://itch.io/game-assets/tag-gui/tag-pixel-art)
185
-
186
- These heights align with the commonly used sprite grids of **16×16**, **32×32**, and **64×64** pixels from pixel-art standards. [\[aipixelart.net\]](https://aipixelart.net/node/267)
187
-
188
- ---
189
-
190
- ### 🧩 **Putting It All Together (Practical Defaults)**
191
-
192
- For a game using a common base pixel-art resolution like **640×360** (widely recommended), typical label sizes look like this: [\[screwloose....github.io\]](https://screwloose-games.github.io/documentation/content/guides/art/pixel_art/pixel_art_guide.html)
193
-
194
- | Label Type | Width | Height |
195
- | ------------------- | ------------- | ----------- |
196
- | Small HUD label | **120–160px** | **24–32px** |
197
- | Medium UI label | **160–256px** | **32–48px** |
198
- | Large heading label | **256–384px** | **48–64px** |
199
-
200
- These fit cleanly into standard pixel-art grids and look correct across the common 320×180, 640×360, and 1280×720 style pixel resolutions.
201
-
202
- ---
203
-
204
- ### 🎯 **Recommended Defaults for kaplay-ui**
205
-
206
- If you want to provide sensible defaults for your Label component:
207
-
208
- - **Width:** Automatically sized based on text
209
- - **Height:**
210
- - **32px** for simple HUD labels
211
- - **48px** for background panels
212
-
213
- This keeps things aligned with the pixel-art norms and avoids awkward scaling.
214
-
215
- ---
216
-
217
- _**See next decisions about `Text Button` here:**_
218
-
219
- - [Text Button](https://github.com/jbakchr/kaplay-ui/blob/v1/docs/design-decisions/text-button/text-button-defaults.md)
package/docs/faq.md DELETED
@@ -1,72 +0,0 @@
1
- # ❓ KAPLAY UI — FAQ
2
-
3
- _Frequently asked questions about the KAPLAY UI plugin._
4
-
5
- ---
6
-
7
- ## 📚 Table of Contents
8
-
9
- - [General](#-general)
10
- - [Installation](#-installation)
11
- - [Usage](#-usage)
12
- - [Licensing](#-licensing)
13
-
14
- ---
15
-
16
- ## 🧠 General
17
-
18
- **Q:** _**What is this plugin for?**_
19
-
20
- **A:** KAPLAY UI provides lightweight, composable UI helpers — such as text‑based buttons and labels — built using familiar **KAPLAY primitives**.
21
-
22
- <div class="block">
23
- It reduces boilerplate, keeps UI consistent, and helps you build menus, HUDs, overlays, and interactive UI faster.
24
- </div>
25
-
26
- ---
27
-
28
- ## 📦 Installation
29
-
30
- ### **Q:** _**How do I install KAPLAY UI?**_
31
-
32
- **A:** Install from your project root using your preferred package manager:
33
-
34
- ```sh
35
- npm install kaplay-ui@next
36
- ```
37
-
38
- ---
39
-
40
- ## 🚀 Usage
41
-
42
- ### **Q:** _**How do I use the `kaplay-ui` plugin?**_
43
-
44
- **A:** Import and enable the plugin when creating your KAPLAY instance:
45
-
46
- ```ts
47
- import kaplay from "kaplay";
48
- import kaplayUI from "kaplay-ui";
49
-
50
- const k = kaplay({
51
- plugins: [kaplayUI],
52
- });
53
- ```
54
-
55
- Now you can create UI components such as:
56
-
57
- ```ts
58
- k.addTextButton("Play");
59
- k.addLabel("Score: 0");
60
- ```
61
-
62
- ---
63
-
64
- ## 📄 Licensing
65
-
66
- ### **Q:** _**How may I use `kaplay-ui` ?**_
67
-
68
- The **MIT License** allows full personal and commercial use with virtually no restrictions.
69
-
70
- <div class="block">
71
- 🔓 **In short:** You can use, modify, distribute, and even sell projects using KAPLAY UI.
72
- </div>
package/docs/index.md DELETED
@@ -1,126 +0,0 @@
1
- # 🦖 KAPLAY-UI 🧩
2
-
3
- _A lightweight and flexible **UI plugin for KAPLAY**, built to feel like a natural extension of the engine._
4
-
5
- Create UI elements quickly using familiar KAPLAY primitives — buttons, labels, HUD elements, menus, and more.
6
-
7
- <div class="block">
8
-
9
- ✨ KAPLAY UI helps you build game-ready user interfaces with almost no setup.
10
-
11
- Perfect for menus, HUDs, mobile UI, prototypes, and small-to-medium games.
12
-
13
- </div>
14
-
15
- ---
16
-
17
- ## 🚀 Why KAPLAY UI?
18
-
19
- - 🧩 Works exactly like native KAPLAY
20
- - 🎛️ Easy, declarative API
21
- - ✨ Sensible styling defaults
22
- - 🎨 Fully customizable
23
-
24
- ---
25
-
26
- ## 📦 Installation _(v1.0.0-alpha\*)_
27
-
28
- ```sh
29
- npm install kaplay-ui@next
30
- ```
31
-
32
- ---
33
-
34
- ## 🧰 Getting Started
35
-
36
- Add the plugin when creating your KAPLAY instance:
37
-
38
- ```ts
39
- import kaplay from "kaplay";
40
- import kaplayUI from "kaplay-ui";
41
-
42
- const k = kaplay({
43
- plugins: [kaplayUI],
44
- });
45
- ```
46
-
47
- Now create a UI element:
48
-
49
- ```ts
50
- const tb = k.addTextButton("Play");
51
- const sl = k.addLabel("Score: 0");
52
- ```
53
-
54
- _**That’s it** — you’re ready to build UI!_
55
-
56
- ---
57
-
58
- ## 🧱 Core Components
59
-
60
- ### 🔤 Text Button
61
-
62
- Create an interactive button with centered text and built‑in outline & area detection.
63
-
64
- ```ts
65
- const tb = k.addTextButton("Play");
66
-
67
- tb.onClick(() => {
68
- console.log("Let's play!");
69
- });
70
- ```
71
-
72
- ### 🏷️ Label
73
-
74
- A small, flexible text element — perfect for HUDs.
75
-
76
- ```ts
77
- const lbl = k.addLabel("Score: 0");
78
- ```
79
-
80
- _More components are being added soon as the plugin grows._ 🎉
81
-
82
- ---
83
-
84
- ## 📚 Documentation
85
-
86
- _Soon_ .. you can find more details here:
87
-
88
- - 📄 **faq.md** — _Questions and answers_
89
- - 🧠 **design-decisions** — _The Whys?_
90
- - 🔘 **API Pages** — _The What & How_
91
- - 🧪 **Examples** — _Learn by doing_
92
- - 🪧 **Demos** — _See it in action_
93
-
94
- ## 🗺️ Roadmap (WIP)
95
-
96
- - **⏳ More component types**
97
- _(sliders, toggles, panels)_
98
-
99
- - **🎨 Theme presets**
100
- _(built-in light/dark UI packs)_
101
-
102
- - **🎛️ Complex layout helpers**
103
- _(stacks, grids)_
104
-
105
- - **📘 Full documentation site**
106
- _(getting started, faq and .. more)_
107
-
108
- ---
109
-
110
- ## 🤝 Contributing
111
-
112
- Contributions and feature ideas are warmly welcome!
113
-
114
- Feel free to submit issues or PRs on GitHub — or share ideas in the discussions tab.
115
-
116
- ---
117
-
118
- ## 📜 License
119
-
120
- MIT © 2026 [Jonas Bak Phillipson](https://github.com/jbakchr)
121
-
122
- ---
123
-
124
- <div class="block" style="text-align:center;font-weight:bold;">
125
- <p>Made with 💚 + 🦖 by:<p>
126
- <p style="font-style:italic;"><span style="color:#ffde86;">The</span> <span style="color:#f2ae99;">KAPLAY </span><span style="color:#CF9FFF;">Community</span></p>
@@ -1,19 +0,0 @@
1
- # About releases
2
-
3
- ## Alpha releases
4
-
5
- ### Before release
6
- Before releasing a new alpha.* version remember to:
7
-
8
- - Update v* branch JSDocs
9
- - Update main branch README.md
10
- - Update ROADMAP.md
11
- - Update main branch docs for website
12
-
13
- ### Steps to release alpha version to npm
14
-
15
- 1. run `npm login``
16
- 2. npm version prerelease --preid=alpha
17
- 3. npm run build
18
- 4. git push
19
- 5. npm publish --tag next
package/src/index.ts DELETED
@@ -1,146 +0,0 @@
1
- import type { KAPLAYCtx } from "kaplay";
2
-
3
- // Types
4
- import {
5
- LabelComponent,
6
- LabelOptions,
7
- TextButtonElement,
8
- TextButtonOptions,
9
- } from "./types";
10
-
11
- // Text Button
12
- import { createLabel, createTextButton } from "./elements";
13
-
14
- /**
15
- * # KAPLAY UI Plugin
16
- *
17
- * A small UI helper plugin that adds convenience functions for creating
18
- * common UI components such as buttons and labels within a KAPLAY game.
19
- *
20
- * ## Available UI Creation Helpers
21
- *
22
- * @returns {object} An object exposing UI creation helpers on `k`:
23
- * - `addTextButton(txt, opts?) → TextButtonElement`
24
- * - `addLabel(txt, opts?) → LabelComponent`
25
- *
26
- * ## Examples
27
- *
28
- * @example
29
- * import kaplay from "kaplay";
30
- * import kaplayUI from "kaplay-ui"
31
- *
32
- * const k = kaplay({
33
- * plugins: [kaplayUI]
34
- * })
35
- *
36
- * const button = k.addTextButton("Start");
37
- * const label = k.addLabel("Hello!");
38
- */
39
-
40
- export default function kaplayUI(k: KAPLAYCtx): {
41
- /**
42
- * # Text Button
43
- * Creates a clickable UI button with centered text.
44
- *
45
- * This helper provides sensible defaults for size, layout, and styling<br>
46
- * so you can quickly add text-based buttons to your KAPLAY game or UI.
47
- *
48
- * ## Parameters
49
- *
50
- * ### Required Paramters
51
- * - `txt` {string}
52
- *
53
- * ### Default Parameter Values for 'opts'
54
- * - `opts.width`: `150`
55
- * - `opts.height`: `60`
56
- * - `opts.radius`: `10`
57
- * - `opts.posX`: `0`
58
- * - `opts.posY`: `0`
59
- * - `opts.outline`: `3`
60
- *
61
- * ## Default Styling
62
- * The button object is created with:
63
- * - `k.anchor("topleft")`
64
- * - `k.color(200, 200, 200)`
65
- * - `k.outline(opts.outline, k.rgb(92, 91, 91))`
66
- * - `k.area()`
67
- *
68
- * @param {string} [txt]
69
- * Required text label to be displayed at the center of the button.
70
- *
71
- * @param {TextButtonOptions} [opts={}]
72
- * Optional configuration object used to customize the button.
73
- *
74
- * @returns {TextButtonElement}
75
- * A KAPLAY Game Object representing the button with centered text.
76
- *
77
- * @example
78
- * // Basic usage (uses default width/height)
79
- * const playBtn = addTextButton("Play");
80
- * playBtn.onClick(() => console.log("Play clicked!"));
81
- *
82
- * @example
83
- * // Custom sizing
84
- * const bigBtn = addTextButton("Start", { width: 300, height: 120 });
85
- *
86
- * @example
87
- * // Override only one dimension
88
- * const tallBtn = addTextButton("Options", { radius: 2 });
89
- */
90
- addTextButton(txt: string, opts?: TextButtonOptions): TextButtonElement;
91
- /**
92
- * # Label
93
- *
94
- * Creates a simple text container with a background and layout box.
95
- *
96
- * Labels are lightweight UI elements used to display non-interactive text
97
- * such as titles, descriptions, or dynamic info (scores, status, etc.).
98
- *
99
- * ## Parameters
100
- *
101
- * ### Required Paramters
102
- * - `txt` {string}
103
- *
104
- * ### Default Parameter Values for 'opts'
105
- * - `opts.width`: `160`
106
- * - `opts.height`: `96`
107
- * - `opts.txtSize`: `22`
108
- *
109
- * ## Default Styling
110
- *
111
- * A labels base (its 'background' surface) includes:
112
- * - `k.pos(0, 0)`
113
- * - `k.color(0, 0, 0)`
114
- * - `k.opacity(0.7)`
115
- * - `k.anchor("topleft")`
116
- *
117
- * A label centered text includes:
118
- * - `k.anchor("center"))
119
- * - `k.color(255, 255, 255))
120
- *
121
- * @param {LabelOptions} [opts={}]
122
- * Optional configuration object used to customize the button.
123
- *
124
- * @returns {LabelElement}
125
- * A KAPLAY game object representing a text label.
126
- *
127
- * @example
128
- * let score = 0
129
- * const scoreLabel = addLabel(`Score: ${score}`);
130
- *
131
- * k.wait(2, () => {
132
- * score++;
133
- * scoreLabel.children[0].text = `Score: ${score}`;
134
- * })
135
- */
136
- addLabel(txt: string, opts?: LabelOptions): LabelComponent;
137
- } {
138
- return {
139
- addTextButton: (
140
- txt: string,
141
- opts: TextButtonOptions = {},
142
- ): TextButtonElement => createTextButton(k, txt, opts),
143
- addLabel: (txt, opts: LabelOptions = {}): LabelComponent =>
144
- createLabel(k, txt, opts),
145
- };
146
- }