Commit graph

7 commits

Author SHA1 Message Date
CRT
f136250707 Make the besom spray, and stop cutting its twigs to one length
The head read as a lampshade pushed onto a stick, and two numbers were
responsible.

The spray angle is derived as atan((tip - tie) / span), which at a tip
radius of 0.102 came to five degrees. Five degrees is not a besom; the
reference fans out until the spread at the sweeping end is comparable to
the length of the bundle itself, which is about twenty. The tip radius
carries that, and the slider range moves with it.

The twig lengths varied by three percent, so every twig finished within a
few millimetres of its neighbours and the bundle ended in a straight cut
across the bottom. That single edge is most of what made it look
manufactured: no bundle of cut birch ends level, and the ragged tip is
what identifies a besom on sight. Lengths now spread by about a third --
downwards only, never above the nominal span. Centring the spread on 1.0
first produced a 1.32 m broom from a declared length of 1.2, which the size
guard caught and which was a real inconsistency rather than a tolerance
problem.

Two supporting changes. The bundle ran from the binding down for 36% of the
broom against roughly half in the reference, so it is longer. And each
sheaf was a 31 mm slat, which at thirty-two of them read as a fan of laths;
they are narrower now and there are forty-six, keeping about the same mass
in the bundle with the pieces at the right scale.

One correction to the record: the head was not, as I first estimated by
eye, a fifth of the broom. Measured, it was 46% of the whole and 36% below
the binding. The eye was reading a diagonal reference against a vertical
render.

27 models, 18021 triangles, all checks pass, 0 floating cases.
2026-08-22 13:25:08 +07:00
CRT
ebc5cbec6d Close the basket's weave, fill it, and stop calling willow straw
Three defects, two of them mine.

The weave had gaps you could see the contents through. The band height was
a flat 0.11 of the model height while the spacing between rows is 1/rows --
0.167 at the default six -- leaving a 12 mm hole between every course. It
was a slatted crate, not a weave. The height now derives from the row
count so rows meet at any setting.

The fruit was invisible, and that was a regression I introduced. An earlier
pass fixed produce that hung level with the rim over a gap by resting it on
the base. That was right; what did not follow was that a basket deeper than
its contents then needs enough contents to fill it. Nine apples in two
layers topped out 12 cm below a 10 cm rim -- correctly supported, and
completely out of sight. The basket is shallower, holds fifteen, and the
layers nest at 0.95 of a diameter rather than 1.5, so the heap now mounds
over the rim, which is the only state a fruit basket is ever drawn in.

Closing the weave then exposed two collisions. Overlapping rows meet in
coplanar faces at the nodes where the undulation crosses zero -- on a
cylindrical basket every row shares one radius -- so alternate rows now sit
slightly proud of and behind each other, which is how a weaver's rod really
passes the stakes. And the rim's inner surface sat at 0.16055 against the
liner's 0.16065: a tenth of a millimetre apart, by coincidence, and the
same 22-sided prism. The rim is now the heavy rod it should be and clears
the liner.

Colour: the basket drew from the `straw` palette and rendered at hue 41,
saturation 0.59 against a reference at 29 and 0.50 -- bright yellow
plastic. Willow is a wood, so both the colour and the material slot move to
oak, which measures 7 and 0.03 away instead of 12 and 0.09.

It still does not look like the photograph, and the measurement cannot say
why. Filtering to pixels above 0.18 saturation discards precisely the grey,
weathered pixels that give the reference its character, so the statistic
reports agreement that the eye does not see. Setting the lift to 0.12 to
make willow "paler than oak" turned it salmon -- raising HSL lightness
holds saturation, so a saturated brown climbs towards peach. Sweeping the
lift over 0.00 / 0.04 / 0.08 moved the measurement by 0.01, which is the
clearest evidence that this axis is not where the remaining gap lives.

27 models, 17853 triangles, all checks pass, 0 floating cases, build clean.
2026-08-22 12:08:56 +07:00
CRT
a0659e24ac Enforce "nothing floats", and rebuild the barrel from a reference photo
Two rules were missing, and each one had been quietly failing for a while.

The first is structural. Every check in this repo asked about surfaces --
winding, coplanarity, triangle counts -- and none of them could see a piece
of a model hanging in the air with nothing holding it up. A chest lid
separated from its chest passed everything we had. scripts/support.ts
voxelises the model, finds the connected components of occupied space and
requires each one to reach the floor; scripts/audit.ts runs that across
default, min, max, both sweep ends, actions and the midpoint of a morph, so
a variation cannot break what the default gets right. That audit started at
22 failing cases: the bell and the sign had no supporting structure at all
and now have a frame and a post, the lantern was in four pieces, the sack's
collar floated above its body, the basket's fruit hung level with the rim
instead of resting on the base, and the ladder's rungs were sized by a
formula that disagreed with where the rails actually were. It now reports 0.

The second is that we had no target. The feedback loop was an offline
render of our own output, which can only answer "is this broken", never
"is this right". Given a reference photograph of a cask, five defects were
obvious in seconds that three rounds of self-review had missed: four hoops
where there should be six, no rivets at all, a chime cut so shallow it did
not read, and a stave count low enough to leave a visibly polygonal
silhouette. All four are fixed here.

Two things the rivets taught us, both kept as comments rather than as
scars: a stud that tapers outward tilts its side normals back towards the
axis, which the radial check correctly reports as reversed winding -- a
real rivet head flares, so the honest shape is also the passing one. And
once seated deep enough to look right, the stud's buried inner cap falls
inside the shell the check inspects, so it is not generated at all, exactly
as bandGeometry already declines to build the inside of a hoop.

27 models, 16973 triangles, all checks pass, 0 floating cases.
2026-08-21 19:23:11 +07:00
CRT
50c7fc60b9 Translate the whole repository to English
The kit is going public, so everything a reader sees is now English:
27 model sources, the core vocabulary, meta.ts (titles, descriptions and
every slider label), the viewer UI, all script output, REFERENCE.md and
the READMEs.

Rules applied: only comments, doc comments and human-facing strings were
touched. Identifiers, numbers, logic, registry item ids, part names and
material slot names are unchanged — those are a published contract and
were already English.

Verified rather than assumed: for all 53 changed .ts files the code
skeleton (source with comments stripped and string contents replaced by a
placeholder) is byte-identical before and after. Full gate is green —
typecheck, registry conformance, ~510 model checks, GLB round trip and a
production build.

Also fixed here:
- index.html and viewer.html were missed by the translation pass because
  the file list only covered .ts/.md/.css. Both had lang="tr" and Turkish
  titles.
- The viewer formatted triangle counts with toLocaleString('tr-TR'), which
  prints 15.425 rather than 15,425.
- REFERENCE.md's model table header did not match what
  scripts/catalog-table.ts emits, so the next regeneration would have
  silently changed it. Aligned to the generator.
- Removed scripts/probe.ts and scripts/zdiag.ts; they were throwaway
  diagnostics that got committed by accident.
2026-08-21 14:35:13 +07:00
CRT
72f219d087 Süpürge, çapa ve çiti yeniden kur; kapanma/alaca parametrelerini sınırla
Üçü de render'a bakılarak elden geçirildi. Ortak sebep: her birinde
modelin KONUSU eksikti.

çit — birleşim yoktu. Dört kare çubuk ve önlerine konmuş iki lata;
derinlik/boy oranı 54:1, yani karton. Artık gerçek zıvana var: direk iki
yanak + köprü bloklarından kuruluyor, delik geometrik olarak var oluyor,
kiriş içinden geçip uçlarda karşı yüzden taşıyor. Ayrıca kiriş dağılımı
formülü kaç kiriş olursa olsun hep 0.28–0.78 aralığını dolduruyordu —
üstü ve altı doldurmak yapısal olarak imkânsızdı. 440 → 860 üçgen,
derinlik 0.09 → 0.31 m.

çapa — kaz boynu yoktu. Ağzı sapın ekseninden öne taşıyan kıvrık boyun
olmadan model "kürsü / yol tabelası" diye okunuyordu. Boyun latheGeometry
ile kurulup bükülüyor, ağız boyun ucunun teğetine hizalanıyor; ikisi de
hesapla, gözle değil.

süpürge — demet içi boş bir koni kabuğuydu: bütün levhalar tek halkada.
Üç eşmerkezli halka (6/10/16) kütleyi kuruyor. Bağlar artık demetin dış
yarıçapına oturuyor; eskiden ayrı bir tahmin formülüyle levhaların İÇİNDE
kalıyor ve hiç görünmüyorlardı.

Ölçerek bulunan iki gerçek hata:

- bendGeometry'nin etkisi geometrinin y=0'a göre nerede durduğuna bağlı.
  Orijinde ORTALANMIŞ bir gövde simetrik bükülüyor: iki uç aynı yöne
  gidiyor, siluet değişmiyor. Çapanın ağzında Z aralığı 0.0337'den
  0.0327'ye DÜŞÜYORDU — yani yorumda "sorunu çözüyor" dediğim kavis hiç
  yoktu. Tabanı orijinde kurulunca kaçış 44 mm. Yardımcıya yazıldı.
- Süpürgede açılma işareti tersti: rotateX(+f) levhanın ucunu -Z'ye
  atıyor, rotateY onu EKSENE doğru çeviriyor. Levhalar ekseni geçip karşı
  tarafa savruluyordu; demetin kabuk olmasının asıl sebebi buydu. Gözle
  değil ölçüyle yakalandı (genişlik 0.23 beklerken 0.13).

Sistemik: kapanma yarıçapı ve alaca hücresi modelin en büyük ölçüsünden
türetiliyordu. 4.89 m'lik çitte hücre 0.27 m çıkıyor, yani bütün direk tek
hücreye düşüyor ve doku sistemi hiçbir şey yapmıyordu; kapanma yarıçapı
0.69 m ile her şeyi battaniye gibi karartıyordu. İkisi de mutlak sınırlara
alındı — ahşabın damar lekesi nesnenin boyundan bağımsızdır.

Doğrulama: test yamalarının gerçek config alanlarına işaret ettiği artık
denetleniyor. Çapa yeniden yazılırken `bladeAngle` alanı kalkmıştı ama
test hâlâ onu yamalıyordu, yani o varyant sessizce varsayılan modeli
sınıyordu.

render.ts: --angles ile turntable. Tek bir 3/4 açı yanıltıcı — çit ancak
tam yandan bakınca cılız görünüyor.
2026-08-21 14:05:22 +07:00
CRT
8a982160ac wicker-basket ekle ve dokümanı 27 modele güncelle
Kullanıcının prop listesindeki son madde meyve/sebzeydi; sepetle birlikte
kapatıldı çünkü kitte zaten sepet eksikti.

Örgü, biçimi yapımdan türetiyor: yatay halkalar önce düz bant olarak
üretilip köşeleri açılarına bağlı olarak içeri-dışarı itiliyor
(yarıçap × (1 + genlik·cos(dikeySayısı·açı + faz))), ardışık sıralarda faz
π kaydırılıyor. Dikey çubuk başına iki segment yeterli — dalga tam olarak
her çubukta bir artı bir eksi örnekleniyor.

Halka başına iç yüz üretmek altı sırada ~800 üçgen tutuyor ve modeli
lowpoly bütçesinin dışına çıkarıyordu; yerine 44 üçgenlik tek parça iç
astar var.

Yeni `produce` materyal yuvası (mumsu kabuk, roughness 0.52). Meyve rengi
`hue` alanından geliyor: aynı modelden elma, şalgam ya da lahana sepeti.
2026-08-21 09:50:34 +07:00
CRT
a3300ff233 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
2026-08-21 09:44:58 +07:00