Bind the book the way a board binding is bound, and soften the pouch
The page block was written as 1.035 of the cover, spilling past it on three sides -- the comment above it said so plainly, and it is backwards. The overhang is called the square and it is the entire point of a board binding: the boards take the knocks so the leaves do not. Written the wrong way round the model read as a ream of paper with a leather lid, which is what it had always looked like. Flush at the spine, inset on the three free edges, and the leather now shows around the block. With that, the boards are also thicker. At a ninth of the book each they came to 14 mm against 48 mm of paper; a medieval binding is oak boards first and leather second, and they are substantial. And the book now has its corner bosses. They are the most recognisable thing about a book of this period and there were none. Not ornament either: a volume this heavy was stored flat, often on its side, and the bosses hold the leather clear of the shelf so it does not abrade -- the same edges the square protects. The pouch's body goes from nine sides to thirteen. Leather has no facets, and the body is the whole silhouette of that model. The spilled coins beside it stay. That is not a fault: the config field says "number of coins spilled outside", so the scatter is the model's own idea and pulling it in would be redesigning rather than fixing. 27 models, 19007 triangles, all checks pass, 0 floating cases, build clean.
This commit is contained in:
parent
85f423fe10
commit
64e8932d1b
5 changed files with 141 additions and 43 deletions
|
|
@ -67,7 +67,7 @@
|
||||||
"address": "@medieval-kit/wooden-barrel",
|
"address": "@medieval-kit/wooden-barrel",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.944Z",
|
"installedAt": "2026-08-23T05:02:54.976Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-barrel\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-barrel\\model.ts",
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
"address": "@medieval-kit/core",
|
"address": "@medieval-kit/core",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.925Z",
|
"installedAt": "2026-08-23T05:02:54.957Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\core\\geometry.ts",
|
"path": "src\\models\\medieval-kit\\core\\geometry.ts",
|
||||||
|
|
@ -129,7 +129,7 @@
|
||||||
"address": "@medieval-kit/wooden-crate",
|
"address": "@medieval-kit/wooden-crate",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.948Z",
|
"installedAt": "2026-08-23T05:02:54.980Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-crate\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-crate\\model.ts",
|
||||||
|
|
@ -144,7 +144,7 @@
|
||||||
"address": "@medieval-kit/kit",
|
"address": "@medieval-kit/kit",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.954Z",
|
"installedAt": "2026-08-23T05:02:54.985Z",
|
||||||
"files": [],
|
"files": [],
|
||||||
"dependencies": []
|
"dependencies": []
|
||||||
},
|
},
|
||||||
|
|
@ -152,7 +152,7 @@
|
||||||
"address": "@medieval-kit/iron-anvil",
|
"address": "@medieval-kit/iron-anvil",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.932Z",
|
"installedAt": "2026-08-23T05:02:54.964Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\iron-anvil\\model.ts",
|
"path": "src\\models\\medieval-kit\\iron-anvil\\model.ts",
|
||||||
|
|
@ -167,7 +167,7 @@
|
||||||
"address": "@medieval-kit/wooden-bucket",
|
"address": "@medieval-kit/wooden-bucket",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.946Z",
|
"installedAt": "2026-08-23T05:02:54.978Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-bucket\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-bucket\\model.ts",
|
||||||
|
|
@ -182,7 +182,7 @@
|
||||||
"address": "@medieval-kit/wooden-fence",
|
"address": "@medieval-kit/wooden-fence",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.949Z",
|
"installedAt": "2026-08-23T05:02:54.981Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-fence\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-fence\\model.ts",
|
||||||
|
|
@ -197,7 +197,7 @@
|
||||||
"address": "@medieval-kit/wooden-hoe",
|
"address": "@medieval-kit/wooden-hoe",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.950Z",
|
"installedAt": "2026-08-23T05:02:54.982Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-hoe\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-hoe\\model.ts",
|
||||||
|
|
@ -212,7 +212,7 @@
|
||||||
"address": "@medieval-kit/wooden-ladder",
|
"address": "@medieval-kit/wooden-ladder",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.951Z",
|
"installedAt": "2026-08-23T05:02:54.982Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-ladder\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-ladder\\model.ts",
|
||||||
|
|
@ -227,7 +227,7 @@
|
||||||
"address": "@medieval-kit/wooden-pitchfork",
|
"address": "@medieval-kit/wooden-pitchfork",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.952Z",
|
"installedAt": "2026-08-23T05:02:54.983Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-pitchfork\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-pitchfork\\model.ts",
|
||||||
|
|
@ -242,7 +242,7 @@
|
||||||
"address": "@medieval-kit/wooden-shovel",
|
"address": "@medieval-kit/wooden-shovel",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.953Z",
|
"installedAt": "2026-08-23T05:02:54.984Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-shovel\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-shovel\\model.ts",
|
||||||
|
|
@ -257,7 +257,7 @@
|
||||||
"address": "@medieval-kit/wooden-stool",
|
"address": "@medieval-kit/wooden-stool",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.954Z",
|
"installedAt": "2026-08-23T05:02:54.985Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-stool\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-stool\\model.ts",
|
||||||
|
|
@ -272,7 +272,7 @@
|
||||||
"address": "@medieval-kit/cart-wheel",
|
"address": "@medieval-kit/cart-wheel",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.928Z",
|
"installedAt": "2026-08-23T05:02:54.960Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\cart-wheel\\model.ts",
|
"path": "src\\models\\medieval-kit\\cart-wheel\\model.ts",
|
||||||
|
|
@ -287,7 +287,7 @@
|
||||||
"address": "@medieval-kit/log-pile",
|
"address": "@medieval-kit/log-pile",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.936Z",
|
"installedAt": "2026-08-23T05:02:54.968Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\log-pile\\model.ts",
|
"path": "src\\models\\medieval-kit\\log-pile\\model.ts",
|
||||||
|
|
@ -302,7 +302,7 @@
|
||||||
"address": "@medieval-kit/trestle-table",
|
"address": "@medieval-kit/trestle-table",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.942Z",
|
"installedAt": "2026-08-23T05:02:54.974Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\trestle-table\\model.ts",
|
"path": "src\\models\\medieval-kit\\trestle-table\\model.ts",
|
||||||
|
|
@ -317,7 +317,7 @@
|
||||||
"address": "@medieval-kit/wooden-chest",
|
"address": "@medieval-kit/wooden-chest",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.947Z",
|
"installedAt": "2026-08-23T05:02:54.979Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-chest\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-chest\\model.ts",
|
||||||
|
|
@ -332,7 +332,7 @@
|
||||||
"address": "@medieval-kit/hay-bale",
|
"address": "@medieval-kit/hay-bale",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.931Z",
|
"installedAt": "2026-08-23T05:02:54.963Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\hay-bale\\model.ts",
|
"path": "src\\models\\medieval-kit\\hay-bale\\model.ts",
|
||||||
|
|
@ -347,7 +347,7 @@
|
||||||
"address": "@medieval-kit/pitch-torch",
|
"address": "@medieval-kit/pitch-torch",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.938Z",
|
"installedAt": "2026-08-23T05:02:54.970Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\pitch-torch\\model.ts",
|
"path": "src\\models\\medieval-kit\\pitch-torch\\model.ts",
|
||||||
|
|
@ -362,7 +362,7 @@
|
||||||
"address": "@medieval-kit/wooden-bench",
|
"address": "@medieval-kit/wooden-bench",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.945Z",
|
"installedAt": "2026-08-23T05:02:54.977Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wooden-bench\\model.ts",
|
"path": "src\\models\\medieval-kit\\wooden-bench\\model.ts",
|
||||||
|
|
@ -377,7 +377,7 @@
|
||||||
"address": "@medieval-kit/linen-sack",
|
"address": "@medieval-kit/linen-sack",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.935Z",
|
"installedAt": "2026-08-23T05:02:54.967Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\linen-sack\\model.ts",
|
"path": "src\\models\\medieval-kit\\linen-sack\\model.ts",
|
||||||
|
|
@ -392,7 +392,7 @@
|
||||||
"address": "@medieval-kit/oak-tankard",
|
"address": "@medieval-kit/oak-tankard",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.937Z",
|
"installedAt": "2026-08-23T05:02:54.969Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\oak-tankard\\model.ts",
|
"path": "src\\models\\medieval-kit\\oak-tankard\\model.ts",
|
||||||
|
|
@ -407,7 +407,7 @@
|
||||||
"address": "@medieval-kit/straw-broom",
|
"address": "@medieval-kit/straw-broom",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.939Z",
|
"installedAt": "2026-08-23T05:02:54.971Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\straw-broom\\model.ts",
|
"path": "src\\models\\medieval-kit\\straw-broom\\model.ts",
|
||||||
|
|
@ -422,7 +422,7 @@
|
||||||
"address": "@medieval-kit/bronze-bell",
|
"address": "@medieval-kit/bronze-bell",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.927Z",
|
"installedAt": "2026-08-23T05:02:54.959Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\bronze-bell\\model.ts",
|
"path": "src\\models\\medieval-kit\\bronze-bell\\model.ts",
|
||||||
|
|
@ -437,7 +437,7 @@
|
||||||
"address": "@medieval-kit/iron-lantern",
|
"address": "@medieval-kit/iron-lantern",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.933Z",
|
"installedAt": "2026-08-23T05:02:54.965Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\iron-lantern\\model.ts",
|
"path": "src\\models\\medieval-kit\\iron-lantern\\model.ts",
|
||||||
|
|
@ -452,7 +452,7 @@
|
||||||
"address": "@medieval-kit/tavern-sign",
|
"address": "@medieval-kit/tavern-sign",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.940Z",
|
"installedAt": "2026-08-23T05:02:54.972Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\tavern-sign\\model.ts",
|
"path": "src\\models\\medieval-kit\\tavern-sign\\model.ts",
|
||||||
|
|
@ -467,11 +467,11 @@
|
||||||
"address": "@medieval-kit/coin-pouch",
|
"address": "@medieval-kit/coin-pouch",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.929Z",
|
"installedAt": "2026-08-23T05:02:54.961Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\coin-pouch\\model.ts",
|
"path": "src\\models\\medieval-kit\\coin-pouch\\model.ts",
|
||||||
"sourceHash": "e635a892ed2ebc3d1211383eb289e23f55b72eb8fe285cce81510fefec269e70"
|
"sourceHash": "0f3f18fbe15f17b0fefe335586bb2f3bfb4753d422f62aad2bb42e95d39fad78"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|
@ -482,7 +482,7 @@
|
||||||
"address": "@medieval-kit/glass-phial",
|
"address": "@medieval-kit/glass-phial",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.930Z",
|
"installedAt": "2026-08-23T05:02:54.962Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\glass-phial\\model.ts",
|
"path": "src\\models\\medieval-kit\\glass-phial\\model.ts",
|
||||||
|
|
@ -497,11 +497,11 @@
|
||||||
"address": "@medieval-kit/leather-book",
|
"address": "@medieval-kit/leather-book",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.934Z",
|
"installedAt": "2026-08-23T05:02:54.966Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\leather-book\\model.ts",
|
"path": "src\\models\\medieval-kit\\leather-book\\model.ts",
|
||||||
"sourceHash": "54d1c424c124e06ea529081f2a3f3e787ec9b4b4ceac582e5ed3754d8e6f1175"
|
"sourceHash": "60857ef9cbab7e83c0e52f89370591e4988f06a82264bf475a14a60551914fe0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|
@ -512,7 +512,7 @@
|
||||||
"address": "@medieval-kit/wicker-basket",
|
"address": "@medieval-kit/wicker-basket",
|
||||||
"source": "file:my-registry/dist/registry.json",
|
"source": "file:my-registry/dist/registry.json",
|
||||||
"version": "workspace",
|
"version": "workspace",
|
||||||
"installedAt": "2026-08-23T04:56:51.943Z",
|
"installedAt": "2026-08-23T05:02:54.975Z",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"path": "src\\models\\medieval-kit\\wicker-basket\\model.ts",
|
"path": "src\\models\\medieval-kit\\wicker-basket\\model.ts",
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,10 @@ export function createModel(overrides: Partial<CoinPouchConfig> = {}) {
|
||||||
{ y: neckY + config.height * 0.16, radius: config.radius * 0.26 },
|
{ y: neckY + config.height * 0.16, radius: config.radius * 0.26 },
|
||||||
{ y: neckY + config.height * 0.28, radius: config.radius * 0.34 },
|
{ y: neckY + config.height * 0.28, radius: config.radius * 0.34 },
|
||||||
]
|
]
|
||||||
const pouch = latheGeometry(profile, 9, [0, 0, 0], tint('leather', -0.05, 0.9), {
|
// Thirteen sides, not nine. Leather has no facets: at nine the pouch was
|
||||||
|
// a hard-edged lump where the reference is a soft bag, and the body is
|
||||||
|
// the whole silhouette of this model.
|
||||||
|
const pouch = latheGeometry(profile, 13, [0, 0, 0], tint('leather', -0.05, 0.9), {
|
||||||
colourTop: tint('leather', 0.06, 0.9),
|
colourTop: tint('leather', 0.06, 0.9),
|
||||||
capTop: true,
|
capTop: true,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import {
|
||||||
createTinter,
|
createTinter,
|
||||||
jitter,
|
jitter,
|
||||||
mergeColoured,
|
mergeColoured,
|
||||||
|
flipGeometry,
|
||||||
|
prismGeometry,
|
||||||
roughenGeometry,
|
roughenGeometry,
|
||||||
} from '../core/index.ts'
|
} from '../core/index.ts'
|
||||||
|
|
||||||
|
|
@ -61,7 +63,11 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
build: ({ config, random }) => {
|
build: ({ config, random }) => {
|
||||||
const tint = createTinter(random)
|
const tint = createTinter(random)
|
||||||
const half = config.thickness / 2
|
const half = config.thickness / 2
|
||||||
const boardThickness = config.thickness * 0.11
|
// 0.16, not 0.11. At a ninth of the book each way the two boards came
|
||||||
|
// to 14 mm against 48 mm of paper, and the thing read as a ream with
|
||||||
|
// leather stuck to it. A medieval binding is oak boards first, covered
|
||||||
|
// in leather second, and they are substantial.
|
||||||
|
const boardThickness = config.thickness * 0.16
|
||||||
const halfWidth = config.width / 2
|
const halfWidth = config.width / 2
|
||||||
const spineX = -halfWidth
|
const spineX = -halfWidth
|
||||||
|
|
||||||
|
|
@ -111,13 +117,22 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Page block ---------------------------------------------------------
|
// --- Page block ---------------------------------------------------------
|
||||||
// Spills past the cover on three sides (not the spine) with ragged edges.
|
// The BOARDS overhang the pages, not the other way round.
|
||||||
|
//
|
||||||
|
// This was written the wrong way round -- pages at 1.035 of the cover,
|
||||||
|
// spilling past it on three sides -- and it is why the model read as a
|
||||||
|
// ream of paper with a leather lid rather than as a book. The overhang
|
||||||
|
// is called the square and it is the whole point of a board binding:
|
||||||
|
// the boards take the knocks so the leaves do not, which is also what
|
||||||
|
// the corner bosses are protecting. Flush at the spine, inset on the
|
||||||
|
// three free edges.
|
||||||
|
const square = config.width * 0.055
|
||||||
const pages = chamferedBoxGeometry(
|
const pages = chamferedBoxGeometry(
|
||||||
[config.width * 1.035, config.length * 1.03],
|
[config.width - square, config.length - square * 1.1],
|
||||||
[config.width * 1.03, config.length * 1.025],
|
[config.width - square * 1.15, config.length - square * 1.25],
|
||||||
config.thickness - boardThickness * 2.4,
|
config.thickness - boardThickness * 2.4,
|
||||||
config.thickness * 0.02,
|
config.thickness * 0.02,
|
||||||
[config.width * 0.018, 0, 0],
|
[-square / 2, 0, 0],
|
||||||
tint('cloth', 0.09, 0.7),
|
tint('cloth', 0.09, 0.7),
|
||||||
)
|
)
|
||||||
// Vellum is not flat: the waviness at the edge is what makes the block
|
// Vellum is not flat: the waviness at the edge is what makes the block
|
||||||
|
|
@ -149,6 +164,37 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Corner bosses ------------------------------------------------------
|
||||||
|
// Brass studs at the four corners of both boards.
|
||||||
|
//
|
||||||
|
// These are the single most recognisable thing about a medieval book and
|
||||||
|
// the model had none. They are not ornament: a book of this weight was
|
||||||
|
// stored FLAT, often on its side, and the bosses hold the leather clear
|
||||||
|
// of the shelf so it does not abrade. Without them the silhouette is a
|
||||||
|
// modern hardback.
|
||||||
|
const bossRadius = config.width * 0.055
|
||||||
|
for (const side of [-1, 1]) {
|
||||||
|
for (const sx of [-1, 1]) {
|
||||||
|
for (const sz of [-1, 1]) {
|
||||||
|
const boss = prismGeometry(
|
||||||
|
bossRadius,
|
||||||
|
bossRadius * 0.55,
|
||||||
|
config.thickness * 0.2,
|
||||||
|
6,
|
||||||
|
[
|
||||||
|
sx * halfWidth * 0.78,
|
||||||
|
side * (half + config.thickness * 0.04),
|
||||||
|
sz * (config.length / 2) * 0.84,
|
||||||
|
],
|
||||||
|
tint('brass', side > 0 ? 0.04 : -0.02, 0.6),
|
||||||
|
)
|
||||||
|
// Domes point away from the book on each face.
|
||||||
|
if (side < 0) flipGeometry(boss)
|
||||||
|
claspPieces.push(boss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cover: { slot: 'leather' as const, geometry: mergeColoured(cover) },
|
cover: { slot: 'leather' as const, geometry: mergeColoured(cover) },
|
||||||
pages: { slot: 'cloth' as const, geometry: mergeColoured([pages]) },
|
pages: { slot: 'cloth' as const, geometry: mergeColoured([pages]) },
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,10 @@ export function createModel(overrides: Partial<CoinPouchConfig> = {}) {
|
||||||
{ y: neckY + config.height * 0.16, radius: config.radius * 0.26 },
|
{ y: neckY + config.height * 0.16, radius: config.radius * 0.26 },
|
||||||
{ y: neckY + config.height * 0.28, radius: config.radius * 0.34 },
|
{ y: neckY + config.height * 0.28, radius: config.radius * 0.34 },
|
||||||
]
|
]
|
||||||
const pouch = latheGeometry(profile, 9, [0, 0, 0], tint('leather', -0.05, 0.9), {
|
// Thirteen sides, not nine. Leather has no facets: at nine the pouch was
|
||||||
|
// a hard-edged lump where the reference is a soft bag, and the body is
|
||||||
|
// the whole silhouette of this model.
|
||||||
|
const pouch = latheGeometry(profile, 13, [0, 0, 0], tint('leather', -0.05, 0.9), {
|
||||||
colourTop: tint('leather', 0.06, 0.9),
|
colourTop: tint('leather', 0.06, 0.9),
|
||||||
capTop: true,
|
capTop: true,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import {
|
||||||
createTinter,
|
createTinter,
|
||||||
jitter,
|
jitter,
|
||||||
mergeColoured,
|
mergeColoured,
|
||||||
|
flipGeometry,
|
||||||
|
prismGeometry,
|
||||||
roughenGeometry,
|
roughenGeometry,
|
||||||
} from '../core/index.ts'
|
} from '../core/index.ts'
|
||||||
|
|
||||||
|
|
@ -61,7 +63,11 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
build: ({ config, random }) => {
|
build: ({ config, random }) => {
|
||||||
const tint = createTinter(random)
|
const tint = createTinter(random)
|
||||||
const half = config.thickness / 2
|
const half = config.thickness / 2
|
||||||
const boardThickness = config.thickness * 0.11
|
// 0.16, not 0.11. At a ninth of the book each way the two boards came
|
||||||
|
// to 14 mm against 48 mm of paper, and the thing read as a ream with
|
||||||
|
// leather stuck to it. A medieval binding is oak boards first, covered
|
||||||
|
// in leather second, and they are substantial.
|
||||||
|
const boardThickness = config.thickness * 0.16
|
||||||
const halfWidth = config.width / 2
|
const halfWidth = config.width / 2
|
||||||
const spineX = -halfWidth
|
const spineX = -halfWidth
|
||||||
|
|
||||||
|
|
@ -111,13 +117,22 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Page block ---------------------------------------------------------
|
// --- Page block ---------------------------------------------------------
|
||||||
// Spills past the cover on three sides (not the spine) with ragged edges.
|
// The BOARDS overhang the pages, not the other way round.
|
||||||
|
//
|
||||||
|
// This was written the wrong way round -- pages at 1.035 of the cover,
|
||||||
|
// spilling past it on three sides -- and it is why the model read as a
|
||||||
|
// ream of paper with a leather lid rather than as a book. The overhang
|
||||||
|
// is called the square and it is the whole point of a board binding:
|
||||||
|
// the boards take the knocks so the leaves do not, which is also what
|
||||||
|
// the corner bosses are protecting. Flush at the spine, inset on the
|
||||||
|
// three free edges.
|
||||||
|
const square = config.width * 0.055
|
||||||
const pages = chamferedBoxGeometry(
|
const pages = chamferedBoxGeometry(
|
||||||
[config.width * 1.035, config.length * 1.03],
|
[config.width - square, config.length - square * 1.1],
|
||||||
[config.width * 1.03, config.length * 1.025],
|
[config.width - square * 1.15, config.length - square * 1.25],
|
||||||
config.thickness - boardThickness * 2.4,
|
config.thickness - boardThickness * 2.4,
|
||||||
config.thickness * 0.02,
|
config.thickness * 0.02,
|
||||||
[config.width * 0.018, 0, 0],
|
[-square / 2, 0, 0],
|
||||||
tint('cloth', 0.09, 0.7),
|
tint('cloth', 0.09, 0.7),
|
||||||
)
|
)
|
||||||
// Vellum is not flat: the waviness at the edge is what makes the block
|
// Vellum is not flat: the waviness at the edge is what makes the block
|
||||||
|
|
@ -149,6 +164,37 @@ export function createModel(overrides: Partial<LeatherBookConfig> = {}) {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Corner bosses ------------------------------------------------------
|
||||||
|
// Brass studs at the four corners of both boards.
|
||||||
|
//
|
||||||
|
// These are the single most recognisable thing about a medieval book and
|
||||||
|
// the model had none. They are not ornament: a book of this weight was
|
||||||
|
// stored FLAT, often on its side, and the bosses hold the leather clear
|
||||||
|
// of the shelf so it does not abrade. Without them the silhouette is a
|
||||||
|
// modern hardback.
|
||||||
|
const bossRadius = config.width * 0.055
|
||||||
|
for (const side of [-1, 1]) {
|
||||||
|
for (const sx of [-1, 1]) {
|
||||||
|
for (const sz of [-1, 1]) {
|
||||||
|
const boss = prismGeometry(
|
||||||
|
bossRadius,
|
||||||
|
bossRadius * 0.55,
|
||||||
|
config.thickness * 0.2,
|
||||||
|
6,
|
||||||
|
[
|
||||||
|
sx * halfWidth * 0.78,
|
||||||
|
side * (half + config.thickness * 0.04),
|
||||||
|
sz * (config.length / 2) * 0.84,
|
||||||
|
],
|
||||||
|
tint('brass', side > 0 ? 0.04 : -0.02, 0.6),
|
||||||
|
)
|
||||||
|
// Domes point away from the book on each face.
|
||||||
|
if (side < 0) flipGeometry(boss)
|
||||||
|
claspPieces.push(boss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cover: { slot: 'leather' as const, geometry: mergeColoured(cover) },
|
cover: { slot: 'leather' as const, geometry: mergeColoured(cover) },
|
||||||
pages: { slot: 'cloth' as const, geometry: mergeColoured([pages]) },
|
pages: { slot: 'cloth' as const, geometry: mergeColoured([pages]) },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue