DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path investigations/loomworks-record-binary-reader-investigation-v0_1.md

Loomworks Record — Binary-Reader Investigation v0.1

Date: 2026-05-23 Trigger: Operator observation that PDF and DOCX files in the record currently render as a "downloadable but not rendered inline" placeholder card (screenshots captured 2026-05-23 afternoon).


What this document is

An investigation into adding inline-view support for PDF and DOCX files on record.dunin7.com. The current view template already promises this as future work ("In production, the viewer will open these in an appropriate inline reader where possible") and has the scaffolding in place — breadcrumb, status row, content card, and a "Not Editable" affordance in the action area. The investigation surveys what filling in the inline-reader work would involve, settles on a recommended approach, and names the scoping question.

The investigation is view-only. Edit support for PDF and DOCX is explicitly out of scope, with the reasoning recorded in §6 below.

The investigation depends on inferences about the current tools/build_site.py implementation that have not been verified by code inspection. Inferences are marked [inferred] throughout. A small CC inspection step would confirm or correct them before any execution work opens.


1 · Current state (what the screenshots tell us)

Two screenshots captured the current behavior:

Screen 1 — viewing examples/loompa-geology-field-example-v0_1.docx:

Screen 2 — viewing examples/loompafivethreadsv0_1.pdf:

What this tells us about the current implementation [inferred]:

  1. tools/build_site.py detects file extensions when generating viewer pages. HTML and Markdown files route to the standard render pipeline (Monaco-style content presentation with the editor accessible). Other extensions route to a binary-document template.
  1. The binary-document template is parameterized by file type — the card header reads "DOCX" or "PDF" depending on the extension. There is likely a small switch or mapping somewhere in the build script.
  1. The binary file itself is presumably present in the static-site output (Cloudflare Pages serves it directly when the Open <filename> link is followed), or the link points to a raw GitHub URL. Either works; the implementation detail affects how the inline reader will fetch the bytes.
  1. The "NOT EDITABLE" button is rendered as a disabled affordance rather than absent, which is interesting — it means the template treats binary documents as a recognized class with a known disposition, not as an unexpected case to handle.

The work this investigation scopes is filling in the "appropriate inline reader" promise without changing any of the existing scaffold.


2 · Reader options surveyed — PDF

Three credible approaches for inline PDF rendering, each with different trade-offs.

Option PDF-A — Native browser PDF embed via <embed> or <iframe>

Approach: serve the PDF directly from the static site, embed it in an <iframe> (or <embed> or <object>) tag sized to fill the content card area.


<iframe src="/examples/loompafivethreadsv0_1.pdf#toolbar=0&navpanes=0" 
        width="100%" height="800px"></iframe>

Strengths:

Weaknesses:

Option PDF-B — PDF.js (Mozilla's JavaScript PDF renderer)

Approach: load PDF.js as a library; render the PDF to a <canvas> element page by page; provide custom navigation controls matching the letterpress theme.


<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<canvas id="pdf-canvas"></canvas>
<script>
  pdfjsLib.getDocument('/examples/loompafivethreadsv0_1.pdf').promise.then(pdf => {
    pdf.getPage(1).then(page => {
      const canvas = document.getElementById('pdf-canvas');
      const ctx = canvas.getContext('2d');
      const viewport = page.getViewport({scale: 1.5});
      canvas.width = viewport.width;
      canvas.height = viewport.height;
      page.render({canvasContext: ctx, viewport: viewport});
    });
  });
</script>

Strengths:

Weaknesses:

Option PDF-C — Hybrid (native embed primary, PDF.js fallback)

Approach: feature-detect whether the browser will render the PDF inline; if yes, use native embed; if no (mobile Safari, some Android browsers), fall back to PDF.js.

Strengths:

Weaknesses:

Recommendation — PDF

Option PDF-A (native embed) for first ship. Reasoning:

  1. The PDFs in record.dunin7.com today are reference material — read-by-Operator on a single workstation (DUNIN7-M4) with a known browser. The mobile-fallback concerns of Option PDF-C don't apply at current usage.
  2. Zero new dependencies preserves the static-site simplicity. The current build script outputs static HTML; adding a JS library introduces a load on every view that may or may not be needed.
  3. If mobile or cross-browser concerns surface later (e.g., the audit viewer also wants to embed PDFs and gets used from a phone), Option PDF-C is the natural upgrade path. PDF.js can be added without removing the native embed.

The implementation work: identify the binary-document template, swap the placeholder card for an <iframe> (or <embed>) tag when the file extension is .pdf, size the embed to use the available content area, keep the existing breadcrumb and status row above it.


3 · Reader options surveyed — DOCX

DOCX is fundamentally different from PDF. PDF is a rendered-page format; DOCX is structured XML in a zip. To display a DOCX inline, the content must be extracted from the XML and rendered as HTML in the browser.

Option DOCX-A — Mammoth.js (client-side DOCX-to-HTML conversion)

Approach: load mammoth.js; fetch the DOCX as a binary blob; mammoth converts it to HTML; inject the resulting HTML into the content card.


<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
<div id="docx-content"></div>
<script>
  fetch('/examples/loompa-geology-field-example-v0_1.docx')
    .then(res => res.arrayBuffer())
    .then(buffer => mammoth.convertToHtml({arrayBuffer: buffer}))
    .then(result => {
      document.getElementById('docx-content').innerHTML = result.value;
    });
</script>

Strengths:

Weaknesses:

Option DOCX-B — Server-side rendering (Pages Function)

Approach: a Pages Function converts the DOCX to HTML on the server side using a Node-compatible library; the viewer receives pre-rendered HTML.

Strengths:

Weaknesses:

Option DOCX-C — Conversion at build time

Approach: when tools/build_site.py runs, it detects DOCX files and pre-converts them to HTML, storing the result as a sibling file. The viewer renders the converted HTML.

Strengths:

Weaknesses:

Recommendation — DOCX

Option DOCX-A (mammoth.js, client-side) for first ship. Reasoning:

  1. Mammoth.js is the established browser-side DOCX renderer. Its limitations are well-documented and predictable.
  2. The DOCX files currently in record.dunin7.com (e.g., loompa-geology-field-example-v0_1.docx) are simple-structure documents likely to render cleanly under mammoth.
  3. Client-side conversion fits the existing static-site architecture cleanly — Pages Functions stay out of the view path; build-script stays simple.
  4. If fidelity issues surface (a document with complex formatting that mammoth doesn't handle), the fallback is obvious: convert to HTML or markdown manually, archive the DOCX, edit the converted version. That's the same pattern the methodology already uses for "imported reference material that needs to be worked with."
  5. The DOCX file size in the repository today is small (the example is under 100KB); mammoth handles small DOCXs quickly. Performance only becomes a concern if multi-megabyte DOCXs with embedded images start appearing.

A small consideration worth naming: mammoth produces unstyled semantic HTML. The viewer needs to apply the letterpress palette via CSS so the rendered DOCX content visually fits the record.dunin7.com aesthetic. This is straightforward CSS work — about as much as styling a normal HTML document.


4 · What execution would roughly look like

Not a CR — just a sketch to size the work.

Engine-side: none. This work lives entirely in loomworks-record.

Pages Function side: none required. The DOCX or PDF file is served directly by Cloudflare Pages from the static-site output. No proxy needed.

Build-script side (tools/build_site.py): modify the binary-document template-generation logic to emit format-specific viewers rather than the current placeholder card.

CSS side (tools/static/site.css or equivalent): add styling rules for .docx-content so mammoth's output renders in the letterpress palette. Add sizing rules for the PDF iframe so it fills the content area cleanly.

Library side: add mammoth.js as a CDN script reference in the binary-document template. No npm install, no build-step change.

Estimated execution surface: 8-12 execution steps total. 3-5 acceptance gates. Mostly bounded HTML/CSS work plus a small Python change in the build script. Smaller than Piece 1 of Phase 63.

The work could plausibly fit as a single piece of a Phase 64 that has 2-3 pieces, or as queued direction that lands ad-hoc when the friction surfaces.


5 · Open questions

Open-1 — File size limits

DOCX files with embedded images can grow to many megabytes. At what point does loading a DOCX through mammoth.js in the browser become unpleasant? An execution-time decision: probably display a warning if a DOCX exceeds, say, 5MB and offer the download link as primary action rather than auto-rendering.

Open-2 — Cross-document references

The DOCX example in the repository (loompa-geology-field-example-v0_1.docx) is referenced from other documents and from the engagement-seed structure described in the project methodology. Does inline rendering change the link semantics? Probably not — the file URL stays the same; only the viewer page that wraps it changes. But worth checking that no existing cross-document references depend on the "download-only" behavior.

Open-3 — Accessibility

The native PDF embed is well-supported by screen readers in Chrome and Firefox; less so in Safari. Mammoth's HTML output is semantic and generally screen-reader friendly. If accessibility becomes a concern (e.g., record.dunin7.com opens to external readers), the PDF.js path may become preferable for its accessibility tooling.

Open-4 — Future support for other binary formats

The current binary-document template handles .pdf and .docx explicitly. What about .xlsx, .pptx, or images (.png, .jpg)? Images probably already render correctly via the build script (browsers handle them natively). XLSX has SheetJS (xlsx) as a credible client-side renderer. PPTX is genuinely hard to render in-browser. Worth knowing whether this work should extend to those formats or remain PDF+DOCX only.


6 · Why edit support is not in scope

The Operator question that triggered this investigation was "can yo look at providing the record edit/view with pdf and docx reader ability." The reasonable reading is "view ability" — the screenshots show the view-side placeholder explicitly named. But "edit/view" could also be read as "edit and view." The investigation considered edit and explicitly excludes it from scope. The reasoning:

PDF and DOCX are categorically different from HTML and Markdown. HTML and Markdown are text source formats — the file is its content. Editing means changing text, the editor handles text, GitHub stores text, Cloudflare Pages serves text. PDF is a rendered artifact format; "editing" a PDF means one of three quite different things (annotation, in-place text substitution, decompose-and-re-render) each requiring substantial separate tooling. DOCX is structured XML in a zip container — editable in principle but tooling cost is significant and round-trip lossiness is real.

The use cases don't establish edit support as load-bearing. Three classes of binary documents typically live in a methodology repository:

  1. Imported source material (e.g., loompafivethreadsv0_1.pdf) — read-mostly. The Operator's edit action would be commentary, which maps better to a sibling markdown file than to in-place modification.
  2. Exports of HTML/MD content — should regenerate from the source markdown, not be edited as exports.
  3. Native binary artifacts (signed PDFs, scanned images, diagrams) — edits don't really apply.

The sibling-markdown pattern handles the actual edit case. When the Operator wants to capture commentary, notes, or analysis on a PDF or DOCX, the methodology's existing pattern is clean: create a new .md file alongside the binary in the same section, with the commentary as markdown. The original file stays unchanged; the commentary is editable through the existing editor; both render through the existing viewer. No new tooling needed. Example: alongside examples/loompafivethreadsv0_1.pdf, an examples/loompafivethreadsv0_1-commentary-v0_1.md file would be the natural place for any analysis.

Adding edit support would muddy the format story. Today record.dunin7.com has a clean disposition: HTML and MD are editable source; PDF and DOCX are reference material. Adding edit support to PDF/DOCX makes the story ambiguous — which version is canonical, the original or the edit? What does diff'ing mean across an edit? What happens on round-trip lossiness? These are real architectural questions that would need to be resolved before edit support could ship. They are not resolved today and don't need to be.

The substrate-friction-discipline pattern argues against it. This morning's session produced the methodology candidate inventory existing substrate before designing new — and a corollary that runs through this discipline is don't design substrate without a concrete use case forcing it. Edit support for PDF/DOCX has no concrete case yet; the formats in the repository today are all read-mostly. Building edit support speculatively would be substrate design ahead of need.

Surface for future revisit. If a concrete edit case surfaces later (e.g., the project starts receiving DOCXs from clients that need structural modification before being served), a separate investigation would open at that point. The case would ground the scope; the analysis would proceed against real requirements rather than speculation. Until then, view-only is the right boundary.


7 · Scoping question

Three plausible dispositions for this work:

Disposition A — Phase 64 (Document Format View Extension)

After Phase 63 closes, Phase 64 opens specifically for view-side binary-format support. Scope is the 8-12 execution steps sketched in §4 plus the open questions in §5 resolved as Decisions. Coherent piece of work; clear acceptance gates; small enough to ship in a single phase cycle.

Disposition B — Queued direction

The work lands in queued-directions/ as a deferred item. When the friction surfaces enough to be load-bearing (e.g., the Operator needs to read a PDF in record.dunin7.com and the placeholder is genuinely in the way), the queued direction converts to a small phase or rides along with another phase.

Disposition C — Absorbed into Phase 63

Phase 63's CR already exists in v0.1 form (phases/phase-63-editor-refinement/loomworks-phase-63-cr-v0_1.html). The binary-reader work could be added as a fourth piece. This is probably wrong — Phase 63 is already comprehensive and is stress-testing the visual-classification system; adding more would dilute the focus.

Recommendation

Disposition B (queued direction) for now, with the option to promote to Disposition A (Phase 64) if friction surfaces. Reasoning:

If the Operator's intuition is that view support should land sooner — the placeholder is more friction than it appears — Disposition A is also defensible. The investigation supports either path.


8 · Recommended next actions

If the Operator selects Disposition B (queued): the investigation lands in investigations/ and is referenced from queued-directions/loomworks-queued-directions-and-deferred-work-v0_12.md (or the current version) as "Binary-format view support — see investigation v0.1." No further action until friction surfaces.

If the Operator selects Disposition A (Phase 64): this investigation becomes the substantive scoping material for Phase 64. A scoping note would resolve §5's open questions and §3's recommendation choices into Settled decisions; a Step 0 inspection would verify the [inferred] claims about the build script by reading the actual code; a CR would draft the 8-12 execution steps with acceptance gates. The phase would likely close in a single cycle without halts given the bounded scope.

If the Operator selects Disposition C (absorb into Phase 63): the investigation becomes amendment material for the Phase 63 CR. Probably wrong path per the reasoning above, but technically possible.

A small CC inspection step would meaningfully tighten this investigation regardless of disposition: read tools/build_site.py for the actual binary-document handling code, confirm or correct the [inferred] claims, identify the exact file paths and template structures touched by §4's execution sketch. About 5-10 minutes of CC time. Should be done before any execution work opens regardless of disposition.


DUNIN7 · Done In Seven LLC · Miami, Florida Loomworks Record · Binary-Reader Investigation · v0.1 · 2026-05-23