You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wet strokes on a web page.--export-web now carries a stroke under .wet or .oil: the page draws the canvas once more without such strokes, as the Mac does, and each one drags that ground along its path, oil lighting its own ridges, within a tenth of a level of the Mac. A wet stroke over a canvas that keeps its paint (noClear) still stops the export by name. Web page
Particles that read a picture.stepParticles(_:custom:textures:) hands a particle step up to four pictures, read in the snippet as picture(index, point) at a canvas point, so particles can steer by a word, a shape, or a blur the sketch draws. A kernel of your own reads up to eight through compute(_:buffers:textures:count:params:), bound at texture 0 onward with a smooth sampler at sampler 0. Every picture reads as linear light, a file decoded from sRGB. A kernel that reads a layer reads it as drawn that frame: it runs after the layers are drawn, and so does every dispatch recorded after it, and an export renders every frame before the one it keeps so each step reads its own frame's picture. The Compute/SteeredByAPicture example traces a word in a quarter of a million particles. Compute
Hatching that fits each shape.Hatching(centersLines: true) spaces each shape's lines across its own extent, the whole number of them nearest its height over spacing, with half a step at each side, so a grid of equal cells hatched one by one gets the same lines in every cell. Without it every fill hatches on one lattice shared across the canvas, which lines neighbors up but gives equal cells a line more or less by where they sit. The SVG exporter honors it too. Export
Wipes in any order.Combine.wipe(_:progress:feather:) turns one layer into another along a WipeOrder as progress runs from 0 to 1, and Filter.wipe(_:progress:feather:) brings one layer in over whatever is behind it. An order is a straight edge (.directional(angle:)), a growing circle (.radial(center:)), a clock hand (.angular(center:angle:)), blocks (.cells(columns:rows:)), or a dissolve (.noise(size:seed:)), reshaped by .folded(), .tiled(_:), .bands(_:), .shuffled(seed:), .checker(), .diamond(), and .reversed(). The front is soft, and the two ends are each layer exactly. In compose { } it is .wiped(to:_:progress:feather:). Both cross to a web page. Effects
Copies of a layer.Filter.repeated(_:count:scale:rotation:opacity:hueShift:jitter:seed:) lays a layer out again in a grid, around a ring (each copy turned to face out with facesOut), or along a line, each copy a step smaller, more turned, fainter, and further around the hue wheel than the one before. It crosses to a web page. Effects
A glowing edge.Filter.edgeGlow(width:colors:spots:spotSize:pulse:bloom:center:phase:) lays a band of light along a layer's edge with spots of each color racing around the shape, added color by color and laid over the layer as light. It crosses to a web page with the other layer styles. Layer styles
Any 3D field as blocks.SDF3D.voxelized(size:gap:jitter:seams:occlusion:seed:) rebuilds a raymarched field out of cubes on a grid, each block colored by the field at its center, with flat faces, seams, crease shading, and a seeded tone per block, so a melt becomes a voxel model and a slab one block thick becomes pixel art. A block field costs about three times the field it is built from. It crosses to a web page. SDF combinators
Dóra Maurer's folder grows to four.Examples/Recreations/DoraMaurer adds two works. FiveOutOfFour, after 5 out of 4 (1975 and 1979) and 4 out of 3 (1976): frames side by side, cut into one panel more than there are frames, every panel the same width, so the seams move along the panels a step at a time; the frames stand whole, the cuts run down, and the panels part and hang, in the 1979 crimson and blue, the 1975 stripes turned 45 degrees a field, or the 1976 wood, from 2 out of 1 to 7 out of 6. Overlappings, after the shaped canvases of 2007 to 2012: congruent sheets on one bent surface (a CoonsPatch), each the one below it shifted and turned by the same step, every overlap the paint mix of the sheets over it so the colors read as layers of film, in three works, two sheets along one S, two turned ones, and five squares on a swelling. Both export SVG that gives the rules back.
Jesús Rafael Soto joins the recreations.Examples/Recreations/JesusRafaelSoto is new, after the Venezuelan artist (1923 to 2005) whose wires and rods, hung a hand's width in front of fine black and white stripes, flicker and come apart as you walk past them, and whose Penetrables are rooms of hanging tubes you walk into. Vibracion gives the pointer the viewer's place: every wire lands on the stripes by its parallax, near ones sliding farther than far ones over shadows that stay put, in the 1961 Vibration, Vibration jaune (1965), or Grande écriture (1972), and the 1961 row of pendulum wires beats against the stripes, the beat moving about twenty-five times as far as the wires. Penetrable builds The Houston Penetrable at the record's measurements, 24,000 tubes one every ten centimeters, each painted yellow where it passes through a floating orb, and walks a visitor through it, the tubes parting at the hip and swinging back from the frame; seen through the visitor's eyes or from the gallery. Both export SVG that gives the rules back.
Shapes filled as what they are made of.fillMedium(_:) shades a fill from its distance to its own edge. .impasto is thick paint that rises along the outline and levels off, swells inside, and catches the light from the upper left, in two colors worked together; .knife lays it in flat passes that meet in straight ridges. .wash glazes what is drawn under it (each channel the darker of the ground and the pigment, so it never lightens it) and .gouache covers it, both dragging the ground along a drifting flow. .chrome reflects a studio and the drawing around its rim, .glass shows the drawing straight through its middle and bent at its rim, and .facetedGlass breaks it into facets. .rock, .marble, and .sand are creased stone, veined stone, and grains thinning out at the edge. It applies to drawShape, drawPolygon, and the circle, rect, and other shapes with a simple outline; the textures move with the shape under translate and rotate. A vector export writes the fill flat, and the web page export stops at it by name. noFillMedium() returns to a flat fill. Marks
Palettes built around one hue.Palette.scheme(_:key:count:jitter:seed:) reads a key color's hue and builds .monochrome (that hue from its most vivid point through deep to light), .vividAndDark (a wheel vivid near the key and dark across it), .vivid (the whole wheel vivid, each hue at the lightness where its color word is most typical), and .pastel and .dark clusters around the key, with a seeded jitter. Color.mostVivid(hue:) is a hue's most vivid displayable color. Color
A sketch is the whole app on a phone or a tablet.@main on a sketch now starts an app on iOS as it opens a window on the Mac: Sketch.main() and OllinApp.run(_:) exist there, with the canvas filling the screen and the sketch's @Params in a panel beside it on an iPad or a Mac and a sheet on an iPhone. A development build shows a small button that opens them and Command-/ opens them in any build; a release build never shows the button. A declared checkpoint is kept, and an installation keeps the screen awake. ollin new --kind ios-app writes the sketch with its @main and a one-line Bundle+Module.swift in place of a host App, and ollin phone now takes a sketch marked @main, as every sketch written for the Mac is, which it could not build before. The sketch on the phone
Stroke media on a web page.--export-web now carries a stroke under a dry medium (.pencil, .charcoal, .pastel, .dry, .bristles, .dryBrush): it crosses as its points and the page shades it with the medium's own functions, one coat where it crosses itself, within a fraction of a level of the Mac. .wet and .oil still stop the export by name. Web page
A worn videotape..vhs(smear:jitter:damage:amount:phase:) plays a layer off a worn tape: each line jitters sideways, a wobble and a rolling crease come in bursts, the bottom lines tear where the heads switch, and the color is split into luma and chroma so the chroma trails behind edges the luma keeps sharp. Feed phase your time; amount 0 is the layer untouched. Effects
A JPEG at a quality, without a file..jpeg(quality:subsamplesChroma:) runs the format's own 8 by 8 block transform with the standard's quantization tables at the quality curve image editors use, the color at half resolution as most files store it: flat tiles with ringing toward 10, the color one tint a 16-pixel macroblock. With subsamplesChroma: false the color keeps full resolution and quality 100 comes back within a level. The layer's alpha is kept. Effects
Tilt-shift and a progressive blur..tiltShift(focus:angle:band:falloff:radius:) keeps a band sharp around a line, untouched byte for byte, and blurs away from it so a view reads as a model; .progressiveBlur(angle:start:end:radius:) fades a blur in across the layer, the same as .gaussianBlur(radius:) where it is full. Effects
A light leak..lightLeak(anchor:spread:streaks:colors:flicker:intensity:phase:seed:) fogs a layer with light from a point on its edge, a hot bloom, a shoulder, and streaks along the beam through a three-color ramp, screened as emitted light: it never darkens a pixel and raises the alpha over transparency. Effects
A page peeling..pagePeel(amount:corner:radius:shading:sheen:shadow:back:) curls a layer up from a corner around a cylinder, its back and its flipped flap showing, with shadows on the sheet and on the ground it lifted off, which is transparent so what is drawn under it shows through. Effects
Hairline scratches.Generator.scratches(count:thickness:length:angle:wobble:flicker:color:phase:seed:) draws the scratches of a worn print over nothing, each line holding its place for a few dozen frames and flickering at 24 frames a second, to composite over a picture. Effects
Datamosh.Sim.datamosh(amount:blockSize:motion:drift:wander:period:seed:) is a field whose blocks refresh from the drawing or hold, a held block dragging its last contents along the drawing's measured motion, a fixed drift, and a slow wander of its own, each block re-rolling its fate on a clock of its own. The Effects/TapeAndLens example runs all eight looks. Every one but the datamosh crosses to a recorded web page. Effects
Roman Verostko joins the recreations.Examples/Recreations/RomanVerostko is new, after the American painter (1929 to 2024) whose own software, Hodos, drove a pen plotter that held a Chinese brush in its arm, and who called the code the work's genotype and each painting one member of its family. Pathway follows the procedure he published in 1988: one gesture cast from control points chained at random, laid down once as a brush stroke (a solid body under a dry brush that drags off at its end) and drawn again thousands of times behind it as fine pen strokes, each smaller and turned and placed around a point of the brush stroke, plotted a pen at a time from warm inks to cool, with thin rectangles of opposing hues near gray standing apart; mirror repeats it across the sheet. Cyberflower repeats one curved line along a larger copy of itself, hundreds of times a hair apart, turned with the path and twisted, until the close lines fold into a flower, two of them in orange and yellow or one in red or green, the initiator small in the lower left. Each plots a sheet, holds it, and plots the next of the family with the next seed, and each exports an SVG a plotter can draw in which every stroke is the gesture under its own scale, turn, and place.
A sketch's --help. Running a sketch with --help (or -h) prints its name, how to run it, its parameters as declared and as --param takes them, and every flag it reads, grouped, each with one line, and stops without opening a window, writing a file, or running setup(). Export
Marks built from one gesture.GestureMark(mark, width:) (or a contour at one width, or points with a width each) turns one drawn path and its width into sixteen families of marks a plotter can draw: cloud, chain, and spikes; dashes, dots, and strips in rows across the width; feather, leaves, and fringe sprouting off both sides; pixels, facets, and lanes; and spiral, strands, fragments, and wiggle around the path. Each returns GestureMark.Pieces (a closed outline to fill or an open line to stroke, with its row and place), and .shape merges a list into one silhouette. Sizes are fractions of the width where a piece sits, so a taper narrows the marks. A growing gesture never moves what it laid down, so a sketch can rebuild the marks from its pen every frame. Beside them, hull() and blob() enclose a whole gesture, figure(_:) is the shape its two ends span, and any Shape can be spiked(_:height:) or wobbled(by:scale:). Gesture marks
Strokes in a material.strokeMedium(_:) shades a stroke one pixel at a time in its own coordinates, how far along the path and where across the width. .pencil, .charcoal, and .pastel are one dry renderer at three settings of .dry(tooth:softness:roughness:palette:seed:): pigment catches on the paper's tooth, so a light line breaks into specks rather than fading, and .pastel(palette:) gives each grain one of several colors. .bristles streaks two pigments along the path, .dryBrush runs dry on the paper's grain, .wet drags the paint under it along its direction (the frame drawn once more without its wet strokes, so a wet mark never drags itself), and .oil lights its own ridges. The stroke's color is the pigment and its alpha the density, so a mark recorded with an opacity response thins where the hand did. A translucent medium mark lays one coat where it crosses itself. The analytic outlines that take a dash take a medium too; a vector export writes the flat ribbon, and the web page export names the call it cannot carry. Marks
A shader stroke knows where it is on the ribbon. Under stroke(_ shader:), info.arcLength is the distance along the path in its own units, info.across the place across the width (-1 and 1 at the edges), and info.halfWidth the local half-width, beside info.along and info.distance. Color
Shaping the press.StrokeMark.pressureDeadZone ignores a press under it, pressureCurve raises the press to a power before any response reads it, and maxWidthChange limits how fast a recorded mark's width may change per point traveled, so a sudden press swells the mark rather than stepping it. Marks
One vertex a particle.drawParticles(buffer, style: .light, maxSize: 1) names the largest particle in a buffer, and each particle is then drawn as one point primitive instead of a quad of four, on the same pixels; the vertex work was most of what a spray of millions of sub-pixel points cost, so such a spray draws in about half the time. LineSpray names its own point size, so a spray gains it with no change to the sketch, and the Particles form takes the same label. A particle wider than 511 texels keeps the quad, so the named size never limits what a buffer draws; unnamed, every particle takes the quad as before, now a strip of four vertices rather than a list of six. Depth of field
A red-and-cyan anaglyph..anaglyph(separation:) prints a layer as a stereo pair for red-and-cyan glasses: the red channel from a copy shifted one way, the green and blue from a copy shifted the other, so a dark mark comes out as a cyan copy and a red copy that meet in a fused dark, and a photograph as the classic doubled print. scene.combined(with: scene.depth, .anaglyph()) reads a depth map instead, a 3D layer's own or one drawn by hand, so a near thing stands off the page and a far one sinks into it by its distance from focus. Effects
Plates out of register.separation.misregistered(offsets:rotations:) moves each ink's master by its own offset and turns it about the sheet's center, on the spot-ink masters and the process plates alike, so the preview shows the misprint: a black mark ringed by its own inks, a fringe of one ink on one side of a shape and bare paper on the other. Misregister first and screen after, so each plate's dots and screen angle stay its own. Print separations
A heat mirage..mirage(horizon:faults:amount:phase:) shifts every row above a horizon sideways by a wavering amount that grows toward it, stepped at faults, and mirrors the picture into a band below the line with waves that grow downward, the shimmer over a hot road; Filter.mirageShift(y:) is the row shift the filter reads, for a sketch that draws where a row went. Effects
Schlieren..schlieren(angle:amount:) reads a layer's luminance as the density of a gas and maps the gradient along a knife's angle to brightness about a mid-gray, light where the density climbs and dark where it falls, with a razor flip at every spine: the knife-edge photograph of heat or a shock. Effects
A ramp over wavelengths.Ramp.wavelengths(from: 400, to: 700) places the pure hues of the wavelengths evenly, so color(at:) walks the physical spectrum, a rainbow with no magenta in it and a wide green. Color
Chromatography rings.Chromatography.scatter(in:count:radius:) and .spread(at:radius:) give the stain a drop of ink leaves as it spreads through paper, as geometry a sketch holds: rings around a core, each a band of one tone, noisy with the paper's grain, with fibers wicking past the outer front, and drops that spread into each other stopping where they meet, with a ruffle, and never entering a neighbor's core. The Effects/Phenomena example shows all six looks under one picker. Textures
Textures drawn as lines. Four textures a plotter can draw, each as geometry a sketch holds and strokes, and each repeating from its seed. WoodGrain.trace(in:) traces wood grain as streamlines through a ring coordinate, bending around its knots and closing into rings around them, every stroke carrying its ring's tone and the strokes crowding on the rings. Frost.grow(along:) stands hoarfrost needles along any outline or shape, barbed under one law and clumped into runs. Crackle.grow(in:) walks the veins of cracked wax across a cell, each forking once near its middle and stopping where it meets another, never crossing, and crowding along the creases you name. Ikat.stripes(in:) dyes stripes whose edges step once per bundle of warp threads, with spikes, intrusions, and a lean along the warp. The Patterns/LineTextures example draws each as a plotter would, stroke by stroke. Textures
Rust and verdigris.generate(.rust()) paints corrosion blooms over steel: blobs whose edge wavers in two octaves around a circle, nested masses in darker tones toward the core, a flaked lip at the edge lit from one side, blisters that catch the light on one side and shade on the other, and stains that run down. generate(.verdigris()) paints a crust over the same blobs in the greens of weathered copper over bronze: a mottled film worn through to the bronze in patches, pale mineral crust where the mottle peaks, a powdery edge, a tide line that comes and goes around the edge, and pale drips where water ran. The blooms are a Patina the sketch can hold, scattered from a seed with Patina.scatter(in:count:radius:seed:), each Blob with its outline, its masses, and its blisters as geometry a plotter draws; hand the generator one and it paints those very blooms, so an outline stroked from it lands on the paint. Textures
A terrazzo floor.generate(.terrazzo()) lays chips of stone in a binder: three size tiers thrown as darts, largest first, every chip clear of every other by a gap, each a polygon of five to eight corners in one of the tones, the larger ones hatched by their size. The chips are a Terrazzo the sketch can hold (Terrazzo.scatter(in:chipRadius:density:gap:tones:seed:)), each Chip a Shape, and the generator paints the floor it is handed. Textures
Bubble wrap..bubbleWrap() lays a sheet of bubble wrap over a layer, or over the whole frame as a postProcess: a hex lattice of lenses that magnify what is under them, each with a shadow ring, a bright arc toward the light and a dark one away, and a highlight on its dome. Effects
A crease in a heightfield.sheet.creased(along: [a, b], width: 0.03, amplitude: 0.3) folds a Heightfield along a path by one closed-form kernel (Heightfield.creaseProfile(at:): a cusp, a step that lifts one flank, and a trough two widths out), so creases stack into a crumpled sheet. The same kernel now shapes .paperTexture's folds, which are straight seeded creases lit on one flank, so a paper-textured picture looks different from before. Terrain
A hologram material.material(.hologram) rules a diffraction grating into a polished metal, the rainbow of a hologram sticker or the back of a disc: fine grooves send each color of a light off at its own angle, so the color at a point follows the angle between the light and the eye and walks through the spectrum as either moves. Material.hologram is the strength, gratingSpacing the groove pitch in nanometers (about 1,000 for a sticker, 1,600 for a disc), and gratingRotation turns the grooves; over a crumpled normal map every facet turns them its own way, which is holographic foil in 3D. It answers the plain lights, and a path-traced export shades it as the metal under it. Examples/3D/Materials/Hologram, Docs.
Chrome for lettering..chrome() fills a layer's shape with airbrushed logo chrome: a sky above a horizon that bends and drifts, a floor below it, and at the join a dark core band, a razor break, and a bright wire. The sky and the floor are Ramps (.chromeSky and .chromeFloor by default), the core and the wire are colors, and the horizon, the warp, the band widths, the amount, and the phase are numbers, so a gold or a night palette is the same call with other stops. It exports to the web page. Examples/Effects/ChromeLettering, Docs.
The color of a thin film, on the CPU.Color.interference(thickness: 420) is the color a clear film that many nanometers deep shows, worked out from the light its two faces send back out of step, at full brightness, and Spectrum.interference(thickness:ior:) is the reflectance curve behind it. A Ramp of it through .alongPath colors a stroke in a soap film's true order, straw to magenta to blue to green, along its length. It matches the .thinFilm filter's pixel within a level through the strong colors. Examples/Color/PearlStrokes, Docs.
Holographic foil..holographicFoil() fills a layer's shape with crumpled holographic foil, and the foil moves: a stepped rainbow runs across a sheet of facets and breaks at every crease, because each facet shifts the stripes by its tilt; a light at lightAngle shades the facets, lights the creases it crosses and darkens the ones it runs along, and puts a cross glint on the corners of the facets that face it hardest; phase sweeps the bands, so phase: time and lightAngle: time * 0.3 make the sheet move; and relief reads the layer's own brightness as height, so a gray mark drawn into the layer presses into the foil as creases. The sheet is a FacetField, the filter's own by default or the one you hand it, and the GPU reads the facets you hold, so the creases you stroke from sheet.edges land on the filter's own. Examples/Effects/CrumpledFoil fills the canvas with a sheet that breathes under a drifting light. (Effects)
A sheet of facets.FacetField lifts a Delaunay triangulation by a height function into flat faces that each know their normal, which way they lean (tilt), and how squarely they face a light (facing(_:)), with every crease listed once in edges for a plotter. FacetField.grid(in:spacing:seed:height:) stands it on a jittered lattice, FacetField(points:height:) on any scatter, crumpled(in:spacing:crinkle:seed:) makes the foil's own crumple, and lifted(by:) lifts the same triangulation again, so a sheet that breathes never triangulates twice. (Voronoi & Delaunay)
A shape cut by a line.shape.split(along: line) gives a shape's two sides of a Ray2, clipped(to: HalfPlane(point:inward:)) keeps one side, and clipped(within:of:) keeps the band around a line, each by one walk of the outline, with holes kept and the two sides of a split adding up to the whole. (Geometry)
A stepped ramp.Ramp.stepped([.red, .orange, .yellow]) holds each color flat up to the next stop, with hard edges and no blending, for a poster-flat gradient; Ramp.stepped(stops:) places the bands, isStepped says which kind a ramp is, and reversed keeps the bands. Ramp.holographic is the foil's stripe spectrum, eight flat bands in the order a grating spreads white light. (Color)
Changed
The Guide is forty-six chapters. Chapter 20 split along its families: Pictures restyled keeps the painting, the line, the grade, the film, the paper, and the hand-colored print, with the ink lines and flat regions after it, and the new Chapter 21, Glass, chrome, and tape, takes the materials built from a silhouette, the chrome, chromatic aberration, the lens, the pin, and the mixer, and the tape and lens looks, with a title card of its own as the finished sketch, then the foil, the bubble wrap, and the filters that read a layer as something else. Every chapter from 21 on has a new number, one higher, so a link to a chapter file needs the new one: 21-PicturesYouSolve.md is now 22-PicturesYouSolve.md, and so on through 46-Installations.md. A link to a section that moved names its new chapter. The Guide's contents list them all.
Feature edges on a mesh that moves. A mesh rebuilt every frame over the same index buffer, a trail or a surface displaced in place, keeps how its faces meet and redoes only the crease test, so featureEdges() on a 1.2-million-vertex mesh costs about 16 ms a frame where it cost 0.8 s. A moving mesh also holds one cached entry rather than one for every recent frame. Hidden-line solids
A volume skips its empty space. The march steps past the blocks of a grid that hold nothing and around the cloud's outside, taking only steps that would have read nothing, so every volume draws the same bytes. The Volumes example's plume went from 9.6 to 7.3 ms a frame at 1080 by 1080 on an M2, and from 24 to 18 at 1800. Volumes
Fixed
Touching pieces bounce the same light every time. Under globalIllumination(), a solid cut into pieces that fit back together (Mesh.fractured, or a box standing flush on a floor) could light a face one level brighter or darker from one render of a frame to the next, in a speckle along the light's gradient, because a probe ray meeting two touching faces at one distance took whichever its search reached first. The tie is now settled by a fixed order, so the same seed and frame draw the same picture, and a scene whose pieces do not touch draws as it did. 3D
A wall, a ceiling, or a floor reads the bounce where it stands. Under globalIllumination(), a surface beside a room's boundary read its light from the probes in the room, up to a cell in front of it and nearer the light, so a ceiling read 12 to 21% brighter than a path trace of the same room, and every boundary read high. Each probe now carries how fast its light dims toward the surface behind it, and a surface's read is carried back to where the surface is: the ceiling reads within 3% of the trace, and the room's mean error falls from about 16% to 4 to 8%. A bounce-lit room comes out a little darker near its walls. It costs about a millisecond a frame in a 1080 room. 3D
An emissive map glows by its map in the bounce. A panel glowing through Mesh.surfaceMapped(emissive:) lit the room under globalIllumination() as if its whole face glowed at its factor; its light now follows the map, as in the path-traced export. A mesh projected by position (triplanar), a copy, and a map that is a layer drawn the same frame keep the factor. 3D
A polished floor throws its light into the bounce. A smooth metal or glossy surface reflected a lamp in a spike the probes all but missed, so a polished copper floor threw under a tenth of its copper onto the ceiling, and nothing as it neared a mirror. The bounce now spreads a lobe narrower than the probes can hold to their own grain: the ceiling gets about 0.84 of a path trace's copper, and the rest lands on the walls as a broad, soft patch rather than a sharp spot. 3D
Fog stays where it was drawn under a caption. A 3D scene with fog and a caption, or anything in withOverlay, drew the fog's air a second time over the finished frame as if every pixel looked out to the far plane, so a low mist became one solid sheet below the horizon (the Atmosphere example since 2026-10-12, when captions moved into the overlay). The overlay pass now leaves the fog out, as it already left out the sky. Effects
A lens flare's coatings reflect what a thin film does. A coated surface's reflectance is the exact single-layer form, every round trip inside the coating summed for each polarization, where it had counted one inner reflection weighted as if the light crossed the outer face the same way twice and blended toward bare glass off the axis. Head on into 1.67 glass a coating sent back 0.0086 where a film sends back 0.0043, and leaving that glass at 20 degrees 0.0226 where it sends back 0.0069. The ghosts' colors shift with it. Lens flare
stopped(to:) means the f-number it names. An f-number is read from the opening as the front of the lens shows it, which the glass in front of the iris magnifies, and the iris was being closed to that opening's size: the double Gauss at f/8 stood at f/5.5 and the Heliar at f/6.4. Every stopped-down flare now draws smaller ghosts and a longer star at the f-number it names, and Lens.standard is the double Gauss at f/5.6, which draws the default flare as it was. Lens flare
Every ghost brightens as the iris closes. Stopped down, a flare brightens every ghost by as much as the opening's area shrank, as a photograph exposed for the scene does, where a ghost the front glass bounds rather than the iris used to keep its brightness. A stopped-down Heliar shows more of its veil. Lens flare
displayHeadroom is 1 unless the sketch asked for headroom. It read the screen's headroom, which the system grants to whatever on the screen asked for some, so a .standard or .wide sketch beside another window holding headroom read that window's 1.76. It now reads 1 there, as its page said, and only an .extended sketch reads the screen. Color output
A live soft proof on a wide canvas proofs the canvas's own colors.Filter.softProof with a proof from: .displayP3 looked a pixel up by its sRGB components, clipped to sRGB, in a table indexed by Display P3 components, and handed back P3 answers as if they were sRGB ones. A saturated P3 color now proofs to within two levels of the same proof on the CPU. Print color
A layer can draw a filter made the same frame. A filtered or combined layer drawn into another layer (withTarget(b) { drawImage(a.filtered(.invert()).image, 0, 0) }) came out empty, because every plain layer was drawn before any filter ran. A layer that draws an op's result now waits for it, through chains of layers and ops; a frame that draws its ops only onto the canvas keeps the order it had. Effects
Hatching no longer skips its first line.Hatching.lines(filling:) and the SVG export's hatched fills started one step too far in whenever a shape's top sat just above a line of the lattice every fill shares, so equal cells in a grid got different counts and a margin of up to a step and a half. The first line is now the lattice line at or just under the top; neighboring fills still line up. Export
A live window survives a framework rebuild. A save after the framework was rebuilt under an open window compiled the sketch against a framework the window was not running, and the window crashed on load. OllinLive, OllinLiveCoding, ollin, and the gallery now refuse that reload with one sentence saying to relaunch, and the sketch on stage keeps playing. Live coding
The path-traced export's two reads of a room. The trace ran hot in an environment with lamps: the path's own miss read the room blurred to its footprint while the environment's draw read it sharp, so a lamp's blurred skirt was counted beside its sharp core, and a white matte ball in the bundled interior traced a quarter brighter than the window showed it (a metal one at roughness 0.5 by 15%). Both reads now take the same picture at the same level along a direction, and the trace and the window agree on a ball in a lit room within 1%; the grain the footprint read settled on a curved mirror stays settled. Path-traced export
Light behind solid glass in the trace. A surface's shadow rays pass a solid straight and tinted while the path that refracts through it reached the same light again at full weight, so a ball behind a block of glass with the air's own index read 8% brighter than without it (behind a 0.3 slab of index 1.5, 23% above the trace's own estimate). The crossing now carries the surface's pairing on, as a thin pane's did, and the ball behind the block reads as it does without it. Path-traced export
A few more numbers stop at the physics bridge. A body's buoyancyScale, a character's facing, a rope's radius, and the 2D world's bounds now keep what they had when handed a value that is not a number, an infinity, or a magnitude past a billion units, with the one-time note the other members print, and a ragdoll's pose(from:) or drive(toward:) ignores a scene whose transforms hold one instead of handing it to the solver. Physics in 3D
A picker that ran off the panel. A @Param picker with style: .segmented whose names are wider than the inspector panel (five long names) ran past the panel's edge, where its segments could not be clicked. It now falls back to the menu row when even the wrapped control does not fit, since a segmented control never shrinks below its names. Parameters