import {useEffect,useRef,useState} from 'react'; import {useMotion} from './Motion'; import {DualScene} from './DualScene'; import {beats,beatIndex,phase,residuePreviewCount} from './dualStory'; import {useScrollStory} from './useScrollStory'; import type {Example} from './types'; import config from '../t5config_large.json'; function MiniBlock({protein=false,decoder=false}:{protein?:boolean;decoder?:boolean}) { return
{protein?'Protein':'Text'} {decoder?'Decoder':'Encoder'}×{decoder?config.num_decoder_layers:config.num_layers}

{decoder?'Masked self-attention':'Self-attention'}

{decoder&&

Cross-attention ← projected context

}

Feed-forward

; } function Vector({protein=false}:{protein?:boolean}) {return {Array.from({length:18},(_,i)=>)};} function ReadingVisual({index,example}:{index:number;example:Example}) { if (index===0) return
REFERENCE DESCRIPTION
{example.text}
↓ Encode the description
; if (index===1) return
→
Linear Wₜ→ₚ{config.d_model} → {config.d_model}
→

Hidden states become the decoder’s context.

↓ Read through cross-attention
; if (index===2) return
↓ Autoregressive output
{example.generatedProtein.slice(0,residuePreviewCount).split('').map((s,i)=>{s})}

First {residuePreviewCount} of {example.generatedProtein.length} generated residues.

; if (index===3) return
REFERENCE SEQUENCE · INDEPENDENT INPUT
{example.protein.slice(0,16).split('').map((s,i)=>{s})}
↓ Encode the original protein
↓
→
Linear Wₚ→ₜSeparate learned projection
→
; if (index===4) return
↓ Recorded text output
{example.generatedText.replace(/([.!?])(?=[A-Z])/g,'$1 ').split(/\s+/).map((word,i)=>{word})}
; return
TEXT → PROTEIN

Text Encoder↓ Wₜ→ₚProtein Decoder

PROTEIN → TEXT

Protein Encoder↓ Wₚ→ₜText Decoder

Text Encoder ↔ Text Decoder
Same text self-attention weights

Protein Encoder ↔ Protein Decoder
Same protein self-attention weights

Corresponding blocks 1–24 within each modality.
L = ½ L(text → protein)
+ ½ L(protein → text)
; } export function DualLearning({example}:{example:Example}) { const {enabled,reduced,paused:pagePaused}=useMotion(); const [small,setSmall]=useState(()=>matchMedia('(max-width: 1100px), (max-height: 640px)').matches); const [readAll,setReadAll]=useState(false),[paused,setPaused]=useState(false); const section=useRef(null),stage=useRef(null); const flow=small||reduced||readAll; const {progress,seek}=useScrollStory(section,stage,enabled&&!paused,flow); const active=beatIndex(progress); useEffect(()=>{ const query=matchMedia('(max-width: 1100px), (max-height: 640px)'); const update=()=>setSmall(query.matches); query.addEventListener('change',update); return()=>query.removeEventListener('change',update); },[]); return

01 INSIDE OUROBOROS

One example.
Two ways to learn.

Follow a function into a protein.
Then follow a protein into language.

{flow?'SIX STEPS THROUGH DUAL LEARNING':'SCROLL TO EXPLORE · SCROLL BACK TO REVISIT'}
{flow?
{!small&&!reduced&&} {beats.map((beat,i)=>
{beat.tag}

{beat.title}

{beat.body}

{beat.note}
)}
:
THE DUAL LEARNING FRAMEWORK
{paused||pagePaused?'PAUSED · USE CHAPTERS TO STEP':'SCROLL TO ADVANCE OR DRAG'}seek(Number(e.target.value)/1000)} aria-label="Explanation progress" aria-valuetext={`Step ${active+1} of 6: ${beats[active].label}`}/>{String(active+1).padStart(2,'0')} / 06
}
RECORDED EXAMPLE

Two independent predictions from the reference description and reference sequence. Animation timing is illustrative; training uses paired supervision, not cycle reconstruction.

Source data ↗
Inspect the complete example Reference inputs & archived predictions +
01 / TEXT → PROTEIN

Reference description

{example.text}

Generated protein · {example.generatedProtein.length} residues

{example.generatedProtein}

02 / PROTEIN → TEXT

Reference protein · {example.protein.length} residues

{example.protein}

Generated description

{example.generatedText}

Architecture & training notes +

Each large-v5 encoder and decoder contains {config.num_layers} T5-style blocks with hidden size {config.d_model.toLocaleString('en-US')}. Encoders use self-attention and feed-forward layers; decoders add masked self-attention and cross-attention to the projected source states. The diagram expands a representative block, omitting residual connections and layer normalization for clarity. Hidden-state squares illustrate vectors; their values are not measured activations.

The original model jointly optimizes two autoregressive, teacher-forced cross-entropy losses. Corresponding encoder/decoder self-attention parameters are shared within each modality. The two linear projections are initialized as transposes and optimized independently. The displayed predictions are archived inference outputs, not a visualization of teacher forcing. Word chips are readable excerpts, not T5 subword boundaries.

; }