<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Notes from the build | Sites by Presive</title><link>https://presive.co/sitesbypresive/journal</link><atom:link href="https://presive.co/sitesbypresive/journal/feed.xml" rel="self" type="application/rss+xml"/><description>Short notes on how this site is made: the parts that took longest to get right.</description><language>en-us</language><item><title>Keys to the thread</title><link>https://presive.co/sitesbypresive/journal/keys-to-the-thread</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/keys-to-the-thread</guid><pubDate>Wed, 30 Sep 2026 12:00:00 GMT</pubDate><description>A site built around one object should let you look at the object. Six keys walk the chapters, show the grid, keep a frame, take the words away for a moment or send the page back to its wireframe; one field goes anywhere.</description><content:encoded><![CDATA[<p>Every page of this site is read past a graphite ribbon, and the reading is the point: the ribbon sinks under a line of text wherever it would cross one. That leaves a visitor who wants to see the object itself with nowhere to look. So there are keys, listed under the question mark and in a card behind Keys in the footer.</p><figure><img src="https://presive.co/sitesbypresive/journal/alone-1440.webp" alt="The home page&apos;s first screen with the text taken away: on black, the ribbons alone, one broad graphite band sweeping up from the left with a lit edge along its crest, a second one opening beneath it, a third turning away at the right." width="1440" height="400"/><figcaption>The home page, taken from the running site with T held: the thread alone.</figcaption></figure><h2>Hold T</h2><p>While T is held, the text, the bar and the footer step back and the ribbons draw without the mask that sinks them under the reading, without the work&apos;s pictures and without the headline cut out of them. While it is held the pointer turns the sculpture, a few degrees each way, so it can be looked round. Let go and the page comes back at the same pace. A window that loses focus with the key down lets go too.</p><pre><code>// the reading mask, eased out while T is held
const want = alone.on ? 1 : 0;
aloneEase.current += (want - aloneEase.current) * 0.12;
uniforms.uReadFade.value = fade * (1 - aloneEase.current);</code></pre><h2>Hold S</h2><p>While S is held the page goes back to its wireframe. Every line of type becomes a bar the length of the line, in its own color a step down; every picture, video and live concept becomes a crossed box with its size in pixels; each heading and deck gets its type in the margin, the role and the size over the leading, read from the page&apos;s own computed styles. The canvas draws the ribbons as the mesh they are built from and puts the work&apos;s pictures away. The bars are a line-through, not a new font, so nothing changes size and nothing on the page moves.</p><p>The page does not flip: one lit line crosses the screen and the wireframe is drawn behind it, a view transition of its own type over the page as it was. Let go and the line crosses again with the finished page behind it. With reduced motion it simply changes. On a phone, press and hold “Hold for the wireframe” in the footer.</p><p>These are nearly the rules the sketches in the studies are drawn by, described in “A sketch drawn from the finished page”, applied to the page you are on while it runs. The one difference is display type, which is a bar here and an outline there.</p><figure><img src="https://presive.co/sitesbypresive/journal/wireframe-1440.webp" alt="The home page at the studies, stopped as S goes down: above a lit horizontal line the page is a wireframe, its heading and deck gray bars with their type specs in the left margin and the thread a fine mesh; below the line the first study&apos;s picture is still the finished page." width="1440" height="400"/><figcaption>S going down on the home page, stopped halfway: the wireframe above the line, the finished page below.</figcaption></figure><pre><code>/* a line of type becomes a bar the length of the line */
html[data-sketch] :is(.page, .site-nav, .site-footer) * {
  -webkit-text-fill-color: transparent;
  text-decoration-line: line-through;
  text-decoration-thickness: clamp(2px, 0.34em, 15px);
  text-decoration-color:
    color-mix(in srgb, currentColor 34%, var(--color-ink));
}</code></pre><h2>Press P</h2><p>P keeps the frame: the canvas is drawn once more without the mask and without the pictures, laid on the page&apos;s own ground at the screen&apos;s own resolution, and saved as a picture with one line of type for the page, how far down it was and when. It is downloaded to your machine and sent nowhere.</p><h2>J, K and G</h2><p>J and K step to the next and the previous chapter. Every chapter opens on a hairline, so a step lands on the line the thread lies down on. G draws the construction grid over the page, the twelve columns everything is set on. None of the keys listen while you are typing, or when a modifier is held.</p><h2>Cmd K, and the rail</h2><p>Cmd K, or Ctrl K, opens one field that finds every page, study and note and everything the keys do, and from three letters the words inside the notes as well: choose a result and the note opens on that paragraph, lit. On a phone the same field is in the menu.</p><p>On a wide screen the rail down the right margin of the home page and of each study is a grip as well as a list: drag along it and the page follows the pointer between the marks, so the whole thread runs under the hand, every pose in order.</p>]]></content:encoded></item><item><title>A thread of your own</title><link>https://presive.co/sitesbypresive/journal/a-thread-of-your-own</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/a-thread-of-your-own</guid><pubDate>Wed, 30 Sep 2026 12:00:00 GMT</pubDate><description>The site keeps the pages you read in this tab, and draws them back for you where you write to us. It sends them only if you tick the box.</description><content:encoded><![CDATA[<p>The whole site is one thread, from the first sketch to the form at the bottom of the page. A visit is one too: the pages you opened, in order, and how long each held the screen. Until now that thread existed only in your head. Now the contact form draws it, on the same hairline and beads as the menu, with a lit bead for the page you are writing on.</p><figure><img src="https://presive.co/sitesbypresive/journal/your-thread-1440.webp" alt="The contact page on black: at the left, under the label Your thread so far and a length of 1.6 m, a hairline with beads for Home, 22 s, Slack Water, 6 s, and Journal, 8 s, and a lit bead for Here, writing; at the right, the form&apos;s name and email fields and an unticked box, Send the pages I read with my note." width="1440" height="400"/><figcaption>The contact page, taken from the running site after a short visit.</figcaption></figure><h2>Kept in the tab</h2><p>The record lives in session storage: one list per tab, gone when the tab closes, never in a cookie and never on our server. A page adds a stop when it opens and adds its visible time every few seconds, so a tab left in the background does not count as reading.</p><pre><code>// on every page: a stop, and the time it is actually on screen
const t = readTrail();
if (t[t.length - 1]?.path !== pathname)
  t.push({ path: pathname, title: &quot;&quot;, ms: 0 });
writeTrail(t); // sessionStorage, this tab only
document.addEventListener(&quot;visibilitychange&quot;, () =&gt; {
  if (document.visibilityState === &quot;hidden&quot;) { flush(); since = 0; }
  else since = performance.now();
});</code></pre><h2>Sent only when asked</h2><p>Under the form there is a box that sends the list with your note, so the person who replies knows whether you read about the boats or only the home page. It is off until you tick it, and the privacy notice says the same.</p><h2>Its length</h2><p>The figure beside the label is the scrolling, up and down, at 96 CSS pixels to the inch. Jumps are left out: an anchor link, or a new page starting at its top, moves the page without anyone pulling the thread.</p><p>On the page that does not exist, the same thread is drawn with every stop a link, so the way back from a dead end is the way you came.</p>]]></content:encoded></item><item><title>A thread that takes the color of the work</title><link>https://presive.co/sitesbypresive/journal/a-thread-that-takes-the-color-of-the-work</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/a-thread-that-takes-the-color-of-the-work</guid><pubDate>Tue, 29 Sep 2026 12:00:00 GMT</pubDate><description>Passing a study, the ribbon leans towards that study&apos;s own color, and gives it back as it leaves. The metal stays the same metal.</description><content:encoded><![CDATA[<p>The three studies on the home page each have a color of their own: the low sun of Concrete and Light, the tide of Slack Water, the sage of Soft Geometry. The ribbon that runs past them was the same gray the whole way down, as if it had never touched them. Now it picks a little of each up, the way a thread takes dye.</p><figure><img src="https://presive.co/sitesbypresive/journal/tints-1440.webp" alt="Two moments of the home page side by side on black: at the left the ribbon hangs beside the Slack Water frame, a dark sea with a large white 42, and its metal is cool and blue-gray; at the right it hangs beside the Soft Geometry catalog page, and its metal is sage." width="1440" height="400"/><figcaption>The home page, taken from the running site: the same ribbon beside Slack Water and beside Soft Geometry.</figcaption></figure><h2>Only the base color</h2><p>The material is locked down the page on purpose: an earlier version let each section swing the lighting, and the same object read as graphite in one place and white vinyl in another. So nothing about the metal changes here, not the roughness, not the reflections. Only its base color leans towards the study&apos;s, at most half way, and only while that study is at the middle of the screen.</p><p>Because the ribbon is mostly metal, the base color tints what it reflects rather than painting over it. On black the result reads as light from the work falling on the object, not as a colored ribbon.</p><pre><code>// once a frame, while the work is on screen
rows.forEach((r, i) =&gt; {
  const d =
    Math.abs(r.top + r.height / 2 - h / 2) / (r.height / 2 + h / 2);
  const weight = 1 - Math.min(1, d);
  if (weight &gt; amt) { amt = weight; idx = i; }
});
tint.lerp(STUDY_TINTS[idx], 0.08);
mix += (Math.min(1, amt * 1.4) * 0.5 - mix) * 0.06;
material.color.copy(BASE).lerp(tint, mix);</code></pre><h2>And the other way</h2><p>A fast scroll pulls the thread taut: the slow breath that runs along it flattens at once and comes back over a second or so once the page stops. It is the smallest possible answer to the hand that moves the page, and it never moves the object off the line it is laid on.</p>]]></content:encoded></item><item><title>Where the thread rests</title><link>https://presive.co/sitesbypresive/journal/where-the-thread-rests</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/where-the-thread-rests</guid><pubDate>Tue, 29 Sep 2026 12:00:00 GMT</pubDate><description>Between two chapters the ribbon lies down on the hairline that opens the next one, and the drawn line steps aside while it is there.</description><content:encoded><![CDATA[<p>Every chapter of this site opens with a hairline above its label. For a long time the ribbon simply changed shape at the boundary, and the hairline sat there as a second, unrelated line. Now the two are one line: at each hand-over on a wide screen, the ribbon narrows onto the incoming hairline, lies on it for a moment as a thread, and lifts off into the next chapter&apos;s shape.</p><figure><img src="https://presive.co/sitesbypresive/journal/thread-on-rule-1440.webp" alt="The home page at the hand-over into the studies: on black, a thin gray thread lies across the full width of the screen on the line above the label Studies and the heading Three studies." width="1440" height="400"/><figcaption>The home page, taken from the running site: the thread on the studies&apos; rule.</figcaption></figure><h2>A thread, not a rod</h2><p>The first version laid a straight bar over the rule, and people read it as a stick on its way down. The pose it lies in now runs a little past both ends of the rule, tapers to a point at each, and keeps a slack of a few pixels along its length, the way a thread lies on a table.</p><pre><code>// the pose on a rule, seven points along its width
const over = Math.min(90, width * 0.08);
const pts = [0, 1, 2, 3, 4, 5, 6].map((i) =&gt; [
  x0 - over + ((width + 2 * over) * i) / 6,
  wy + (i === 0 || i === 6 ? 0 : 3.5 * Math.sin(i * 1.7 + 0.5)),
  0,
]);</code></pre><h2>The line steps aside</h2><p>While the thread lies on a rule, the rule&apos;s own element fades out in 200 ms and comes back over most of a second when the thread leaves, so the page never shows two lines where there is one. On every page but the home page and the contact page, the last hand-over is onto the footer&apos;s rule, timed to the end of the scroll, and the thread stays there.</p><p>Nothing here is animated on a clock. Every pose is a function of the scroll position, so scrolling back up plays the whole thing backwards, which is what the link above the footer does.</p><p>Where the object does not come down onto the rules, on the paper of the case studies and on a phone, the rule itself carries the thread: it is drawn over from the left as the reading reaches it, and a bead settles where it ends. On a phone the same line runs into the submit button at the end of the form.</p>]]></content:encoded></item><item><title>A sketch drawn from the finished page</title><link>https://presive.co/sitesbypresive/journal/a-sketch-drawn-from-the-finished-page</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/a-sketch-drawn-from-the-finished-page</guid><pubDate>Tue, 29 Sep 2026 12:00:00 GMT</pubDate><description>Each concept&apos;s case page wipes from its week-one wireframe to the finished section. The wireframe is not drawn by hand: it is the same page, told to forget its paint.</description><content:encoded><![CDATA[<p>The line under this site&apos;s name is one thread from the first sketch to the form. A case page can show that instead of saying it: the section frame sits over its first sketch, and as the page is read, the thread wipes the sketch into the finished work.</p><h2>Forgetting the paint</h2><p>A script opens the concept page in a headless browser, reads every element&apos;s computed style first, and then redraws it. Display type keeps its size and position and loses its fill, so a headline becomes its outline. Reading text turns into a gray bar the length of each line. Anything painted and large enough becomes a crossed box, the old sign for a picture that has not been made yet, and a thick drawn arc comes down to a pencil line. The construction grid stays.</p><p>Last, a displacement filter with a little noise makes every line wobble by about a pixel. Without it the result looked like a print of the page, not like a drawing of it.</p><h2>Why the same page</h2><p>Because the layout is the part that was decided in week one. Drawing a new sketch after the fact would have been a picture of a process; taking it from the finished page shows that the columns, the rows and the headline&apos;s place were there from the start, and that what changed was everything laid on top of them.</p>]]></content:encoded></item><item><title>A ribbon that never crosses a word</title><link>https://presive.co/sitesbypresive/journal/a-ribbon-that-never-crosses-a-word</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/a-ribbon-that-never-crosses-a-word</guid><pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate><description>One 3D object runs behind the whole site. Here is how it stays out of the way of every line of text without turning into a gray box.</description><content:encoded><![CDATA[<p>The site is built around one object: a graphite ribbon in a single WebGL canvas, fixed behind the page, that changes shape for every section. The canvas sits under the text, so the ribbon can always be read around. The problem is the light. A bright crest passing behind a paragraph makes the paragraph hard to read, and the page is full of paragraphs.</p><h2>A map of the reading</h2><p>Whenever the layout changes, every text node on the page is measured, line by line, with the same boxes the browser uses to draw it. Lines that sit above one another in one column are merged into a single box, because a stack of rectangles of different widths prints itself into the ribbon as a staircase. The boxes are drawn as one white shape into a small canvas and blurred once, by hand, so that where two boxes meet there is a slope and not a step. That canvas is the mask the shader reads.</p><p>Each box is grown by most of the blur radius before it is softened. Without that, a short label is smaller than the blur, the mask never reaches full strength inside it, and the ribbon stays bright exactly where a 12 px line needs it not to be.</p><p>Display type is taken at a fraction of the strength: a ribbon behind a large headline is part of the composition, a ribbon behind body copy is not.</p><h2>Sinking, not hiding</h2><p>Each pixel of the ribbon reads the mask at its own place on the screen. The mask keeps the viewport&apos;s proportions, so the falloff is the same in both directions at any window shape. Where there is reading, the pixel is mixed towards the page&apos;s own background color.</p><p>How much is decided by the pixel&apos;s own brightness. A lit crest under a label sinks almost completely; a face in shadow keeps its shape. A flat fade would have to be strong enough for the brightest crest, and at that strength it flattens every dark part of the object into a gray rectangle. This way the ribbon passes behind the text and stays an object.</p><pre><code>// ribbon fragment shader, after tone mapping
float read = texture2D(uRead, gl_FragCoord.xy / uResolution).r;
float rbLum = dot(gl_FragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
float rbFade = clamp(uReadFade * (0.5 + 1.6 * rbLum), 0.0, 1.0);
gl_FragColor.rgb = mix(gl_FragColor.rgb, uGround, read * rbFade);</code></pre><h2>Measured, not eyeballed</h2><p>A script loads each section, takes the canvas once with the ribbon and once without, and counts the ribbon pixels that land inside each text box. The bar is under half a percent of a block&apos;s area, and above three percent of the frame outside the text, so the object never simply disappears to pass the test.</p><p>The one exception is the home page headline. Its glyphs are drawn into the stencil buffer, so one ribbon passes in front of the letters and two behind them, and only while the first screen is at rest. Once the page moves, all three pass behind.</p>]]></content:encoded></item><item><title>A performance budget we publish</title><link>https://presive.co/sitesbypresive/journal/a-performance-budget-we-publish</link><guid isPermaLink="true">https://presive.co/sitesbypresive/journal/a-performance-budget-we-publish</guid><pubDate>Sun, 27 Sep 2026 12:00:00 GMT</pubDate><description>Every release of this site runs the gate every client project runs. The numbers on the home page are read from its last run, never typed in.</description><content:encoded><![CDATA[<p>A studio that sells motion and 3D has to show that neither costs the visitor a slow page. So the budget is written down before the work starts, and the site is held to it the same way a client&apos;s is.</p><h2>The gate</h2><p>A production build is served locally and measured with Lighthouse on mobile and desktop, then in a phone lab: a 390 px profile with the processor slowed four times and a Fast 3G network. The same run checks accessibility with axe, and loads the site again with reduced motion and with WebGL switched off, because both have to work on their own.</p><p>The thresholds: Lighthouse performance at 90 or above on a phone, the largest paint under 2.5 seconds, interaction to next paint under 200 ms, layout shift under 0.1, and the home page under 1.8 MB on a phone. A release that misses one does not ship.</p><figure><img src="https://presive.co/sitesbypresive/journal/budget-1440.webp" alt="A dark panel from the approach page with two measurements: page ready on a phone, 976 ms of 2.5 s, and tap answered on a phone, 88 ms of 200 ms, each with a bright bar well short of the mark that stands for its budget." width="1440" height="400"/><figcaption>The approach page, taken from the running site: the budget as the last gate measured it.</figcaption></figure><pre><code>// what the home page reads, from the last gate run
&quot;thresholds&quot;: {
  &quot;lighthousePerformanceMobile&quot;: 90,
  &quot;lcpMs&quot;: 2500,
  &quot;inpMs&quot;: 200,
  &quot;cls&quot;: 0.1,
  &quot;fpsMin&quot;: 55
}</code></pre><h2>What it takes</h2><p>The headline is plain text in the document and it is the largest paint, so nothing may load before it. The canvas is created after the load event, in an idle moment, and only on pages that have something to draw. There is one canvas for the whole site and one material for the ribbon.</p><p>The renderer watches itself. Quality comes in three tiers, from 360 segments along each ribbon down to 100, and two seconds under 50 frames a second drops the pixel density once. Pages that are for reading let the canvas render on demand, so it costs nothing while nothing moves.</p><h2>Published</h2><p>The release gate writes its results to one file, and the home page reads its four numbers and their budgets from that file. The full run, with every page and every check, is on the QA report page.</p>]]></content:encoded></item></channel></rss>