create-asciitorium 0.1.44 → 0.1.46
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.
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# ASCIITORIUM Quick Reference
|
|
2
2
|
|
|
3
|
-
> **For LLMs**: This document provides correct usage patterns for ASCIITORIUM
|
|
3
|
+
> **For LLMs**: This document provides correct usage patterns for ASCIITORIUM
|
|
4
|
+
> components. Always refer to the examples here rather than assuming React-like
|
|
5
|
+
> conventions.
|
|
4
6
|
|
|
5
7
|
## Quick Index
|
|
6
8
|
|
|
@@ -35,7 +37,7 @@
|
|
|
35
37
|
- [Keybind](#keybind)
|
|
36
38
|
- [PerfMonitor](#perfmonitor)
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
|
|
39
41
|
|
|
40
42
|
## State Management
|
|
41
43
|
|
|
@@ -118,7 +120,7 @@ count++; // NO! count is a State object
|
|
|
118
120
|
count.value++;
|
|
119
121
|
```
|
|
120
122
|
|
|
121
|
-
|
|
123
|
+
|
|
122
124
|
|
|
123
125
|
## JSX & Props
|
|
124
126
|
|
|
@@ -172,7 +174,7 @@ align="center" // Alignment (layout-specific)
|
|
|
172
174
|
</Text>
|
|
173
175
|
```
|
|
174
176
|
|
|
175
|
-
|
|
177
|
+
|
|
176
178
|
|
|
177
179
|
## Row
|
|
178
180
|
|
|
@@ -215,7 +217,7 @@ align="center" // Alignment (layout-specific)
|
|
|
215
217
|
</Row>
|
|
216
218
|
```
|
|
217
219
|
|
|
218
|
-
|
|
220
|
+
|
|
219
221
|
|
|
220
222
|
## Column
|
|
221
223
|
|
|
@@ -262,7 +264,7 @@ align="center" // Alignment (layout-specific)
|
|
|
262
264
|
</Column>
|
|
263
265
|
```
|
|
264
266
|
|
|
265
|
-
|
|
267
|
+
|
|
266
268
|
|
|
267
269
|
## Text
|
|
268
270
|
|
|
@@ -361,7 +363,7 @@ const playerName = new State('Hero');
|
|
|
361
363
|
<Text>{count.value}</Text> // Explicit .value also works
|
|
362
364
|
```
|
|
363
365
|
|
|
364
|
-
|
|
366
|
+
|
|
365
367
|
|
|
366
368
|
## Button
|
|
367
369
|
|
|
@@ -439,7 +441,7 @@ const count = new State(0);
|
|
|
439
441
|
<Button>Very Long Text</Button> // Auto-sizes
|
|
440
442
|
```
|
|
441
443
|
|
|
442
|
-
|
|
444
|
+
|
|
443
445
|
|
|
444
446
|
## Select
|
|
445
447
|
|
|
@@ -553,142 +555,170 @@ const selected = new State("option1");
|
|
|
553
555
|
</Select>
|
|
554
556
|
```
|
|
555
557
|
|
|
556
|
-
|
|
558
|
+
|
|
557
559
|
|
|
558
560
|
## Switch
|
|
559
561
|
|
|
560
562
|
### Basic Usage
|
|
561
563
|
|
|
562
564
|
```tsx
|
|
563
|
-
import { State, Switch } from 'asciitorium';
|
|
565
|
+
import { State, Switch, Case, Default } from 'asciitorium';
|
|
564
566
|
|
|
565
|
-
|
|
566
|
-
const currentView = new State<any>(DashboardComponent);
|
|
567
|
+
const userRole = new State<string>('guest');
|
|
567
568
|
|
|
568
|
-
<Switch
|
|
569
|
+
<Switch condition={userRole}>
|
|
570
|
+
<Case when="admin" create={AdminPanel} />
|
|
571
|
+
<Case when="user" create={UserPanel} />
|
|
572
|
+
<Case when="guest" create={GuestPanel} />
|
|
573
|
+
<Default create={GuestPanel} />
|
|
574
|
+
</Switch>;
|
|
569
575
|
```
|
|
570
576
|
|
|
571
|
-
### Props
|
|
577
|
+
### Props (Switch)
|
|
578
|
+
|
|
579
|
+
| Prop | Type | Default | Description |
|
|
580
|
+
| ----------- | -------------------------------- | ------- | ---------------------------------- |
|
|
581
|
+
| `condition` | `State<string> \| State<number>` | - | State to match against Case values |
|
|
582
|
+
| `width` | `number \| 'fill'` | - | Component width |
|
|
583
|
+
| `height` | `number \| 'fill'` | - | Component height |
|
|
584
|
+
|
|
585
|
+
### Props (Case)
|
|
586
|
+
|
|
587
|
+
| Prop | Type | Description |
|
|
588
|
+
| -------- | ------------------ | ----------------------------------- |
|
|
589
|
+
| `when` | `string \| number` | Value to match against condition |
|
|
590
|
+
| `create` | `any` | Component class/function to create |
|
|
591
|
+
| `with` | `any` | Optional props to pass to component |
|
|
572
592
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
|
576
|
-
|
|
|
577
|
-
| `
|
|
593
|
+
### Props (Default)
|
|
594
|
+
|
|
595
|
+
| Prop | Type | Description |
|
|
596
|
+
| -------- | ----- | ----------------------------------- |
|
|
597
|
+
| `create` | `any` | Component class/function to create |
|
|
598
|
+
| `with` | `any` | Optional props to pass to component |
|
|
578
599
|
|
|
579
600
|
### Common Patterns
|
|
580
601
|
|
|
581
|
-
**Pattern 1:
|
|
602
|
+
**Pattern 1: Simple Conditional Rendering**
|
|
582
603
|
|
|
583
604
|
```tsx
|
|
584
|
-
import { State, Switch,
|
|
605
|
+
import { State, Switch, Case, Default } from 'asciitorium';
|
|
585
606
|
|
|
586
|
-
//
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
class SettingsView extends Component {
|
|
591
|
-
/* ... */
|
|
592
|
-
}
|
|
593
|
-
class ProfileView extends Component {
|
|
594
|
-
/* ... */
|
|
595
|
-
}
|
|
607
|
+
// Function components
|
|
608
|
+
const AdminPanel = () => <Column>Admin View</Column>;
|
|
609
|
+
const UserPanel = () => <Column>User View</Column>;
|
|
610
|
+
const GuestPanel = () => <Column>Guest View</Column>;
|
|
596
611
|
|
|
597
|
-
const
|
|
612
|
+
const userRole = new State<string>('guest');
|
|
598
613
|
|
|
599
614
|
<Column>
|
|
600
|
-
<Button onClick={() => (
|
|
601
|
-
<Button onClick={() => (
|
|
602
|
-
<Button onClick={() => (
|
|
603
|
-
|
|
604
|
-
<Switch
|
|
615
|
+
<Button onClick={() => (userRole.value = 'admin')}>Admin</Button>
|
|
616
|
+
<Button onClick={() => (userRole.value = 'user')}>User</Button>
|
|
617
|
+
<Button onClick={() => (userRole.value = 'guest')}>Guest</Button>
|
|
618
|
+
|
|
619
|
+
<Switch condition={userRole} width="fill" height="fill">
|
|
620
|
+
<Case when="admin" create={AdminPanel} />
|
|
621
|
+
<Case when="user" create={UserPanel} />
|
|
622
|
+
<Case when="guest" create={GuestPanel} />
|
|
623
|
+
<Default create={GuestPanel} />
|
|
624
|
+
</Switch>
|
|
605
625
|
</Column>;
|
|
606
626
|
```
|
|
607
627
|
|
|
608
|
-
**Pattern 2:
|
|
628
|
+
**Pattern 2: Class Components with Props**
|
|
609
629
|
|
|
610
630
|
```tsx
|
|
611
|
-
import { State,
|
|
631
|
+
import { State, Switch, Case, Component } from 'asciitorium';
|
|
612
632
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
}
|
|
633
|
+
class SettingsPanel extends Component {
|
|
634
|
+
constructor(props: { theme: string }) {
|
|
635
|
+
super(props);
|
|
636
|
+
// Use props.theme
|
|
637
|
+
}
|
|
638
|
+
}
|
|
619
639
|
|
|
620
|
-
const
|
|
621
|
-
const selectedComponent = new State<any>(pageMap['home']);
|
|
640
|
+
const currentView = new State<string>('settings');
|
|
622
641
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
642
|
+
<Switch condition={currentView}>
|
|
643
|
+
<Case when="settings" create={SettingsPanel} with={{ theme: 'dark' }} />
|
|
644
|
+
<Case when="profile" create={ProfilePanel} />
|
|
645
|
+
</Switch>;
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Pattern 3: Navigation with Select**
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
import { State, Select, Option, Switch, Case } from 'asciitorium';
|
|
652
|
+
|
|
653
|
+
const selectedPage = new State<string>('home');
|
|
627
654
|
|
|
628
655
|
<Column>
|
|
629
|
-
<Select selected={
|
|
656
|
+
<Select selected={selectedPage}>
|
|
630
657
|
<Option value="home" label="Home" />
|
|
631
658
|
<Option value="about" label="About" />
|
|
632
659
|
<Option value="contact" label="Contact" />
|
|
633
660
|
</Select>
|
|
634
661
|
|
|
635
|
-
<Switch
|
|
662
|
+
<Switch condition={selectedPage} width="fill" height="fill">
|
|
663
|
+
<Case when="home" create={HomePage} />
|
|
664
|
+
<Case when="about" create={AboutPage} />
|
|
665
|
+
<Case when="contact" create={ContactPage} />
|
|
666
|
+
</Switch>
|
|
636
667
|
</Column>;
|
|
637
668
|
```
|
|
638
669
|
|
|
639
|
-
**Pattern
|
|
640
|
-
|
|
641
|
-
```tsx
|
|
642
|
-
// Using factory functions instead of constructors
|
|
643
|
-
const viewFactory = () => new CustomView({ customProp: 'value' });
|
|
644
|
-
const currentView = new State<any>(viewFactory);
|
|
645
|
-
|
|
646
|
-
<Switch component={currentView} />;
|
|
647
|
-
```
|
|
648
|
-
|
|
649
|
-
**Pattern 4: Component Instances**
|
|
670
|
+
**Pattern 4: Numeric Conditions**
|
|
650
671
|
|
|
651
672
|
```tsx
|
|
652
|
-
|
|
653
|
-
const dashboard = new DashboardView({ width: 80 });
|
|
654
|
-
const settings = new SettingsView({ width: 80 });
|
|
655
|
-
|
|
656
|
-
const currentView = new State<Component>(dashboard);
|
|
673
|
+
const level = new State<number>(1);
|
|
657
674
|
|
|
658
|
-
<
|
|
659
|
-
<
|
|
675
|
+
<Switch condition={level}>
|
|
676
|
+
<Case when={1} create={Level1} />
|
|
677
|
+
<Case when={2} create={Level2} />
|
|
678
|
+
<Case when={3} create={Level3} />
|
|
679
|
+
<Default create={CompletionScreen} />
|
|
680
|
+
</Switch>;
|
|
660
681
|
```
|
|
661
682
|
|
|
662
683
|
### Common Mistakes
|
|
663
684
|
|
|
664
|
-
❌ **WRONG** -
|
|
685
|
+
❌ **WRONG** - Using JSX children
|
|
665
686
|
|
|
666
687
|
```tsx
|
|
667
|
-
<Switch
|
|
688
|
+
<Switch condition={role}>
|
|
689
|
+
<Case when="admin">
|
|
690
|
+
<AdminPanel /> {/* Components persist in memory! */}
|
|
691
|
+
</Case>
|
|
692
|
+
</Switch>
|
|
668
693
|
```
|
|
669
694
|
|
|
670
|
-
✅ **CORRECT** - Using
|
|
695
|
+
✅ **CORRECT** - Using create prop
|
|
671
696
|
|
|
672
697
|
```tsx
|
|
673
|
-
|
|
674
|
-
<
|
|
698
|
+
<Switch condition={role}>
|
|
699
|
+
<Case when="admin" create={AdminPanel} />
|
|
700
|
+
</Switch>
|
|
675
701
|
```
|
|
676
702
|
|
|
677
|
-
❌ **WRONG** -
|
|
703
|
+
❌ **WRONG** - Missing Default fallback
|
|
678
704
|
|
|
679
705
|
```tsx
|
|
680
|
-
|
|
681
|
-
<
|
|
706
|
+
<Switch condition={status}>
|
|
707
|
+
<Case when="loading" create={Spinner} />
|
|
708
|
+
{/* No fallback - nothing shows if status is unknown */}
|
|
709
|
+
</Switch>
|
|
682
710
|
```
|
|
683
711
|
|
|
684
|
-
✅ **CORRECT** -
|
|
712
|
+
✅ **CORRECT** - Including Default
|
|
685
713
|
|
|
686
714
|
```tsx
|
|
687
|
-
|
|
688
|
-
<
|
|
715
|
+
<Switch condition={status}>
|
|
716
|
+
<Case when="loading" create={Spinner} />
|
|
717
|
+
<Default create={ErrorMessage} />
|
|
718
|
+
</Switch>
|
|
689
719
|
```
|
|
690
720
|
|
|
691
|
-
|
|
721
|
+
|
|
692
722
|
|
|
693
723
|
## TextInput
|
|
694
724
|
|
|
@@ -771,7 +801,7 @@ const text = new State('initial');
|
|
|
771
801
|
<Button onClick={() => console.log(inputValue.value)}>Submit</Button>
|
|
772
802
|
```
|
|
773
803
|
|
|
774
|
-
|
|
804
|
+
|
|
775
805
|
|
|
776
806
|
## Art
|
|
777
807
|
|
|
@@ -837,7 +867,7 @@ const text = new State('initial');
|
|
|
837
867
|
<Art font="standard" text="Title" /> // Generated
|
|
838
868
|
```
|
|
839
869
|
|
|
840
|
-
|
|
870
|
+
|
|
841
871
|
|
|
842
872
|
## Keybind
|
|
843
873
|
|
|
@@ -926,7 +956,7 @@ const gameStarted = new State(false);
|
|
|
926
956
|
<Keybind keyBinding="ArrowUp" action={() => moveUp()} />
|
|
927
957
|
```
|
|
928
958
|
|
|
929
|
-
|
|
959
|
+
|
|
930
960
|
|
|
931
961
|
## GameWorld
|
|
932
962
|
|
|
@@ -1055,7 +1085,7 @@ gameWorld.player.value.x += 1; // Bypasses collision detection
|
|
|
1055
1085
|
gameWorld.moveForward(); // Handles collision
|
|
1056
1086
|
```
|
|
1057
1087
|
|
|
1058
|
-
|
|
1088
|
+
|
|
1059
1089
|
|
|
1060
1090
|
## MapView
|
|
1061
1091
|
|
|
@@ -1138,7 +1168,7 @@ gameWorld.player.subscribe((p) => {
|
|
|
1138
1168
|
<MapView mapAsset={gameWorld.mapAsset} player={gameWorld.player} />
|
|
1139
1169
|
```
|
|
1140
1170
|
|
|
1141
|
-
|
|
1171
|
+
|
|
1142
1172
|
|
|
1143
1173
|
## FirstPersonView
|
|
1144
1174
|
|
|
@@ -1216,7 +1246,7 @@ gameWorld.player.subscribe((p) => {
|
|
|
1216
1246
|
<FirstPersonView mapAsset={gameWorld.mapAsset} player={gameWorld.player} />
|
|
1217
1247
|
```
|
|
1218
1248
|
|
|
1219
|
-
|
|
1249
|
+
|
|
1220
1250
|
|
|
1221
1251
|
## PerfMonitor
|
|
1222
1252
|
|
|
@@ -1267,7 +1297,7 @@ const showPerf = new State(false);
|
|
|
1267
1297
|
<PerfMonitor visible={showPerf} />
|
|
1268
1298
|
```
|
|
1269
1299
|
|
|
1270
|
-
|
|
1300
|
+
|
|
1271
1301
|
|
|
1272
1302
|
## Component Lifecycle
|
|
1273
1303
|
|
|
@@ -1307,7 +1337,7 @@ count.subscribe((newValue) => {
|
|
|
1307
1337
|
// No manual cleanup needed in most cases
|
|
1308
1338
|
```
|
|
1309
1339
|
|
|
1310
|
-
|
|
1340
|
+
|
|
1311
1341
|
|
|
1312
1342
|
## Legend System (Game Maps)
|
|
1313
1343
|
|
|
@@ -1368,7 +1398,7 @@ if (tile?.tag === 'door') {
|
|
|
1368
1398
|
}
|
|
1369
1399
|
```
|
|
1370
1400
|
|
|
1371
|
-
|
|
1401
|
+
|
|
1372
1402
|
|
|
1373
1403
|
## Directory Structure
|
|
1374
1404
|
|
|
@@ -1409,7 +1439,7 @@ Example:
|
|
|
1409
1439
|
╚══════════════════╝
|
|
1410
1440
|
```
|
|
1411
1441
|
|
|
1412
|
-
|
|
1442
|
+
|
|
1413
1443
|
|
|
1414
1444
|
## Type Annotations
|
|
1415
1445
|
|
|
@@ -1451,7 +1481,7 @@ const entry: LegendEntry = {
|
|
|
1451
1481
|
};
|
|
1452
1482
|
```
|
|
1453
1483
|
|
|
1454
|
-
|
|
1484
|
+
|
|
1455
1485
|
|
|
1456
1486
|
## Complete Example: Simple Game
|
|
1457
1487
|
|
|
@@ -1522,28 +1552,32 @@ const app = (
|
|
|
1522
1552
|
await app.start();
|
|
1523
1553
|
```
|
|
1524
1554
|
|
|
1525
|
-
|
|
1555
|
+
|
|
1526
1556
|
|
|
1527
1557
|
## Understanding "auto" vs Omitting Props
|
|
1528
1558
|
|
|
1529
|
-
**Key Concept:** In ASCIITORIUM, omitting `width` or `height` props is the same
|
|
1559
|
+
**Key Concept:** In ASCIITORIUM, omitting `width` or `height` props is the same
|
|
1560
|
+
as setting them to `undefined` or `"auto"`.
|
|
1530
1561
|
|
|
1531
1562
|
- `width={40}` → Fixed width of 40 characters
|
|
1532
1563
|
- `width="fill"` → Fill available parent space
|
|
1533
1564
|
- `width="auto"` → Auto-size to content (same as omitting the prop)
|
|
1534
1565
|
- _Omitting width prop_ → Auto-size to content (recommended approach)
|
|
1535
1566
|
|
|
1536
|
-
**Recommendation:** Omit props instead of using `"auto"` for clarity. The type
|
|
1567
|
+
**Recommendation:** Omit props instead of using `"auto"` for clarity. The type
|
|
1568
|
+
system allows `"auto"` but it's unnecessary.
|
|
1537
1569
|
|
|
1538
1570
|
**Component-specific auto-sizing:**
|
|
1539
1571
|
|
|
1540
|
-
- **Text**: Auto-sizes to content length (width) and wrapped lines (height) when
|
|
1541
|
-
|
|
1572
|
+
- **Text**: Auto-sizes to content length (width) and wrapped lines (height) when
|
|
1573
|
+
props omitted
|
|
1574
|
+
- **Button**: Always calculates size based on content (`buttonText.length + 7`
|
|
1575
|
+
for width, `4` for height)
|
|
1542
1576
|
- **Art**: Auto-sizes to loaded art dimensions when props omitted
|
|
1543
1577
|
- **Column**: Auto-sizes to fit children when width omitted
|
|
1544
1578
|
- **Row**: Defaults to `width="fill"`
|
|
1545
1579
|
|
|
1546
|
-
|
|
1580
|
+
|
|
1547
1581
|
|
|
1548
1582
|
## Tips for LLMs
|
|
1549
1583
|
|
|
@@ -1552,12 +1586,16 @@ await app.start();
|
|
|
1552
1586
|
3. **Text newlines use `¶` (pilcrow)** - Not `\n`
|
|
1553
1587
|
4. **Components accept children via JSX or explicit props** - Both patterns work
|
|
1554
1588
|
5. **GameWorld must be awaited** - `await gameWorld.ready` before rendering
|
|
1555
|
-
6. **Keybinds are invisible components** - They never render, just register
|
|
1556
|
-
|
|
1589
|
+
6. **Keybinds are invisible components** - They never render, just register
|
|
1590
|
+
handlers
|
|
1591
|
+
7. **MapView and FirstPersonView are display-only** - Movement logic goes in
|
|
1592
|
+
GameWorld or Keybinds
|
|
1557
1593
|
8. **Legend system drives collision** - Use `isSolid()` for movement validation
|
|
1558
1594
|
9. **No CSS or className** - ASCIITORIUM uses ASCII rendering, not DOM styling
|
|
1559
|
-
10. **Omit width/height props for auto-sizing** - Components have smart defaults
|
|
1595
|
+
10. **Omit width/height props for auto-sizing** - Components have smart defaults
|
|
1596
|
+
(Text/Art/Column size to content, Button calculates from label, Row fills
|
|
1597
|
+
width)
|
|
1598
|
+
|
|
1560
1599
|
|
|
1561
|
-
---
|
|
1562
1600
|
|
|
1563
1601
|
_End of Reference_
|