Pitfalls that have already sprung
Every entry here happened once. The symptom was visible every time and the cause every time somewhere other than where one looked first – which is why the collection lives in one place.
A generator has an unpleasant property: it does not fail with an exception but with a picture. Nothing crashes, nothing turns red, it only looks wrong – and often only for one seed in a hundred or in one rotation in twenty. Whoever looks for such bugs mostly looks where they see the symptom, and finds them three steps earlier.
The patterns repeat. A jump in a boundary function is always a hole in the surface built from it. A roll after a visibility test is always a flicker. And everything that hangs off an index instead of an angle jumps at the next rotation.
Signs and directions
Symptom: Every smile is a pout. And so convincingly so that one searches the curve for the error for a long time.
Cause: The y axis of an anchor points UP – it follows latitude towards the crown. The y axis of the canvas points DOWN.
Fix: Every shape function in
gesicht.ts computes in canvas direction and flips the
sign in its own to. Not centrally but in every function
– because each brings its own scale along and the switch belongs
where you need it while reading the curve.
Symptom: The eye rings looked like a second lid: apex at the eye, ends hanging. Unnoticed for a long time because they are pale.
Cause: The arc ran from 1.15π to 1.85π around a centre below the eye – that is the upper half of a circle, a roof. But a ring under the eye follows the lower lid: a bowl, ends pointing up.
Fix: Lower half of the circle (0.12π to 0.88π) around a centre just below the eye. The same pitfall as the pout, only in the angle instead of the sign.
Addendum: The direction was right after that, the distance was not. The bowl started only 0.87 eye radii below the centre and was narrower than the eye – lying free on the cheek it read as a laugh line, and two such arcs on every head as cheeks. Now the ends start at 0.57, level with the lid corners, the middle dips to 0.96 just below the eyeball (which reaches 0.74), and the second arc is the exception instead of the rule.
Symptom: Ears are drawn into the cheek instead of beside it; features appear on the far side that have no business there.
Cause: The surface normal was flipped towards the
camera. Then the far side passes the nz visibility test
too, and the lift along the normal points the wrong
way.
Fix: The normal points outwards from the head's
centre, never towards the viewer. That makes
nz < 0 honestly mean "turned away from the camera".
See Space.
Symptom: A gap yawns between ear and head; the ear floats beside it.
Cause: The ear arc was attached flush to the skin. But the drawn contour is a smoothed silhouette and lies a little inside the point where the ear sits.
Fix: The surface of the ear reaches further into the head than its line does – a seam behind the root.
Symptom: On a turned head the near ear shrinks to a sickle at the edge, and the contour runs straight through it.
Cause: Both ears lay under the head surface. For the far one that is right; the near one travels behind the silhouette as the head turns and then lies in front of the cheek.
Fix: A layer of its own,
zugewandtes-ohr, behind the head surface, and which ear
lands there is said by its normal – not by its side in the picture.
The arc runs over the contour onto the cheek by the inset, with no
line at the root. See Features.
Symptom: When the head turns, the neck travels off to the side and gets narrower doing it.
Cause: It hung off two anchors on the surface. An ellipsoid has nearly the same outline in every rotation – only the points on it run away underneath. So the visible edge of the chin stays almost put, the surface point does not.
Fix: The neck hangs off the outline, where the head really ends in the picture. Width and collar, by contrast, come from the unrotated head: a body does not get narrower when the head turns, and a shirt does not nod along.
Symptom: With a turned head a piece of the near eye is missing.
Cause: The nose was drawn in front of both eyes. It has volume and stands free – it should cover the far eye, but not the near one.
Fix: The order is far eye → nose → near eye; which one is in front is decided by the z depth of the two anchors. The same applies to the beard: it lies under the nose, so it is drawn before it. See The sheet.
Edges and surfaces
Symptom: A ridge all around the skull, in the silhouette the same edge at the same height on both sides – and in every rotation.
Cause: The bump (beule) depended only
on height. A wave that depends only on height multiplies x and z
evenly; that is not a bump but a ring.
Fix: A cos(u) term in the wave. Then
the bump sits at one spot on the surface. See
Head shape.
Symptom: With strong boxiness, gaps tear open in the silhouette, and the anchors no longer behave as expected.
Cause: An exponent on sin/cos
has infinite slope at the equator. The sampling cannot keep up, and
the tangent reference on which every anchor hangs its local system
is distorted.
Fix: Approximate the superellipse as a smooth
radial bump on the diagonals, via sin(2u) and
sin(2v). Never infinitely steep anywhere.
Symptom: A deep, softly running indentation sits at the widest point of the head.
Cause: An empty angular bin in the outline. At the widest point the projected y jumps between neighbouring rings by more than one bin width – a bin is left empty there. The smoothing that follows smears the zero into a dent.
Fix: Empty bins are bridged before smoothing. The order is the entire point. See Point cloud.
Symptom: From a certain rotation onwards a surface of hair lies across the face.
Cause: The outline of the hairdo took its back side along too. With a shell that has a low bottom edge, that hangs down below the middle of the head; if it slips into the lower angular bins, the arc has "mass all around" and closes into a ring.
Fix: UmrissOpt.hinter – a point only
counts if it can be seen. The threshold is at
rz < −0.15 and not at 0: at the silhouette itself
the shell lies around zero, and its outermost point in the bin may
sit a little behind that.
Symptom: at the sides, roughly at ear height, the hair stops abruptly and has a spike pointing outwards – at a place without any special zone.
Cause: the flip side of the trap above. Where the sphere dips under the head contour it is behind the head and no longer counts towards the outline. The last angular bin with visible mass therefore still sits a stretch short of the contour – at a bin width of just under four degrees the outline drops by more than a tenth of a head radius there. The edge broke off next to the cheek, and the chord the fill closes it with became a filled tab.
Fix: laufeAus appends one bin to each
end, one angular step further and just inside the contour. The edge
ends at the head's edge, and the chord lies inside the head again.
Symptom: at some rotations the hair surface lies as a bubble or wedge across the face and juts out past the head at the side. The spikes of the hairline are drawn correctly – only the fill does not keep to them.
Cause: the polygon is the outline forwards and the
hairline back. Which end of the hairline joins which end of the
outline was guessed at the END POINT: does the last stretch of the
outline lie closer to the start or to the end of the hairline? That
assumes the outline ends at the temple. It ends where its angular
bins run out, though – with a flat shell under a hat that is in the
middle of the face. Then the decision compares two meaningless
distances. If it comes out wrong, naht looks for its two
seams at the wrong ends, finds none, and takes the next best pair
instead – half a head apart. rundeZipfel then makes not a
tip out of it but a bubble: it puts its control point three quarters
of the chord outwards.
Fix: do not guess, TRY. Both directions run through
naht, and the one whose seams actually close is taken.
That is the same question, only measured at its answer instead of at a
proxy. Across 53,675 combinations of head and pose the decision comes
out differently 91 times – and in all 91 the gap is smaller. On top of
that the tip gets an upper bound: longer than about two shell
thicknesses it is no tip, and then the straight chord is the more
honest fallback.
Symptom: A thin line runs down from the hairdo across the cheek, with no surface beside it.
Cause: Two sources that miss each other. The hairline ended further out than the outline; the polygon closed across a chord, the fill stopped there, and the drawn hairline ran on beside it. In an earlier version the same symptom came from too few longitudes in the shell cloud – then the narrow lobe at the temple had gaps in the angular bins.
Fix: stutzeAnsatz throws away what
lies beyond the outline, and the shell is sampled with 144
longitudes instead of 56.
Symptom: On a turned head the hairdo hangs down on the far side as a lobe reaching ear height, with an almost horizontal lower edge; the head contour runs visibly through it. Conspicuous under a hat, where the shell is thin.
Cause: The outer edge is a radial outline around the head centre: per angular bin the farthest visible point of the shell. When the mass hangs low on the far side, the bins pointing diagonally down look right through the mass, and the farthest point there is the hairline itself – the flank of a spike. The edge bends inward at the temple and runs along the spike; the seam cuts at the latest close spot and keeps exactly this inward run.
Fix: stutzeAussen trims the outer edge
from both ends by everything that is close to the hairline AND
clearly inside the head contour – “close” meaning one shell
thickness, since the inward run is the inflated flank, not the skin. Real silhouette sits on the skin
plus thickness, i.e. outside the contour – the hedgehog's tongue
survives too.
Symptom: A narrow wedge falls out of the hairdo and crosses its outer edge.
Cause: The clamp of the hairline jumped in steps, and by more than the spacing of two sample points. Between the two points the boundary line plunged.
Fix: Smooth instead of stepped
(t·t·(3−2t)). This is the general case:
a jump in a boundary function is always a hole in the surface
built from it.
Symptom A: At the lower edge of the hairdo a horizontal wedge sticks out of the head at the side. Symptom B: The hairdo is flat at the sides and sticks to the skull.
Cause: Two mistakes close together. If the shell thickness does not run out at all, it stands at full thickness along the lower edge and becomes visible radially outwards (A). If it runs out over the full height, nothing is left on top (B).
Fix: Only the last stretch above the hairline gets thinner; the rest stands at full thickness, at the temple too.
Symptom: The hairdo ends at the temple with a straight horizontal cut, or its tip hooks back into the face.
Cause: Outline and hairline come from different sources and do not stop at the same point. Whoever cuts the join at the narrowest point hits some arbitrary place on the narrow tongue and lops off its tip – the two edges lie close together along the whole stretch there.
Fix: Cut at the latest narrow place, on
both sides. And do not close the remainder with a chord but with an
arc that continues the direction of the outer edge
(rundeZipfel). See Hair and
hat.
Symptom: Curls look like beads on a string – or like a saw.
Cause: Beads come about when bales are laid on a smooth edge: the edge runs through underneath, and the eye reads a line-circle pattern. The saw comes about when the bulges are sine arcs – those run out flat at both ends and meet their neighbour in a point.
Fix: The edge itself becomes a sequence of coils, and the bulge is a semicircle: it stands vertical at its ends, and every coil becomes a round bulge with a notch beside it.
Symptom: With a small notch the top edge of the heart on the mouth was not a round arc but a row of three humps.
Cause: Peaks and flanks sat as fixed points in the list, and only the midpoint hung off the slider. With a small notch the middle stood higher than its own flanks.
Fix: Do not assemble a shape that a slider changes out of peaks and valleys, but compute it as one base form plus one disturbance: here an arc and a bell that cuts into it. See Features.
Symptom: The paper grain is missing on one of the two pictures – or it is there, but at the wrong resolution.
Cause: The grain tile is drawn once and filled as a pattern afterwards; it was cached by device ratio alone. Ever since the workshop draws the same sheet onto a SECOND canvas in order to save it, that is not enough: a pattern belongs to the surface it was created on.
Fix: The surface belongs in the key. Two lines, and the pitfall is closed.
Symptom: The tint of the lens sat visibly beside its ring: a band of colour above the rim at the top, a pale seam between colour and frame at the bottom. On square glasses it looked like a second lens glued on askew.
Cause: The misregistration is a FIXED amount in head space – barely a fiftieth of the head's width. On the skin, which fills the whole head, that is a breath. A lens is a quarter of that wide, and the same amount is a sixteenth of its width there: the offset does not grow with the surface, so it shows up on small ones.
Fix: The tint is printed dry, like the neck
against the chin and the band against the crown – the exception is
for surfaces that have to meet something. The hand's wobble along the
edge stays (spur and wackel), so the edge is
still drawn and not a vector line; it just stays inside its ring. The
same arithmetic applies to every small colour surface: do not switch
off the press, ask how large the offset is relative to THIS surface.
Symptom: the full beard's edge was crooked – a notch at the cheek, a spur at the neck, and turning one away produced the other.
Cause: the radial outline takes the farthest cloud point per angular bin around the head centre. For hair every ray meets the edge once. A beard is a narrow band around the jaw: at the cheeks the rays graze it tangentially and bins are left empty; at the chin several latitudes pile into one bin. The four repairs at the ends then leave a spur at every corner.
Fix: do not measure at all. A thin coat has the skull's silhouette, offset by its thickness – the head contour between the two corners pushed outward radially, the beard line running back along the skin. Both end in the same points. The general rule: a measuring method has a range of validity, and using it outside that range means repairing forever after.
Symptom: the teeth along the beard's edge were computed, rolled and measurable in the profile – what you saw was an egg with a straight cut across its lower left.
Cause: curvature. The same construction sits on an almost straight forehead at the hairline, and on an arc that turns some thirty degrees per tooth at the beard. A triangle filling its cell rises more gently than that – the curvature eats the point and the straight flank is what remains. On top of that the Catmull stroke rounds away the rest.
Solution: on a curved edge the point must rise more
steeply than the edge turns: the same depth across a quarter of the
cell, the rest of the cell staying the round contour, and drawn
eckig. The general rule: a shape that works on a
straight edge is not the same shape on a curved one.
Symptom: the light strands on the beard's mass all converged on a single point below the chin.
Cause: a strand runs along its meridian, and meridians converge at the pole. For hair that is right – hair really does converge at the crown. At the lower pole the same computation is wrong.
Fix: the strand moves outward by
cos v₀ / cos v, exactly the factor by which its latitude
narrows, and stops short of the pole.
Measures and sizes
Symptom: Eyes two percent of the head width.
Cause: The zone height was taken directly as the size. But the eye zone is flat – between brow and bridge of the nose there is little room – and its height is not the size of the eye but the limit it must not bump into.
Fix: A desired measure from the face scale, capped by the zone, with a lower bound. The zone is the ceiling, not the specification. See Zones.
Symptom: A sheet full of babies.
Cause: Small features in a large head are the baby schema. The first version tied eye size hard to the zone height; a crowded face got pinheads.
Fix: Lower bounds for eye, nose and mouth. And the same thought one level up: without enough span in the head shape all heads are eggs – and eggs are babies.
Symptom: Features shrink when the head turns, zones sitting low become a line.
Cause: The zone size was measured in pixels and
then handed to f.to() – which squashes lx with fx and
ly with fy once more.
Fix: platz() computes both axes
foreshortened back before they go out as a measure.
Symptom: On every second head the laughing mouth stood outside the silhouette – past the cheek at the sides, past the chin below.
Cause: Two mistakes on top of each other. Every feature is drawn in the tangent plane of its anchor; that is right as long as it is small. A mouth running across almost the whole face is not: drawn flat it keeps running straight while the surface below it tips away. And its limit was the mouth zone – space on the sphere, which knows nothing about the silhouette in the image.
Fix: Draw it on the sphere
(kugelFlaeche: every point gets its own field) and
measure it against the outline
(lachRaum). Of 1600 images, 608 crossed the contour
before, five afterwards.
Symptom: The mouth fitted head-on but stuck out of the turned head – and measuring it per image, it grew and shrank while the head followed the pointer.
Cause: Measured against the outline, the size hangs on the pose, because the outline turns along. The size of a feature never may.
Fix: Once per head, at the corners of the pose space, the tightest one wins. What then no longer fits becomes flatter rather than narrower – the width is the feature.
Symptom: After the mouth zone had grown, the open mouth was no longer a round O but a wide ellipse.
Cause: The ellipse computes in mouth widths. A hole of 0.3 mouth widths grows with every mouth width – as long as that was tightly capped, nobody noticed.
Fix: A cap of its own for this mouth, set at the mouth width and not at the ellipse. Whoever computes a shape as a share of another measure inherits every change to that measure.
Symptom: Once the mouth was allowed to run further, the chin stubble was suddenly much larger.
Cause: The beard was handed the mouth width as its measure – sensible as long as that hung on the scale of the face alone. With the per-head mouth width it suddenly hung on something that has nothing to do with the beard.
Fix: A beard measure of its own: the mouth as it stands at rest in the face. A shared measure is a coupling – it only shows once one of the two moves.
Symptom: With a thick hairdo the hair stood above the crown, and the hat hung beside it.
Cause: The hat measured the bare skull, the hairdo was drawn as its own surface underneath.
Fix: First a padding (haarPolster:
measure skull plus hair) – over the afro that made it a lid on a
sphere. Now the hat is a body in the depth buffer, shrunk onto the
skull, and the hair is stuffed into the crown as under the
beanie. Related: the hat band sat on the foot of the crown, exactly
under where the brim attaches, and read as a shadow under the hat.
It now sits higher up the crown.
Symptom: Hats that are either mushrooms or disappear between the ears.
Cause: Crown height and brim width were rolled separately. A tall crown with a wide brim is a mushroom, a flat crown with a scant brim is invisible – and uniformly distributed values all land in the middle anyway.
Fix: Do not roll the axes but the kind: fedora, trilby, sun hat, top hat, bucket. The same thought carries the afro kinds and the two size classes of the curls.
Symptom: On a long skull the beanie sits far up, narrow, with a wavy edge.
Cause: It hung on a latitude like a shell – and the same latitude lies on a long egg where the head is already narrow. A garment does not inherit the head shape.
Fix: A surface of revolution from a profile in height and radius, shrunk onto the skull – onto the skull, not onto skull plus hair, or it becomes a tent over the afro. See The beanie is a body.
Symptom: The afro lies as a bonnet over the beanie's crown; the beanie is only its cuff any more.
Cause: The hair was allowed to gain in height what it lost in width, and rose up in front of the crown. And a band of fixed height under the edge turned the hairdo into a horizontal step the radial outline cannot see.
Fix: Width decides, height is not added; under the edge a cone instead of a band – it has no step. Steep and at the skull at the front and sides, shallow and midway between skull and edge at the back: otherwise a step stands beside the beanie's corners when looking up. Lesson: with "front" and "back", first check which points draw the edge.
Symptom: The beanie's cuff edge is missing in stretches although nothing lies in front of it.
Cause: The depth buffer tested lines on the surface with the tolerance meant for points behind it – and at the edge the crown stands immediately in front.
Fix: A separate, wide tolerance (0.06) for strokes on the surface. What really covers them – the far half – lies a whole head diameter behind, there is plenty of room.
Symptom: A hairdo runs into the neighbouring cell – or, after the obvious remedy, every head stands at a different size.
Cause: A hairdo with a shape of its own (the afro) can be wider than the head is tall. Whoever does not know the space requirement has only bad options.
Fix: The style declares what it needs
(Raumbedarf); if that is not enough, it is not that one
head that gets smaller but the whole sheet. Nine scales
look like a fault, a slightly smaller sheet looks like intent.
Symptom: The moustache sat right over a straight line, too low over a smile, inside the open mouth.
Cause: The beard knew one number about the mouth –
"0.18 mouth heights above the anchor" – and the mouth was a
switch of strokes, not a shape one could read from.
Fix: mundForm: the mouth is data first
(top edge, bottom edge, outline, corners) and drawing second. Beard
and stubble read from it. See
Features, beards.
Symptom: With little room between nose and mouth the walrus ran as a bar down below the neck.
Cause: A fraction was divided by "beard width minus corner distance". With a small b the corners lie further out than the beard reaches: the denominator turns negative, the fraction large with the wrong sign.
Fix: Denominator with a floor, fraction clamped, the bottom edge tied to the mouth width instead of b.
Symptom: The collar is a flat disc below the chin with a stalk poking through its middle.
Cause: Its ring took its measure from the head instead of the neck – three times too wide. A collar is not a disc but a tube: it is not the width that makes it, but the height by which the neck disappears into it.
Fix: A ring just over neck width; the width comes from what hangs on it. And the roll of the knitting belongs at the top; in the middle of the band's height it is a life ring. See Features, collars.
Symptom: A tall knitted collar makes the head long-legged: first a neck at full length, then a collar below it.
Cause: The collar hung at the BOTTOM of the neck and kept growing downwards. A roll neck takes the neck up, though; it does not hang from it.
Fix: The lower edge is fixed, the band grows upwards and eats into the neck – all but a remainder below the chin.
Symptom: A darker shadow sticks out below the finished collar, coming from nowhere.
Cause: Under every part lies one area that keeps paper from flashing between them – band, leaves and back each wobble on their own and shift with the misregistration. If that ground reaches deeper than what lies in front of it, it peeks out at the bottom.
Fix: Its lower edge follows the shape instead of being flat: on the shirt deep in the middle, shallow at the sides.
Symptom: A canvas whose size JavaScript derives
from the surrounding box grows a little with every measurement – or
the ResizeObserver fires forever.
Cause: The element sits in the flow and therefore helps determine the very box it derives its size from. A loop, and the observer turns it.
Fix: Whatever gets measured does not measure along.
The workshop's sheet sits absolute inside its holder;
the holder is sized by the scaffold, the sheet by the computation.
Randomness and streams
Symptom: After a harmless change all the faces are different people.
Cause: A new field was inserted in the
middle of the draw order of macheDna. From that
place on every following draw gets a different number.
Fix: Always append new fields at the end. Where
that is not possible, fork a stream of your own
(strom(seed, 'layout')). The same rule applies one
level down for the scatter in the style: new values behind the
existing draws. See Randomness.
Symptom: At every blink the whole face changes its line work.
Cause: The warp came from a running random stream. A single skipped stroke – a closed eye draws fewer lines – shifts all the following draws.
Fix: The warp hangs off a trace, that is off a name. The same name plus the same seed gives the same tremor in every frame, independently of what was drawn before. See The pen.
Symptom: At every small rotation all the curls in the afro change size.
Cause: The rolls fell after the visibility test. A curl that is just turning away then drags the whole stream behind it.
Fix: All the rolls first, then check what is visible. In general: no draw may depend on a condition that changes per frame.
Symptom: Spikes, fringes and curls jump one position further with every breath.
Cause: They hung off indices of the outer edge. The edge is a sampling of the silhouette and travels by one point with every small rotation.
Fix: Hang them off fixed angles around the
head's centre (randZuWinkeln). Then the trimmings stand
still and only glide with the silhouette. The same applies to the
roughening of the afro edge.
Symptom: The sheet fidgets.
Cause: Two variants of the same mistake. If every colour surface rolls its misregistration individually, each slips somewhere else – that is not printing, that is a loose contact. And if the paper grain is rolled anew per frame it is no longer paper but noise (apart from the fact that a few thousand dots per frame would cost more than all the rest).
Fix: The register hangs off the seed, that is off the head – one direction for the whole face. The grain is drawn once into a tile and after that filled as a pattern.
Symptom: The workshop re-rolls the eye shape – and the new star has exactly the same spikes as the old one. The new hairdo has the same hairline, the same fall, the same fullness.
Cause: The choice of feature lives in the DNA, but
its EXECUTION lives in the style: spikes, curls, star shape and
collar ribs hang off strom(dna.seed, …). The seed does
not change when rolling, so the handwriting does not change with it.
Fix: The DNA may say which stream the details of a
feature come from (dna.stil, see
styles/klar/hand.ts). Without an entry it is the seed,
as before – which is why no head from the sheet changes and the
print check stays the same. The handwriting block itself is NOT
re-hung: its sequence of draws is a contract. Whatever was rolled is
drawn once more BEHIND the block.
Symptom: After a roll on the hairdo a spiky cut sits under a cap – a combination that appears on no sheet.
Cause: nichtMit is directional. The
cap drops out of the table when the hair is a mass; the other way
round nothing is written, because the hair is drawn first. While a
DNA is being built that is correct – when a single feature is
re-rolled, everything around it has already been drawn.
Fix: sperreFuer reads the same rule
twice, forwards and backwards, and names the category responsible.
See Zones.
Movement
Symptom: The pupils tremble.
Cause: The dot boiled along with the beat. On a line that reads as a pen, on a dot as a tremor – a pupil sitting somewhere else at every beat is not a hand drawing but a mistake.
Fix: punkt() never boils; its warp
hangs off the seed only. The same applies to small pale secondary
lines (ruhig): eye rings and hatching that boil along
read as a flicker of the picture.
Symptom: Short strokes – mouth, brow – become visibly longer and shorter from frame to frame.
Cause: The even sampling hit the end point only up to rounding. Whether the last step just fits or just does not tips with every tiny change in length.
Fix: The end point always belongs. Related: the warp scales with the stroke length, and short strokes barely boil – the same amount is a meander on a long contour and a jump of the whole line on a short brow.
Symptom: Nine heads move like a comb, and their lines all set down anew at the same moment.
Cause: The same spring stiffness for everyone, and a beat coming from a shared clock with no offset.
Fix: Every head gets its own stiffness, its own
breath phase and its own taktVersatz – all three from
the seed. Looking around without a pointer also runs on two sines
with non-round periods, or the whole row nods in time.
Symptom: The lenses look painted on instead of standing in front.
Cause: They were drawn through the anchor and thus hugged the curvature – they foreshortened like skin.
Fix: The glasses are a figure in head space: two circles in the frontal plane, a bridge, two temples to the ear, rotated and projected like the skull itself. A turned head then foreshortens a lens only by the cosine of the rotation – and that is exactly what a lens does. See Space.
Pitfalls no picture shows
All the pitfalls so far have a symptom: you can see them on the head. The four here have none. They build without errors, they throw nothing, the console stays quiet – and still something is wrong. That is why each of them now has a guard behind it instead of a comment.
Symptom: The same seed shows a different head in the docs than on the sheet – different eye sizes, a different star in the eye. Not a bug, just a difference.
Cause: The step-by-step board carried the drawing order as a reconstruction, complete with re-enacted random draws. When the core was moved from the hex fork to named streams, the reconstruction went on drawing from the old one. The comment above it said "has to be maintained along with it" – that is not a mechanism, that is a hope.
Fix: The board asks the style for its strokes instead of rebuilding them. What a demo wants to show it has to be able to fetch; if it cannot, an export is missing. See Order.
Symptom: The brand above the sheet stands there as a miniature, without its black boxes. The compiler is happy, the console empty.
Cause: A renaming pass had translated identifiers
and caught string literals on the way: font-size became
font-mass, width="…" became
breite="…". An SVG passes over an attribute it does not
know without comment – it does not complain, it just draws
differently.
Fix: check-vokabular.mjs knows a list
of forms that can only exist as damage: a CSS or SVG property with a
German half.
Symptom: None. That is exactly the pitfall.
Cause: In the stylesheet, in the comment above the
frame loop and in these docs it said consistently that the only role
going to the canvas was --marke-canvas. The app had
long been reading --flaeche too. Nobody noticed,
because nothing breaks at that border:
getPropertyValue on a name that does not exist returns
an empty string.
Fix: The bridge is a list of names in
check-rollen.mjs. See
the second border.
Symptom: /docs shows the sheet instead
of these docs – with status 200, no redirect, no message.
Cause: Without a trailing slash /docs
is not a folder to the development server but an unknown path, and
an unknown path gets the application. A 404 would have been a hint;
a 200 with the wrong page is not.
Fix: A 301 to /docs/, in the
development and preview servers alike – a difference between the two
would be the same pitfall all over again.
What follows from this
Most of these mistakes were not errors of thought but errors of order: smooth first, then fill gaps; check first, then roll; measure first, then squash. In a generator the order is part of the correctness, and it stands in no signature.
That is why many places in the code carry a comment that does not say what happens there but what happens if you do it differently. Anybody who has read this collection knows why.
And where a comment is not enough, there stands a guard. The difference is not a subtlety: a comment is read when somebody looks in the right place, a guard speaks up by itself. The four pitfalls above have that in common – all four were written down as agreements, and all four happened anyway.