@medieval-kit/registry 0.1.0
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/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/registry.json +3551 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CRTkafa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Medieval Kit
|
|
2
|
+
|
|
3
|
+
A lowpoly medieval model library for [Vibe3D](https://github.com/vibe-stack/vibe3d)
|
|
4
|
+
and Three.js. Install a prop and you own its source: readable TypeScript in your
|
|
5
|
+
own tree, not an opaque package boundary.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
bunx vibe3d init
|
|
15
|
+
bun add three
|
|
16
|
+
bun add -d @types/three
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`init` writes `models.json` and puts the shared Vibe3D runtime under
|
|
20
|
+
`src/lib/vibe3d/`, which the installed models import from. `@types/three` is a
|
|
21
|
+
dev dependency and not optional: `three` ships no type declarations of its own,
|
|
22
|
+
so without it the source you just installed does not typecheck.
|
|
23
|
+
|
|
24
|
+
`init` seeds `models.json` with `@scifi-kit` only, so add this registry to the
|
|
25
|
+
`registries` object it created:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"registries": {
|
|
30
|
+
"@medieval-kit": {
|
|
31
|
+
"source": "npm:@medieval-kit/registry",
|
|
32
|
+
"version": "latest"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That map is how the namespace resolves — `vibe3d add` stops with
|
|
39
|
+
`Registry @medieval-kit is not configured in models.json` without it.
|
|
40
|
+
|
|
41
|
+
Then take one model, or the lot:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
bunx vibe3d add @medieval-kit/wooden-barrel
|
|
45
|
+
bunx vibe3d add @medieval-kit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Project setup
|
|
49
|
+
|
|
50
|
+
The installed source imports through the `@/` alias that `models.json` declares,
|
|
51
|
+
and it imports `.ts` files by their extension. Both have to be true on your side
|
|
52
|
+
as well — in `tsconfig.json`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"compilerOptions": {
|
|
57
|
+
"moduleResolution": "bundler",
|
|
58
|
+
"allowImportingTsExtensions": true,
|
|
59
|
+
"baseUrl": ".",
|
|
60
|
+
"paths": { "@/*": ["./src/*"] }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
and in your bundler, because TypeScript's `paths` only teaches the type checker.
|
|
66
|
+
For Vite:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
resolve: { alias: [{ find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) }] }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Models
|
|
73
|
+
|
|
74
|
+
37 models and one shared lib. Addresses are `@medieval-kit/<id>`. This table is
|
|
75
|
+
generated from the models themselves with `bun scripts/catalog-table.ts` — a
|
|
76
|
+
hand-written list goes stale on the first model you add, and this one already
|
|
77
|
+
did once.
|
|
78
|
+
|
|
79
|
+
| Model | Category | Triangles | Parts | Size (m) | Material slots | Animated |
|
|
80
|
+
| --- | --- | ---: | ---: | --- | --- | :-: |
|
|
81
|
+
| `wooden-chest` | Furniture | 552 | 4 | 0.86×0.51×0.48 | oak, iron | ✔ |
|
|
82
|
+
| `wooden-barrel` | Props | 1690 | 3 | 0.83×1.05×0.83 | oak, iron | |
|
|
83
|
+
| `wooden-crate` | Props | 1320 | 3 | 0.69×0.52×0.55 | oak, iron | |
|
|
84
|
+
| `wooden-bucket` | Props | 439 | 4 | 0.31×0.46×0.30 | oak, iron | |
|
|
85
|
+
| `trestle-table` | Furniture | 660 | 3 | 1.91×0.74×0.78 | oak | |
|
|
86
|
+
| `wooden-bench` | Furniture | 216 | 3 | 1.62×0.45×0.30 | oak | |
|
|
87
|
+
| `wooden-stool` | Furniture | 180 | 2 | 0.38×0.43×0.36 | oak | |
|
|
88
|
+
| `pitch-torch` | Lighting | 239 | 3 | 0.13×0.70×0.13 | oak, char, ember | ✔ |
|
|
89
|
+
| `iron-lantern` | Lighting | 480 | 4 | 0.15×0.30×0.17 | iron, glass, char, ember | ✔ |
|
|
90
|
+
| `iron-anvil` | Smithy | 256 | 6 | 0.54×0.75×0.41 | iron, steel, oak | |
|
|
91
|
+
| `cart-wheel` | Structure | 1136 | 4 | 1.04×1.06×0.19 | oak, iron | |
|
|
92
|
+
| `log-pile` | Props | 924 | 2 | 0.99×0.58×0.70 | oak | |
|
|
93
|
+
| `hay-bale` | Props | 910 | 3 | 1.04×0.42×0.43 | straw, cloth | |
|
|
94
|
+
| `linen-sack` | Props | 342 | 3 | 0.34×0.53×0.33 | cloth | |
|
|
95
|
+
| `oak-tankard` | Props | 390 | 4 | 0.11×0.16×0.14 | oak, iron | |
|
|
96
|
+
| `straw-broom` | Tools | 1048 | 3 | 0.30×1.22×0.30 | oak, straw, cloth | |
|
|
97
|
+
| `bronze-bell` | Props | 1048 | 4 | 0.51×0.68×0.36 | brass, iron, oak | ✔ |
|
|
98
|
+
| `tavern-sign` | Props | 876 | 3 | 0.38×2.29×0.93 | oak, iron | ✔ |
|
|
99
|
+
| `wicker-basket` | Props | 2326 | 3 | 0.34×0.16×0.35 | oak, produce | |
|
|
100
|
+
| `leather-book` | Props | 440 | 3 | 0.20×0.08×0.27 | leather, cloth, brass | |
|
|
101
|
+
| `glass-phial` | Props | 339 | 3 | 0.06×0.14×0.06 | glass, ember, oak, char | |
|
|
102
|
+
| `coin-pouch` | Props | 602 | 3 | 0.18×0.11×0.16 | leather, cloth, brass | |
|
|
103
|
+
| `wooden-ladder` | Structure | 440 | 2 | 0.49×2.20×0.06 | oak | |
|
|
104
|
+
| `wooden-fence` | Structure | 860 | 2 | 5.18×1.31×0.31 | oak | |
|
|
105
|
+
| `wooden-hoe` | Tools | 394 | 3 | 0.23×1.23×0.33 | oak, iron, steel | |
|
|
106
|
+
| `wooden-shovel` | Tools | 496 | 3 | 0.27×1.20×0.08 | oak, iron | |
|
|
107
|
+
| `wooden-pitchfork` | Tools | 392 | 3 | 0.27×1.58×0.15 | oak, iron | |
|
|
108
|
+
| `iron-cauldron` | Lighting | 1134 | 3 | 1.09×1.37×1.10 | stone, iron, char, ember | ✔ |
|
|
109
|
+
| `hand-cart` | Structure | 2044 | 4 | 0.87×0.68×2.49 | oak, iron | ✔ |
|
|
110
|
+
| `vegetables` | Props | 1718 | 2 | 0.60×0.12×0.59 | produce | |
|
|
111
|
+
| `round-shield` | Arms | 729 | 3 | 0.73×0.73×0.17 | oak, leather, iron | |
|
|
112
|
+
| `forge-hearth` | Smithy | 1426 | 4 | 2.06×1.78×0.87 | stone, char, ember, oak, leather, iron | ✔ |
|
|
113
|
+
| `stone-well` | Structure | 1376 | 4 | 1.88×2.00×1.28 | stone, oak, iron, cloth | ✔ |
|
|
114
|
+
| `stone-trough` | Structure | 344 | 2 | 1.52×0.45×0.60 | stone, water | |
|
|
115
|
+
| `grindstone` | Smithy | 568 | 4 | 1.24×0.95×0.70 | stone, oak, iron, water | ✔ |
|
|
116
|
+
| `market-stall` | Structure | 384 | 4 | 1.83×2.03×0.97 | oak, cloth | |
|
|
117
|
+
| `post-mill` | Structure | 1672 | 4 | 6.60×7.23×6.98 | oak, iron | ✔ |
|
|
118
|
+
|
|
119
|
+
**30 390 triangles** in total. The whole kit in one scene costs less than a
|
|
120
|
+
single mid-complexity character model.
|
|
121
|
+
|
|
122
|
+
Every model depends on `@medieval-kit/core`, a shared support item holding the
|
|
123
|
+
palette, deterministic randomness, and the geometry vocabulary. Pulling a single
|
|
124
|
+
prop brings it along, so an individually installed crate still looks like it
|
|
125
|
+
came from the same catalogue as the barrel beside it.
|
|
126
|
+
|
|
127
|
+
## Plain WebGL
|
|
128
|
+
|
|
129
|
+
This kit does **not** require WebGPU. It declares `capabilities: []` and builds
|
|
130
|
+
on `MeshStandardMaterial` and `MeshBasicMaterial`, so it renders on
|
|
131
|
+
`WebGLRenderer` as well as `WebGPURenderer`.
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
Models are procedural, not baked. Every prop exposes typed fields:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { createModel } from '@/models/medieval-kit/wooden-barrel/model.ts'
|
|
139
|
+
|
|
140
|
+
const barrel = createModel({ staveCount: 17, taper: 0.22, seed: 42 })
|
|
141
|
+
scene.add(barrel.root)
|
|
142
|
+
|
|
143
|
+
barrel.configure({ hoopCount: 6 }) // rebuilds geometry inside a stable root
|
|
144
|
+
barrel.dispose()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`seed` is a real field, not a debug knob. Variation is deterministic: the same
|
|
148
|
+
seed always produces the same prop, so previews, tests, and art direction stay
|
|
149
|
+
reproducible. Change the seed to get a different barrel from the same model.
|
|
150
|
+
|
|
151
|
+
## Runtime anatomy
|
|
152
|
+
|
|
153
|
+
Each model follows the Vibe3D protocol:
|
|
154
|
+
|
|
155
|
+
- **`root`** keeps its object identity for the model's whole lifetime.
|
|
156
|
+
- **`parts`** expose stable semantic anchors. Attach your own lights, labels, or
|
|
157
|
+
gameplay objects to `part.anchor` — they survive `configure()`, because only
|
|
158
|
+
`part.content` is rebuilt.
|
|
159
|
+
- **`materials`** resolve per slot and can be overridden. Materials you supply
|
|
160
|
+
are borrowed: the model never disposes them.
|
|
161
|
+
- **`actions`** and **`update(delta)`** carry interactive state. Eleven models
|
|
162
|
+
have them, and they are the ✔ column in the table above: `wooden-chest`,
|
|
163
|
+
`pitch-torch`, `iron-lantern`, `bronze-bell`, `tavern-sign`, `iron-cauldron`,
|
|
164
|
+
`hand-cart`, `forge-hearth`, `stone-well`, `grindstone` and `post-mill`. Crank
|
|
165
|
+
the grindstone and it turns and slows; set the mill turning and its sails go
|
|
166
|
+
round; lower the well's bucket down the shaft:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const chest = createModel()
|
|
170
|
+
chest.actions.setOpen(true)
|
|
171
|
+
chest.update(deltaSeconds) // the lid eases open, frame-rate independent
|
|
172
|
+
|
|
173
|
+
const torch = createModel()
|
|
174
|
+
torch.actions.setLit(false)
|
|
175
|
+
torch.update(deltaSeconds) // flame flicker and light modulation
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
A model that never receives `update()` simply stands still; nothing animates
|
|
179
|
+
behind your back. Reach for `configure()` when a user changes a setting; it
|
|
180
|
+
rebuilds topology and is not cheap. Anything that changes per frame belongs in
|
|
181
|
+
`update()`.
|
|
182
|
+
|
|
183
|
+
## Material slots
|
|
184
|
+
|
|
185
|
+
Thirteen slots, and each one exists because a single material could not carry the
|
|
186
|
+
difference.
|
|
187
|
+
|
|
188
|
+
| Slot | What it covers | Why it is separate |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `oak` | timber | — |
|
|
191
|
+
| `iron` | forged iron, oxidised and matte | separate from `steel`: the difference is not in colour but in ROUGHNESS, and vertex colour cannot carry roughness |
|
|
192
|
+
| `steel` | steel polished by use | the anvil face, the shovel blade, the pitchfork tines |
|
|
193
|
+
| `brass` | bronze and copper | the bell, the coins |
|
|
194
|
+
| `straw` | straw, wicker, broom bristle | a bale declaring itself "oak" would be a lie told to the consumer |
|
|
195
|
+
| `cloth` | linen, sackcloth, rope | — |
|
|
196
|
+
| `leather` | worked leather | — |
|
|
197
|
+
| `glass` | blown glass | transparent, `depthWrite` OFF, `DoubleSide` |
|
|
198
|
+
| `produce` | fruit and vegetable skin | given straw's roughness, an apple would look like dry grass |
|
|
199
|
+
| `ember` | flame | `MeshBasicMaterial` — it does not receive light, it emits |
|
|
200
|
+
| `char` | charcoal and pitch | — |
|
|
201
|
+
| `water` | standing water | a thin transparent film over whatever holds it: in the reference trough the basin reads hue 39.5, which is the hue of the STONE underneath, so it works through opacity rather than colour |
|
|
202
|
+
| `stone` | dressed and rubble masonry | its colour is close to weathered oak; what separates them at a glance is that stone scatters light completely flat, and roughness is not something vertex colour can carry |
|
|
203
|
+
|
|
204
|
+
`ember` also acts as a rule in two places: bodies in that slot are skipped
|
|
205
|
+
entirely while ambient occlusion and mottle are baked. The reason is simple —
|
|
206
|
+
in an unlit material the vertex colour *is* the final colour, so darkening it
|
|
207
|
+
puts the flame out. The rule is attached to the slot itself rather than to a
|
|
208
|
+
per-model flag, so it cannot be forgotten.
|
|
209
|
+
|
|
210
|
+
Colour variation lives in the geometry, not in the materials: each of the
|
|
211
|
+
barrel's 17 staves carries its own tone as vertex colours, and all of them share
|
|
212
|
+
one material and therefore one draw call.
|
|
213
|
+
|
|
214
|
+
## Building from source
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
bun build.ts # emit dist/registry.json
|
|
218
|
+
bunx vibe3d registry validate dist/registry.json
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The build walks `models/`. A folder containing `model.ts` becomes a
|
|
222
|
+
`vibe3d:model`; any other folder becomes a `vibe3d:lib`. Registry dependencies
|
|
223
|
+
are derived from the source — an import from `../core/` makes
|
|
224
|
+
`@medieval-kit/core` a dependency automatically, so there is no hand-maintained
|
|
225
|
+
list to go stale.
|
|
226
|
+
|
|
227
|
+
`drafts/` is deliberately outside that walk: the code is kept in the tree but
|
|
228
|
+
never reaches the published package — including its own `drafts/README.md`,
|
|
229
|
+
which is why this sentence does not link to it. A relative link on an npm
|
|
230
|
+
package page resolves against the repository, and there is nothing at the
|
|
231
|
+
other end of it for a reader of this page.
|
|
232
|
+
|
|
233
|
+
Released under the MIT License.
|