Kit'i 26 modele çıkar, doğrulamayı ve inceleyiciyi genişlet

Modeller (13 → 26): chest, bench, torch, lantern, bell, sign, hay bale,
sack, broom, tankard, book, phial, coin pouch. Kürek, çapa ve yaba
render'lara bakılarak yeniden yazıldı.

core:
- createKitModel artık tipli `actions` ve `update(dt)` taşıyor
- BuiltPart.extras: bir parça birden çok materyal yuvası kullanabiliyor
  (sandığın kapağı = meşe tahta + demir kayış, birlikte dönmek zorunda)
- BuiltPart.origin: parça başına dönme merkezi (menteşe, sarkaç)
- bendGeometry / roughenGeometry / mottleGeometry
- 5 yeni materyal yuvası: steel, brass, straw, cloth, leather, glass
- bandGeometry({ inner }) — serbest halkalar kapalı katı olabilsin

my-registry/meta.ts: katalog metadata'sı artık build.ts ve viewer için
tek kaynak. Doğrulama modelle metadata'nın uyuştuğunu denetliyor ve bu
eklendiği gün dört modelde gerçek bir sapma yakaladı.

Doğrulama (~500 kontrol):
- metadata uyumu, eylem semantiği, kare hızı bağımsızlığı
- scripts/render.ts: tarayıcısız yazılım rasterleyici. Bütün doğrulama
  geometrikti; "bu kürek küreğe benzemiyor" diyebilmek için modele
  bakmak gerekiyordu
- scripts/verify-glb.ts: dışa aktar → geri oku → karşılaştır

GLB dışa aktarımı: viewer düğmesi ve toplu CLI aynı kodu kullanıyor.

Viewer:
- parça paneli (solo/izole) ve materyal yuvası paneli (canlı renk override)
- kit görünümü: 26 model tek sahnede, ölçek ve ton tutarlılığı için
- configure() sonrası gölge bayraklarının düşmesi düzeltildi
This commit is contained in:
CRTkafa 2026-08-21 09:44:58 +07:00
parent 98cfbab180
commit a3300ff233
85 changed files with 14473 additions and 1915 deletions

View file

@ -0,0 +1,98 @@
/**
* @medieval-kit/wooden-ladder
*
* İki dikme, aralarında basamaklar. Kitin en ucuz modeli ve sahne değeri en
* yüksek olanlardan biri: bir sahneye dikey hareket önerir.
*
* Basamaklar dikmelerin İÇİNE giriyor (geçme), yani hiçbir yüzey dikmelerin
* yüzeyiyle aynı düzleme oturmuyor.
*/
import { Color } from 'three'
import {
chamferedBoxGeometry,
createKitModel,
jitter,
MEDIEVAL_PALETTE,
mergeColoured,
} from '../core/index.ts'
export interface WoodenLadderConfig {
readonly height: number
/** Dikmeler arası mesafe (metre). */
readonly width: number
readonly rungCount: number
/** Dikmelerin üste doğru incelmesi. 0 = paralel. */
readonly taper: number
readonly seed: number
}
export const woodenLadderDefaults: WoodenLadderConfig = {
height: 2.2,
width: 0.42,
rungCount: 8,
taper: 0.18,
seed: 4,
}
export type WoodenLadderParts = 'rails' | 'rungs'
export function createModel(overrides: Partial<WoodenLadderConfig> = {}) {
return createKitModel<WoodenLadderConfig, 'oak', WoodenLadderParts>({
id: 'wooden-ladder',
defaults: woodenLadderDefaults,
slots: ['oak'],
build: ({ config, random }) => {
const tint = new Color()
const shade = (lift = 0): Color => {
tint.copy(MEDIEVAL_PALETTE.oak)
tint.offsetHSL(jitter(random, 0.012), jitter(random, 0.05), lift + jitter(random, 0.055))
return tint
}
const railThickness = config.width * 0.1
const half = config.width / 2
// Dikmeler üste doğru birbirine yaklaşır; bu tek detay merdiveni
// "iki tahta" olmaktan çıkarıp merdiven yapıyor.
const lean = half * config.taper
const rails = [-1, 1].map((side) => {
const rail = chamferedBoxGeometry(
[railThickness, railThickness * 1.35],
[railThickness * 0.85, railThickness * 1.15],
config.height,
railThickness * 0.16,
[0, 0, 0],
shade(),
)
// Z ekseni etrafında hafif eğ: alt uç dışta, üst uç içte.
rail.rotateZ((side * -lean) / config.height)
rail.translate(side * half, 0, 0)
return rail
})
const rungs = []
const count = Math.max(2, config.rungCount)
for (let i = 0; i < count; i += 1) {
const t = (i + 0.5) / count
const y = -config.height / 2 + t * config.height
// Basamak, o yükseklikteki dikme aralığından biraz UZUN: uçları
// dikmelerin içinde kalsın.
const span = (half - lean * t) * 2 + railThickness * 0.9
rungs.push(chamferedBoxGeometry(
[span, railThickness * 1.05],
[span, railThickness * 1.05],
railThickness * 0.8,
railThickness * 0.16,
[0, y, 0],
shade(0.03),
))
}
return {
rails: { slot: 'oak', geometry: mergeColoured(rails) },
rungs: { slot: 'oak', geometry: mergeColoured(rungs) },
}
},
}, overrides)
}