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

The pout

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.

The roof under the eye

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.

The inverted cheek

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.

The ear as a fallen-off handle

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.

The bitten ear

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.

The neck beside the chin

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.

The nose erases the near eye

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

The squeeze

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.

The exponent on sin and cos

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.

The dent in the cheek

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.

The flap across the face

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.

The spike at the bottom of the afro

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.

The hairdo as a bubble beside the head

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.

The thread at the temple

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.

The lobe on the far side

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.

The hole in the fill

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.

The horizontal wedge – and the wet hair

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.

The truncated tongue and the cut at eye level

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.

The string of beads and the saw

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.

Three waves instead of two arcs

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.

The pattern from the wrong surface

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.

The colour plate beside the frame

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.

The staircase along the beard's edge

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.

The beard cut on a slant

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.

The sliced melon

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

The zone as the measure

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.

Small features in a large head

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.

Squashed twice

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.

The mouth that ran off the face

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.

The breathing mouth

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.

The astonishment that turned into a yawn

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.

The beard that grew along

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.

The hat in mid-air

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.

The mushroom and the vanished brim

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.

The beanie as a plate with a frill

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.

The bonnet over the crown

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.

The edge that vanishes under its own beanie

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.

One sheet at nine scales

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.

The moustache guesses the mouth

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.

The walrus grows out past the chin

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.

The lampshade

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.

The stacked neck

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.

The second collar under the collar

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.

The box that measures itself

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

The shifted DNA

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.

The flickering face

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.

The flickering pattern

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.

The jumping trimmings

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.

The loose contact and the television static

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.

The half throw

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.

The condition that only looks backwards

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

The boiling dot

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.

The trembling of short lines

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.

The comb and the pot

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.

The painted-on glasses

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.

The copy that drifts apart

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.

The translated attribute

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.

The bridge that was two

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.

The path that serves the wrong page

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.