From 9547beb8e96e0d1d771e31b51ece6472c2c91d41 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 20:48:16 +0300 Subject: [PATCH 01/20] =?UTF-8?q?fix(interpolare):=20Lagrange=20r=C4=83m?= =?UTF-8?q?=C3=A2ne=20cu=20o=20singur=C4=83=20linie=20pe=20desen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multiplicatorul nu se mai trasa de la commit-ul trecut, dar restul piesei rămăsese pe loc: `multiplicatorLagrange` importat degeaba, `kAles` folosit după ce fusese șters — de aici și eroarea de tipuri —, iar legenda anunța în continuare o curbă și un nod care nu mai apar nicăieri. Evidențierea din formulă trece de pe `l_k(x)` pe `P_n(x)`: pe grafic e o singură linie, iar aceea e suma, nu multiplicatorul. Produsul rămâne scris, fiindcă el spune din ce e făcută suma. Descrierea pentru cititorul de ecran spune același lucru ca desenul: o linie prin toate nodurile, cu abaterea maximă față de funcție. --- .../content/InterfataInterpolare.tsx | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/components/content/InterfataInterpolare.tsx b/src/components/content/InterfataInterpolare.tsx index a736004..e9f9c7a 100644 --- a/src/components/content/InterfataInterpolare.tsx +++ b/src/components/content/InterfataInterpolare.tsx @@ -4,11 +4,7 @@ import { FUNCTII_INTERPOLATE, getFunctieInterpolata, } from "@/algorithms/interpolare-polinomiala/functii-interpolare"; -import { - esantioneaza, - multiplicatorLagrange, - polinomLagrange, -} from "@/algorithms/interpolare-polinomiala/lagrange"; +import { esantioneaza, polinomLagrange } from "@/algorithms/interpolare-polinomiala/lagrange"; import { schemaNeville, valoareNeville } from "@/algorithms/interpolare-polinomiala/neville"; import { evalueazaSpline, @@ -105,11 +101,11 @@ function extremele(valori: readonly number[]): [number, number] { /** * Interfața interactivă a paginii 12. * - * **Un singur desen, patru întrebări.** Nodurile, funcția și cadrul rămân + * **Un singur desen, trei întrebări.** Nodurile, funcția și cadrul rămân * aceleași de la o filă la alta; se schimbă doar ce se desenează peste ele: - * multiplicatorul unui nod, nivelurile schemei Neville, oscilația de la capete - * sau bucățile spline-ului. Așa se vede că Lagrange și Neville dau **același** - * polinom, iar spline-ul e altceva — nu patru pagini care nu se ating. + * polinomul întreg, nivelurile schemei Neville sau bucățile spline-ului. Așa se + * vede că Lagrange și Neville dau **același** polinom, iar spline-ul e altceva — + * nu trei pagini care nu se ating. * * **Nodurile se trag cu mâna** (`PlotPunctTras`), în afara filei cu funcția * Runge: acolo fenomenul e chiar despre noduri echidistante, iar unul mutat cu @@ -339,7 +335,6 @@ export function InterfataInterpolare() { nivel: nivelAles, xEval, rezultat: schema.rezultat, - k: kAles, tipSpline, })} inaltimeMaxima={460} @@ -660,8 +655,12 @@ function etichetaFilei(fila: Fila): string { function formulaFilei(fila: Fila, tipSpline: TipSpline): string { if (fila === "lagrange") { + // Evidențiat e **polinomul**, nu multiplicatorul: pe desen se trasează o + // singură linie, iar aceea e suma din stânga. Un `l_k` aprins în formulă ar + // fi trimis ochiul să caute pe grafic o curbă care nu mai există. Produsul + // rămâne scris, fiindcă el spune din ce e făcută suma. return ( - "P_n(x) = \\sum_{k=0}^{n} f(x_k)\\, \\htmlId{multiplicator}{l_k(x)}, \\qquad " + + "\\htmlId{polinom}{P_n(x)} = \\sum_{k=0}^{n} f(x_k)\\, l_k(x), \\qquad " + "l_k(x) = \\prod_{\\substack{i=0 \\\\ i \\neq k}}^{n} \\frac{x - x_i}{x_k - x_i}" ); } @@ -683,7 +682,7 @@ function formulaFilei(fila: Fila, tipSpline: TipSpline): string { } function evidentiereaFilei(fila: Fila, nivel: number): string[] { - if (fila === "lagrange") return ["multiplicator"]; + if (fila === "lagrange") return ["polinom"]; if (fila === "neville") return nivel === 0 ? [] : ["pondere-stanga", "pondere-dreapta"]; return ["capete"]; } @@ -750,13 +749,6 @@ function legendaFilei(fila: Fila, tipSpline: TipSpline): ElementLegenda[] { forma: "linie", explicatie: "Suma multiplicatorilor, fiecare ponderat cu valoarea din nodul lui.", }, - { - rol: "interval", - eticheta: "multiplicatorul lₖ al nodului ales", - forma: "linie", - explicatie: "Trece prin 1 în nodul lui și prin 0 în toate celelalte.", - }, - { rol: "pivot", eticheta: "nodul ales și valoarea lₖ(xₖ) = 1", forma: "punct" }, ]; } @@ -821,7 +813,6 @@ function descrieDesenul({ nivel, xEval, rezultat, - k, tipSpline, }: { fila: Fila; @@ -833,7 +824,6 @@ function descrieDesenul({ nivel: number; xEval: number; rezultat: number; - k: number; tipSpline: TipSpline; }): string { const n = noduri.length - 1; @@ -841,8 +831,8 @@ function descrieDesenul({ if (fila === "lagrange") { return ( - `${comun} Se vede multiplicatorul nodului ${k}: valorează 1 în nodul lui și 0 în celelalte. ` + - `Polinomul de interpolare se abate de funcție cu cel mult ${zecimale(eroarePolinom, 4)}.` + `${comun} Se vede o singură linie, polinomul de interpolare: trece prin toate cele ` + + `${noduri.length} noduri și se abate de funcție cu cel mult ${zecimale(eroarePolinom, 4)}.` ); } if (fila === "neville") { From 61666e6e280c19a22aa100c67cf947437d27fc06 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 20:49:33 +0300 Subject: [PATCH 02/20] =?UTF-8?q?fix(interpolare):=20nivelurile=20lui=20Ne?= =?UTF-8?q?ville=20se=20iau=20cu=20s=C4=83ge=C8=9Bile,=20sub=20desen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bara de derulare și `useDerulare` erau folosite în JSX de la commit-ul trecut, dar nu fusese importat niciunul, deci fișierul nu compila deloc. Odată cu ele: - legenda scapă de „verticala punctului evaluat" și de „P₀ₙ(x)" — niciuna nu se mai desenează, iar `PlotDreapta` nu mai e importat degeaba; - intrarea rămasă spune și de punctele de pe curbe, ca legenda să acopere tot ce se vede; - graficul urcă de la 460 la 560 de pixeli, adică exact locul lăsat liber de triunghiul mutat sub bara de derulare. Până acum tabelul creștea cu fiecare nivel și împingea desenul în sus, deci graficul era cel mai mic tocmai la pasul în care se vede toată schema. --- src/components/content/InterfataInterpolare.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/content/InterfataInterpolare.tsx b/src/components/content/InterfataInterpolare.tsx index e9f9c7a..0acfeba 100644 --- a/src/components/content/InterfataInterpolare.tsx +++ b/src/components/content/InterfataInterpolare.tsx @@ -32,11 +32,12 @@ import { ControlPanel } from "@/components/viz/ControlPanel"; import { FormulaBlock } from "@/components/viz/FormulaBlock"; import { Legend, type ElementLegenda } from "@/components/viz/Legend"; import { Notatie } from "@/components/viz/Notatie"; +import { PlaybackBar } from "@/components/viz/PlaybackBar"; import { Plot } from "@/components/viz/Plot"; import { PlotCurba } from "@/components/viz/PlotCurba"; -import { PlotDreapta } from "@/components/viz/PlotDreapta"; import { PlotPunct } from "@/components/viz/PlotPunct"; import { PlotPunctTras } from "@/components/viz/PlotPunctTras"; +import { useDerulare } from "@/hooks/use-derulare"; import { zecimale } from "@/lib/numere"; import { cn } from "@/lib/utils"; @@ -321,6 +322,11 @@ export function InterfataInterpolare() {
+ {/* Cei 100 de pixeli în plus la înălțime sunt chiar locul lăsat + liber de triunghiul lui Neville, mutat sub bara de derulare: + până acum tabelul creștea cu fiecare nivel calculat și împingea + desenul în sus, adică graficul era cel mai mic exact la pasul + unde se vede tot. */} {/* Funcția de la care s-au luat nodurile. Punctată: nu e ce calculează metoda, ci ce ar vrea să nimerească. */} @@ -760,10 +766,9 @@ function legendaFilei(fila: Fila, tipSpline: TipSpline): ElementLegenda[] { rol: "interval", eticheta: "polinoamele Pᵢⱼ de pe nivelul ales", forma: "linie", - explicatie: "Fiecare e trasat doar peste nodurile din care iese.", + explicatie: + "Fiecare e trasat doar peste nodurile din care iese, cu un punct acolo unde e evaluat.", }, - { rol: "grila", eticheta: "verticala punctului evaluat", forma: "linie-punctata" }, - { rol: "solutie", eticheta: "P₀ₙ(x), rezultatul schemei", forma: "punct" }, ]; } From 56e30a66cd9062f766ab709a5f1cccb98a6b679c Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 20:50:45 +0300 Subject: [PATCH 03/20] =?UTF-8?q?fix(interpolare):=20scoase=20=C8=99i=20ul?= =?UTF-8?q?timele=20urme=20ale=20filei=20Runge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fila dispăruse din listă, dar ramurile ei rămăseseră în cod: o legendă proprie și o descriere pentru cititorul de ecran, amândouă comparate cu un tip de filă care nu mai există — de aici cele două erori de tipuri. Cu ele pleacă și `amplitudine`, singura cifră pe care o folosea doar Runge. `schimbaFila` fusese ștearsă, dar tabul o chema în continuare; nu mai are ce face, fiindcă niciuna dintre cele trei file nu-și mai aduce funcția ei, deci rămâne `setFila`. Cu asta, proiectul compilează din nou: `npm run typecheck` și `npm run lint` trec amândouă. --- .../content/InterfataInterpolare.tsx | 41 ++++--------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/src/components/content/InterfataInterpolare.tsx b/src/components/content/InterfataInterpolare.tsx index 0acfeba..e945f1c 100644 --- a/src/components/content/InterfataInterpolare.tsx +++ b/src/components/content/InterfataInterpolare.tsx @@ -108,9 +108,10 @@ function extremele(valori: readonly number[]): [number, number] { * vede că Lagrange și Neville dau **același** polinom, iar spline-ul e altceva — * nu trei pagini care nu se ating. * - * **Nodurile se trag cu mâna** (`PlotPunctTras`), în afara filei cu funcția - * Runge: acolo fenomenul e chiar despre noduri echidistante, iar unul mutat cu - * degetul ar desființa exemplul. + * **Nodurile se trag cu mâna** (`PlotPunctTras`), pe toate filele. Fila cu + * funcția Runge, singura pe care nodurile stăteau pe loc — acolo fenomenul e + * chiar despre noduri echidistante —, a fost scoasă la cerere; funcția rămâne + * în lista din panou, deci oscilația se poate vedea în continuare. * * Matematica nu stă aici: vine din `src/algorithms/interpolare-polinomiala/`. */ @@ -309,7 +310,10 @@ export function InterfataInterpolare() { activa={FILE.findIndex((f) => f.id === fila)} /> - schimbaFila(v as Fila)}> + {/* Schimbarea filei nu mai atinge nodurile: toate trei lucrează pe funcția + aleasă din panou, deci nu mai există filă care să-și aducă funcția ei + și să le reașeze pe alta. */} + setFila(v as Fila)}> {FILE.map((f) => ( @@ -337,7 +341,6 @@ export function InterfataInterpolare() { noduri, eroarePolinom, eroareSpline, - amplitudine, nivel: nivelAles, xEval, rezultat: schema.rezultat, @@ -772,25 +775,6 @@ function legendaFilei(fila: Fila, tipSpline: TipSpline): ElementLegenda[] { ]; } - if (fila === "runge") { - return [ - LEGENDA_FUNCTIE, - { rol: "anterior", eticheta: "nodurile echidistante", forma: "punct" }, - { - rol: "curent", - eticheta: "polinomul de interpolare Pₙ", - forma: "linie", - explicatie: "Un singur polinom, pe tot intervalul.", - }, - { - rol: "solutie", - eticheta: "spline-ul cubic, pe aceleași noduri", - forma: "linie", - explicatie: "Câte o cubică pe fiecare subinterval, lipite în noduri.", - }, - ]; - } - return [ LEGENDA_FUNCTIE, LEGENDA_NODURI_TRASE, @@ -814,7 +798,6 @@ function descrieDesenul({ noduri, eroarePolinom, eroareSpline, - amplitudine, nivel, xEval, rezultat, @@ -825,7 +808,6 @@ function descrieDesenul({ noduri: readonly Nod[]; eroarePolinom: number; eroareSpline: number; - amplitudine: number; nivel: number; xEval: number; rezultat: number; @@ -846,13 +828,6 @@ function descrieDesenul({ `x = ${zecimale(xEval, 3)}. Rezultatul întregii scheme acolo e ${zecimale(rezultat, 5)}.` ); } - if (fila === "runge") { - return ( - `${comun} Nodurile sunt echidistante. Polinomul urcă până la ${zecimale(amplitudine, 3)} ` + - `și se abate de funcție cu ${zecimale(eroarePolinom, 4)}; spline-ul cubic pe aceleași ` + - `noduri se abate doar cu ${zecimale(eroareSpline, 4)}.` - ); - } return ( `${comun} Spline-ul ${tipSpline === "natural" ? "natural" : "tensionat"} se abate de funcție ` + `cu cel mult ${zecimale(eroareSpline, 4)}.` From 86426bfee2151e2b306faac2fb86ba612c98ab9a Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 20:55:56 +0300 Subject: [PATCH 04/20] =?UTF-8?q?fix(interpolare):=20diferen=C8=9Ba=20dint?= =?UTF-8?q?re=20spline-ul=20natural=20=C8=99i=20cel=20tensionat=20se=20ved?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cele două curbe se desenau deja una peste alta de la commit-ul trecut, dar pe sinusoidă asta nu ajuta: la numărul implicit de noduri stau la **doi pixeli** una de alta, iar de la nouă noduri se suprapun exact. Fila arăta o singură linie și cerea să se creadă că sunt două. Măsurat ca depărtare maximă, transformată în pixeli pe înălțimea desenului: | noduri | 4 | 5 | 7 | 9 | 13 | | --------- | ---- | ---- | ---- | ---- | ---- | | sin(πx) | 8 | 2 | 0 | 0 | 0 | | x⁵ − 2x³ | 12 | 10 | 5 | 3 | 1,5 | Deci funcția de start devine `x⁵ − 2x³`, cum lăsa deschis nota. Celelalte două file nu pierd nimic: polinomul de interpolare nu iese din cadru la niciun număr de noduri (`max |Pₙ| = 1`, cât funcția însăși), iar de la șase noduri o reproduce exact. Legenda numește acum și curba punctată — până acum desenul avea două linii și legenda una singură. Lângă `s″(x₀)`, care spune **de ce** se despart curbele, apare și `depărtarea`, care spune **cu cât**; scrisă în cuvânt, fiindcă al doilea spline n-are simbol în curs. Cu trei noduri, cele două curbe coincid exact: `(−1, 1)`, `(0, 0)` și `(1, −1)` sunt coliniare, deci amândouă condițiile dau dreapta `y = −x`. Nu e o scăpare de calcul, e adevărat, și e scris în cod. `max |s − f|` ceruta la scos era deja plecată. --- .../content/InterfataInterpolare.tsx | 74 ++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/src/components/content/InterfataInterpolare.tsx b/src/components/content/InterfataInterpolare.tsx index e945f1c..4115c03 100644 --- a/src/components/content/InterfataInterpolare.tsx +++ b/src/components/content/InterfataInterpolare.tsx @@ -74,12 +74,31 @@ const ESANTIOANE = 400; /** * Funcția cu care pornește interfața. * - * Sinusoida: polinomul stă lipit de curbă, deci se vede lucrul pe care îl arată - * fila, nu oscilația de la capete. E și funcția pe care cele două condiții de - * capăt ale spline-ului se despart cel mai tare — panta ei la capete e `±π`, - * iar spline-ul natural o ignoră din construcție. + * `x⁵ − 2x³`, fiindcă pe ea se vede diferența dintre cele două condiții de + * capăt ale spline-ului — singurul lucru de pe pagină care se citește doar + * comparând două curbe. Diferența dintre ele, măsurată ca depărtare maximă și + * transformată în pixeli pe înălțimea desenului: + * + * | noduri | 4 | 5 | 7 | 9 | 13 | + * | --------- | ---- | ---- | ---- | ---- | ---- | + * | sin(πx) | 8 | 2 | 0 | 0 | 0 | + * | x⁵ − 2x³ | 12 | 10 | 5 | 3 | 1,5 | + * + * Pe sinusoidă, la numărul implicit de noduri, cele două curbe stau la **doi + * pixeli** una de alta, iar de la nouă noduri se suprapun exact — adică fila + * arăta o singură linie și cerea să se creadă că sunt două. Pe polinom rămân + * despărțite pe aproape tot intervalul cursorului. + * + * Celelalte două file nu pierd nimic: polinomul de interpolare nu iese din + * cadru la niciun număr de noduri (`max |Pₙ| = 1`, cât funcția însăși), iar de + * la șase noduri îl reproduce exact — pe puncte distincte, polinomul de grad + * cel mult `n` care trece prin ele e unic. + * + * Singurul loc unde nu se vede nimic e capătul de jos al cursorului: cu trei + * noduri, `(−1, 1)`, `(0, 0)` și `(1, −1)` sunt coliniare, deci amândouă + * condițiile dau chiar dreapta `y = −x`. Nu e o scăpare de calcul, e adevărat. */ -const FUNCTIE_IMPLICITA = "sinusoida"; +const FUNCTIE_IMPLICITA = "polinom"; /* ───────────────────────── cadrul de desen ───────────────────────── */ @@ -260,6 +279,24 @@ export function InterfataInterpolare() { () => abatereMaxima((x) => evalueazaSpline(spline, x), functie.f, [a, b], 2000), [spline, functie, a, b], ); + + /** + * Cât de departe ajung una de alta cele două condiții de capăt. + * + * E cifra care spune dacă mai e ceva de văzut pe desen: sub câțiva pixeli, + * curbele se suprapun, iar asta nu se poate deosebi cu ochiul de o pană a + * interfeței. Se măsoară doar pe suportul nodurilor, unde spline-ul e definit. + */ + const departareaSplineurilor = useMemo( + () => + abatereMaxima( + (x) => evalueazaSpline(spline, x), + (x) => evalueazaSpline(splineCealalta, x), + [noduri[0]!.x, noduri[n]!.x], + 2000, + ), + [spline, splineCealalta, noduri, n], + ); /* ── mutarea unui nod ─────────────────────────────────────────────── */ const mutaNodul = (i: number, punct: Punct) => { @@ -341,6 +378,7 @@ export function InterfataInterpolare() { noduri, eroarePolinom, eroareSpline, + departare: departareaSplineurilor, nivel: nivelAles, xEval, rezultat: schema.rezultat, @@ -522,10 +560,10 @@ export function InterfataInterpolare() { fila, n, eroarePolinom, - eroareSpline, schema, nivel: nivelAles, spline, + departareaSplineurilor, noduri, }).map(([cheie, valoare]) => (
; nivel: number; spline: ReturnType; + departareaSplineurilor: number; noduri: readonly Nod[]; }): [string, string][] { if (fila === "lagrange") { @@ -729,6 +768,11 @@ function cifrele({ return [ ["bucăți", String(Math.max(0, noduri.length - 1))], ["s″(x₀)", zecimale(2 * (spline.c[0] ?? 0), 3)], + // Cifra care spune cât de mare e diferența pe care fila o desenează: + // `s″(x₀)` arată **de ce** se despart curbele, asta arată **cu cât**. + // Scrisă în cuvânt, nu ca `max |s − s̃|`: al doilea spline n-are simbol în + // curs, iar unul inventat aici ar cere el însuși o legendă. + ["depărtarea", zecimale(departareaSplineurilor, 4)], ]; } @@ -787,6 +831,13 @@ function legendaFilei(fila: Fila, tipSpline: TipSpline): ElementLegenda[] { ? "Curbura se anulează la capete." : "Panta de la capete e chiar cea a funcției.", }, + { + rol: "interval", + eticheta: tipSpline === "natural" ? "spline-ul tensionat" : "spline-ul natural", + forma: "linie-punctata", + explicatie: + "Cealaltă condiție de capăt, pe aceleași noduri: singura piesă cu care se compară.", + }, ]; } @@ -798,6 +849,7 @@ function descrieDesenul({ noduri, eroarePolinom, eroareSpline, + departare, nivel, xEval, rezultat, @@ -808,6 +860,7 @@ function descrieDesenul({ noduri: readonly Nod[]; eroarePolinom: number; eroareSpline: number; + departare: number; nivel: number; xEval: number; rezultat: number; @@ -828,8 +881,11 @@ function descrieDesenul({ `x = ${zecimale(xEval, 3)}. Rezultatul întregii scheme acolo e ${zecimale(rezultat, 5)}.` ); } + const ales = tipSpline === "natural" ? "natural" : "tensionat"; + const celalalt = tipSpline === "natural" ? "tensionat" : "natural"; return ( - `${comun} Spline-ul ${tipSpline === "natural" ? "natural" : "tensionat"} se abate de funcție ` + - `cu cel mult ${zecimale(eroareSpline, 4)}.` + `${comun} Spline-ul ${ales} se abate de funcție cu cel mult ` + + `${zecimale(eroareSpline, 4)}. Punctat, pe aceleași noduri, e spline-ul ${celalalt}: ` + + `cele două se depărtează una de alta cu cel mult ${zecimale(departare, 4)}.` ); } From 16cefba140cf76306f8048d5a7bdee365eb845c6 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:04:09 +0300 Subject: [PATCH 05/20] =?UTF-8?q?fix(interpolare):=20graficul=20lui=20Nevi?= =?UTF-8?q?lle=20chiar=20cre=C8=99te,=20prin=20raport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plafonul de înălțime ridicat în commit-ul de acum două trepte n-a mișcat niciun pixel: măsurat în browser, coloana din stânga se oprește la 707px și nu crește nici pe ecran de 1536px, deci înălțimea ieșea din raportul de formă — `707 / 1,6 = 442px` —, iar plafonul nu era atins la nicio lățime. Cu `raport = 1,3` desenul urcă de la **442px la 544px**, verificat la 1280px și 1536px. Plafonul rămâne pus, ca înălțimea să nu treacă de rândul de cifre de alături. --- package-lock.json | 14 ++++++++++++++ package.json | 1 + src/components/content/InterfataInterpolare.tsx | 16 +++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e0b1035..5892981 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.4", "oxlint": "^1.75.0", + "playwright-core": "^1.62.1", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", "tailwindcss": "^4.3.3", @@ -3385,6 +3386,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/package.json b/package.json index d8edb57..9cfe35e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.4", "oxlint": "^1.75.0", + "playwright-core": "^1.62.1", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", "tailwindcss": "^4.3.3", diff --git a/src/components/content/InterfataInterpolare.tsx b/src/components/content/InterfataInterpolare.tsx index 4115c03..8349846 100644 --- a/src/components/content/InterfataInterpolare.tsx +++ b/src/components/content/InterfataInterpolare.tsx @@ -363,11 +363,16 @@ export function InterfataInterpolare() {
- {/* Cei 100 de pixeli în plus la înălțime sunt chiar locul lăsat - liber de triunghiul lui Neville, mutat sub bara de derulare: - până acum tabelul creștea cu fiecare nivel calculat și împingea - desenul în sus, adică graficul era cel mai mic exact la pasul - unde se vede tot. */} + {/* Locul lăsat liber de triunghiul lui Neville, mutat sub bara de + derulare, se dă graficului — dar prin `raport`, nu prin + `inaltimeMaxima`. + + Măsurat: coloana din stânga se oprește la 707px și nu crește + nici pe ecran de 1536px, deci înălțimea ieșea din `707 / 1,6 = + 442px`. Plafonul nu era atins la nicio lățime, adică ridicat + singur n-ar fi mișcat niciun pixel. Cu `1,3` ies 544px, iar + plafonul rămâne pus ca să nu urce mai mult decât rândul de + cifre de alături. */} {/* Funcția de la care s-au luat nodurile. Punctată: nu e ce From 53fd8e3aa57d4ad7a639499c99e2d9920ecb0e42 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:09:57 +0300 Subject: [PATCH 06/20] =?UTF-8?q?docs:=20lista=20din=20imbunatatiri.md=20e?= =?UTF-8?q?=20terminat=C4=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Punctele rămase erau toate pe pagina 12; celelalte fuseseră deja bifate în trecerea a doua și s-au verificat una câte una în browser: Newton-Cotes scrie „Subintervale N = 4" cu cifra lângă literă și `h` separat la dreapta, cuadraturile pornesc pe `√x` cu fila scrisă „Cuadraturi Adaptive", derivarea are graficul pe toată lățimea, iar eliminarea gaussiană ține `|aᵢₚ|` pe aceeași linie cu matricea, amândouă mărite. `Progress.md` primește secțiunea trecerii a treia, cu măsurătorile care au schimbat două decizii: plafonul de înălțime nu era atins la nicio lățime, iar cele două condiții de capăt ale spline-ului stăteau la doi pixeli una de alta pe funcția de dinainte. Notat acolo și ce am găsit pe drum, dar nu ține de listă: `PlotDreapta` scrie `undefined` în capete la primul cadru, pe `derivare-numerica` și pe `ecuatii-neliniare`. --- Progress.md | 41 +++++++++++++++++++++++++++++++++++++++++ imbunatatiri.md | 34 ++++------------------------------ 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/Progress.md b/Progress.md index 2486d0d..4c55b02 100644 --- a/Progress.md +++ b/Progress.md @@ -650,6 +650,47 @@ Lista rescrisă de utilizator după prima trecere. Ce s-a schimbat: atunci; propoziția pasului a dispărut de pe Neville; fila spline nu mai desenează și polinomul de comparație; nodurile pornesc de la 5 și își scriu numele doar până la 5. +### A treia trecere prin `imbunatatiri.md` (17 august 2026) + +Lista fusese bifată aproape toată în trecerea a doua, dar `InterfataInterpolare.tsx` rămăsese +**la jumătate de refactorizare și nu compila**: `useDerulare` și `PlaybackBar` erau folosite fără +să fie importate, `schimbaFila`, `kAles` și `amplitudine` fuseseră șterse dar erau încă chemate, +iar filei Runge îi rămăseseră ramurile de legendă și de descriere. Zece erori de tipuri, deci nici +`npm run build` nu trecea. Ce s-a terminat: + +- **Lagrange, o singură linie.** Evidențierea din formulă s-a mutat de pe `l_k(x)` pe `P_n(x)`: + multiplicatorul nu se mai desenează, deci nu mai are ce aprinde pe grafic. Legenda a scăpat de + cele două intrări rămase fără desen. +- **Neville, pași cu săgeți.** Bara de derulare și triunghiul stau sub desen; legenda a scăpat de + „verticala punctului evaluat" și de „P₀ₙ(x)", niciuna desenată. +- **Graficul crește prin `raport`, nu prin plafon.** Plafonul ridicat de la 460 la 560 **nu mișcase + niciun pixel**: măsurat în browser, coloana din stânga se oprește la 707px și nu crește nici pe + 1536px, deci înălțimea ieșea din `707 / 1,6 = 442px`, iar plafonul nu era atins la nicio lățime. + Cu `raport = 1,3` se ajunge la **544px**. **De reținut**: `inaltimeMaxima` e o limită, nu o + cerere — cine vrea un desen mai înalt schimbă `raport`. +- **Spline-ul se vede că are două curbe.** Aici măsurătoarea a schimbat decizia. Desenarea + amândurora, făcută în trecerea trecută, nu ajunge: pe `sin(πx)`, la numărul implicit de noduri, + cele două condiții de capăt stau la **2px** una de alta, iar de la nouă noduri se suprapun exact. + + | noduri | 4 | 5 | 7 | 9 | 13 | + | -------- | --- | --- | --- | --- | --- | + | sin(πx) | 8 | 2 | 0 | 0 | 0 | + | x⁵ − 2x³ | 12 | 10 | 5 | 3 | 1,5 | + + Deci funcția de start a devenit `x⁵ − 2x³`. Celelalte două file nu pierd nimic: `max |Pₙ| = 1` + la orice număr de noduri, iar de la șase noduri polinomul reproduce funcția exact. Legenda + numește acum și curba punctată, iar lângă `s″(x₀)` („de ce") stă `depărtarea` („cu cât"). + + Cu trei noduri cele două curbe coincid **exact**: `(−1, 1)`, `(0, 0)`, `(1, −1)` sunt coliniare, + deci amândouă condițiile dau dreapta `y = −x`. Verificat, nu e o scăpare de calcul. + +Verificat în browser, pe ambele teme, la 360px și 1280px, cu `prefers-reduced-motion`: fără erori +în consolă și fără derulare orizontală. + +**Rămâne de reparat, în afara listei:** `PlotDreapta` scrie `undefined` în `x1/x2/y1/y2` la primul +cadru (`motion.line` cu `animate` și fără valori statice), deci consola primește patru erori pe +`derivare-numerica` și pe `ecuatii-neliniare`. E mai vechi decât lista și nu ține de ea. + ### Pagina 13 — `curbe-bezier`, ce e gata și ce nu Ce există: diff --git a/imbunatatiri.md b/imbunatatiri.md index 6c937ff..826ddcd 100644 --- a/imbunatatiri.md +++ b/imbunatatiri.md @@ -1,32 +1,6 @@ -# De schimbat la Cuadraturi: -La interactiv: -1. La Gaussiene, pune prima functie radical(x) -2. Scrie titlul de la Cuadraturi adaptive "Cuadraturi Adaptive" - - -# De schimbat la Newton-Cotes: -Probleme Persistente: -e descentrata partea de sub grafic: SubintervaleN 4h = 0,7854. 4 ar trebui sa stea langa N - - - -# De schimbat la Derivare Numerica: -La interactiv: -1. Fa mai mare graficul, acum e decentrat cu parametrii - - -# De schimbat la interpolari: -La interactiv: -1. La Lagrange: imbina multiplicatorul cu polinomul doar intr-o singura linie, unde sa se vada frumos cum se schimba polinomul la mai multe puncte -2. La Neville: partea cu pasi fa-o sub grafic, nu ca parametru, sa se ruleze cu sagetele. Partea de grade scoate-o sub partea de derulare, iar in locul ei fa graficul mai mare. Scoate partea cu verticala punctului evaluat. Scoate P0n(x) -3. Scoate partea cu functia Runge de tot din interactiv -4. La Spline fa cumva sa se vada mai bine diferenta intre natural si tensionat. Scoate si max |s − f| -0,0200. Schimba functia de start daca e nevoie - - -# La Eliminare Gaussiana si pivotari -La interactiv: adu pe aceeasi linie a(ip) si matricea, mareste simbolul de la a(ip) si mareste per total matricea si linia cu pivotii - - +# Îmbunătățiri +Lista e goală: toate punctele scrise aici au fost rezolvate. Ce s-a schimbat la fiecare e scris în +[`Progress.md`](./Progress.md), în secțiunile despre trecerile prin fișierul ăsta. +Aici se scriu punctele următoare. From bd1ea8b964ae9827ca034ccc063ce78093989c6f Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:11:10 +0300 Subject: [PATCH 07/20] =?UTF-8?q?chore:=20scoate=20playwright-core,=20ad?= =?UTF-8?q?=C4=83ugat=20din=20gre=C8=99eal=C4=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instalat local ca să pot verifica paginile în browser; n-are ce căuta în dependențele proiectului, care n-are încă niciun test. --- package-lock.json | 14 -------------- package.json | 1 - 2 files changed, 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5892981..e0b1035 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,6 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.4", "oxlint": "^1.75.0", - "playwright-core": "^1.62.1", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", "tailwindcss": "^4.3.3", @@ -3386,19 +3385,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/playwright-core": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", - "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/package.json b/package.json index 9cfe35e..d8edb57 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.4", "oxlint": "^1.75.0", - "playwright-core": "^1.62.1", "prettier": "^3.9.6", "prettier-plugin-tailwindcss": "^0.8.1", "tailwindcss": "^4.3.3", From bacdfde077f17c993eee85319f9f4eaa6b334582 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:17:16 +0300 Subject: [PATCH 08/20] =?UTF-8?q?fix(teorie):=20explica=C8=9Bia=20literelo?= =?UTF-8?q?r=20se=20rupe=20la=20marginea=20din=20st=C3=A2nga,=20pe=20telef?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sub `sm`, legenda nu mai e grilă pe două coloane: simbolul și sensul lui curg în același paragraf, deci al doilea rând al unei explicații lungi pleacă de la marginea din stânga, nu de sub semnul egal — indentat acolo, arăta ca o intrare nouă, căreia îi lipsește simbolul. Peste `sm` rămâne grila de dinainte, cu semnele egal aliniate: acolo lățimea ajunge și alinierea chiar ajută la citit. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012EvFhxeqEqtCsEsDgRqgN4 --- src/components/content/TeorieScurta.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/components/content/TeorieScurta.tsx b/src/components/content/TeorieScurta.tsx index a1f8e8f..91009fb 100644 --- a/src/components/content/TeorieScurta.tsx +++ b/src/components/content/TeorieScurta.tsx @@ -48,11 +48,18 @@ function Bloc({ bloc }: { bloc: BlocTeorie }) {

Ce înseamnă literele

-
+ {/* Pe telefon nu e grilă: simbolul și explicația curg în același + paragraf, ca al doilea rând al unei explicații lungi să înceapă + de la marginea din stânga, nu de sub semnul egal. Coloana de + explicații are ~200px pe 360px, deci aproape orice sens de două + propoziții se rupe — iar rupt, textul indentat sub „=" arăta ca + o intrare nouă, cu simbolul lipsă. Peste `sm` revine grila, unde + lățimea ajunge și alinierea semnelor egal chiar ajută la citit. */} +
{bloc.legenda.map((intrare) => (
{/* Pe ecran lat, aliniat la dreapta: semnele egal cad unul sub altul, deși simbolurile au lățimi diferite („a" față de @@ -61,13 +68,15 @@ function Bloc({ bloc }: { bloc: BlocTeorie }) { („r = √(x² + y²)") se rupe pe două rânduri: aliniat la dreapta, rândurile lui plecau din locuri diferite și nu se mai vedea unde începe intrarea. */} -
+
{intrare.simbol} -
-
{intrare.sens}
+ {" "} +
+ {intrare.sens} +
))}
From dbd0af8734909ab3f0fcdd10f8b9c4573f3a5158 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:23:24 +0300 Subject: [PATCH 09/20] =?UTF-8?q?fix(derulare):=20s=C4=83geata=20=E2=80=9E?= =?UTF-8?q?pagina=20urm=C4=83toare"=20duce=20la=20titlu,=20nu=20=C3=AEn=20?= =?UTF-8?q?subsol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Poziția salvată se refăcea la orice sosire pe o pagină, indiferent cum ai ajuns acolo. Dar săgețile de navigație stau chiar la **fundul** paginii, deci orice pagină părăsită printr-una din ele își salva poziția „la fund" — iar a doua oară când ajungeai pe ea erai pus înapoi acolo, sub tot conținutul, în loc să vezi titlul. Măsurat pe `interpolare-polinomiala` → `curbe-bezier`, a doua trecere: 6713 din 6966 pe telefon, 5031 din 5031 pe desktop. Se vede mai tare pe telefon, unde paginile sunt de două ori mai înalte și o săgeată se apasă mult mai des decât un buton „înapoi", dar nu era o problemă de telefon. Acum poziția se reface doar la `POP` — înapoi/înainte din browser, adică exact gestul căruia browserul îi reface singur derularea pe un site obișnuit. Un clic pe o legătură e `PUSH`: ai cerut altă pagină, deci o primești de la început. Verificat pe 360px și 1280px: toate cele trei apăsări de săgeată ajung la `scrollY = 0`, „înapoi" din browser reface poziția exactă (6966, respectiv 5031), iar breadcrumb-ul cu ancoră duce mai departe la secțiune, la 96px de marginea de sus. --- src/components/layout/ScrollToTop.tsx | 41 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/components/layout/ScrollToTop.tsx b/src/components/layout/ScrollToTop.tsx index d9e51b7..f83193d 100644 --- a/src/components/layout/ScrollToTop.tsx +++ b/src/components/layout/ScrollToTop.tsx @@ -1,5 +1,5 @@ import { useEffect, useLayoutEffect, useRef } from "react"; -import { useLocation } from "react-router"; +import { useLocation, useNavigationType } from "react-router"; /** * Cât așteptăm să apară elementul-țintă înainte să renunțăm și să mergem în @@ -18,13 +18,26 @@ const ASTEPTARE_TINTA_MS = 2000; const pozitii = new Map(); /** - * La schimbarea rutei pagina pornește de sus — **în afară de paginile pe care - * le-ai mai deschis o dată**, unde se așază unde rămăsese. Pe paginile lungi de - * aici capul paginii e la câteva ecrane distanță de locul din care ai plecat, - * iar plimbarea „ies o clipă, mă întorc" e cea obișnuită: se pleacă din mijlocul - * teoriei la cuprins sau la pagina vecină și se revine tot acolo. Nu contează - * cum te-ai întors — cu butonul „înapoi" al browserului sau printr-un link —, - * fiindcă poziția înseamnă același lucru în amândouă cazurile. + * La schimbarea rutei pagina pornește de sus — **în afară de întoarcerile cu + * butonul „înapoi"/„înainte" al browserului**, unde se așază unde rămăsese. Pe + * paginile lungi de aici capul paginii e la câteva ecrane distanță de locul din + * care ai plecat, iar plimbarea „ies o clipă, mă întorc" e cea obișnuită: se + * pleacă din mijlocul teoriei la cuprins și se revine tot acolo. + * + * **Cum te-ai întors contează**, și asta a fost lecția unui bug: apăsând + * săgeata „pagina următoare" ajungeai direct în subsolul paginii următoare, nu + * la titlul ei. Săgețile de navigație stau chiar la **fundul** paginii, deci + * orice pagină părăsită printr-una din ele își salvează poziția „la fund"; a + * doua oară când ajungeai pe ea, oricum ai fi ajuns, erai pus înapoi la fund. + * Măsurat pe `interpolare-polinomiala` → `curbe-bezier`: a doua trecere te lăsa + * la 6713 din 6966 pe telefon și la 5031 din 5031 pe desktop — adică exact la + * capătul de jos. Se vedea mai tare pe telefon, unde paginile sunt de două ori + * mai înalte, dar nu era o problemă de telefon. + * + * Deci poziția se reface **doar la `POP`** — înapoi/înainte din browser, adică + * gestul căruia browserul însuși îi reface derularea pe un site obișnuit. Un + * clic pe o legătură e `PUSH`: ai cerut altă pagină, deci o primești de la + * început. * * Fără `behavior: "smooth"` — `html { scroll-behavior: smooth }` din * `index.css` ar face un derulaj lung și inutil între pagini. @@ -37,6 +50,7 @@ const pozitii = new Map(); */ export function ScrollToTop() { const { pathname, hash } = useLocation(); + const tipNavigare = useNavigationType(); // Calea și poziția paginii pe care tocmai o părăsim. Amândouă în `ref`-uri, // fiindcă se citesc din curățarea efectului, când `pathname` de mai sus e deja @@ -74,10 +88,11 @@ export function ScrollToTop() { useEffect(() => { if (!hash) { - // Pagina se așază unde era, dacă am mai fost pe ea. Poziția se cere cadru - // cu cadru, din același motiv ca la ancoră — pagina se montează `lazy()`, - // deci în primul cadru documentul e prea scurt ca să se poată derula. - const salvata = pozitii.get(pathname); + // Pagina se așază unde era **doar dacă te-ai întors**, nu ori de câte ori + // ai mai fost pe ea. Poziția se cere cadru cu cadru, din același motiv ca + // la ancoră — pagina se montează `lazy()`, deci în primul cadru + // documentul e prea scurt ca să se poată derula. + const salvata = tipNavigare === "POP" ? pozitii.get(pathname) : undefined; if (salvata) { const limita = performance.now() + ASTEPTARE_TINTA_MS; let cadru = 0; @@ -117,7 +132,7 @@ export function ScrollToTop() { cadru = requestAnimationFrame(incearca); return () => cancelAnimationFrame(cadru); - }, [pathname, hash]); + }, [pathname, hash, tipNavigare]); return null; } From f3c7185c3de601a1f59c7050326d52438eba684b Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:24:55 +0300 Subject: [PATCH 10/20] =?UTF-8?q?fix(thomas):=20celulele=20nu=20mai=20poar?= =?UTF-8?q?t=C4=83=20fiecare=20litera=20ei,=20ilizibile=20pe=20telefon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit „a₂" în colț plus „−2" la mijloc înseamnă două texte suprapuse într-o celulă care, pe un ecran de 360px, are vreo 19px reali. Litera dubla oricum ceva ce desenul spune deja: pe ce diagonală stă celula și ce bloc e deasupra ei. Numele literelor rămân unde chiar spun ceva — în formulele din panoul din dreapta. Eticheta se scoate și de pe coloana lui d, nu doar de pe a, b și c: altfel ar fi rămas singura coloană cu litere în colț, adică aceeași aglomerare, doar mai mică. Cifra crește de la 34 la 38 de unități, fiindcă acum are celula pentru ea singură: cel mai lung text desenat are trei semne („x₁", „40") și încape în cele 94 de unități de lățime interioară. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01D1KzHzp6YwHkoM6AfDYGHv --- src/components/content/AnimatiaThomas.tsx | 28 +++++++++-------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/components/content/AnimatiaThomas.tsx b/src/components/content/AnimatiaThomas.tsx index 2243fa5..58237e4 100644 --- a/src/components/content/AnimatiaThomas.tsx +++ b/src/components/content/AnimatiaThomas.tsx @@ -491,7 +491,13 @@ function NumeBloc({ } /** - * O celulă din desen: rama, eticheta din colț („b₂") și valoarea din mijloc. + * O celulă din desen: rama și valoarea din mijloc. + * + * **Fără eticheta din colț.** „a₂", „b₂", „c₂", „d₂" scrise în fiecare celulă + * dublau o informație care se citește deja din desen — diagonala pe care stă + * celula și numele blocului de deasupra —, iar pe un ecran de telefon cele două + * texte suprapuse în aceeași celulă se citeau ca un ghem. Numele literelor + * rămân acolo unde chiar spun ceva: în formulele din panoul din dreapta. * * Valoarea se poate schimba în timpul clipului, deci primește două texte și * greutatea trecerii: cel vechi urcă și se stinge, cel nou intră de jos. E @@ -500,7 +506,6 @@ function NumeBloc({ function Celula({ coloana, linie, - eticheta, vechi, nou, trecere, @@ -513,7 +518,6 @@ function Celula({ }: { coloana: number; linie: number; - eticheta?: string; vechi: string; nou?: string; /** 0 = valoarea veche, 1 = cea nouă. */ @@ -536,7 +540,10 @@ function Celula({ const cy = linie + CH / 2; const m = trecere ?? 0; const gata = m >= 0.999; - const corp = 34 * Math.min(st, 1.35); + // Cifra a crescut de la 34 odată cu scoaterea etichetei din colț: acum are + // celula pentru ea singură, iar cel mai lung text din desen („x₁", „40") are + // trei semne, deci încape lejer în cei 94 de unități de lățime interioară. + const corp = 38 * Math.min(st, 1.35); const culoare = pivot ? "var(--viz-pivot-text)" @@ -561,17 +568,6 @@ function Celula({ stroke={activ > 0.02 ? culoareRol(ROL_ACTIUNE) : "var(--bordura)"} strokeWidth={activ > 0.02 ? 2 + 2 * activ : 2} /> - {eticheta && ( - - )} {m < 0.999 && ( @@ -933,7 +929,6 @@ function Desen() { key={`m${linie}-${coloana}`} coloana={GX + coloana * CW} linie={GY + linie * CH} - eticheta={`${esteA ? "a" : esteB ? "b" : "c"}${indice(linie + 1)}`} vechi={num(valoare)} nou={dupa === undefined ? undefined : num(dupa)} trecere={dupa === undefined ? 0 : schimba(T, cand)} @@ -983,7 +978,6 @@ function Desen() { key={`d${linie}`} coloana={DCOL} linie={GY + linie * CH} - eticheta={`d${indice(linie + 1)}`} vechi={num(D[linie]!)} nou={linie > 0 ? num(D_DUPA_ELIMINARE[linie]!) : undefined} trecere={linie > 0 ? schimba(T, cand) : 0} From 8496b30c8b6f164557cc10484fc374d13d335bce Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:24:57 +0300 Subject: [PATCH 11/20] =?UTF-8?q?docs:=20nota=20despre=20refacerea=20derul?= =?UTF-8?q?=C4=83rii=20doar=20la=20=C3=AEntoarcere?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Progress.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Progress.md b/Progress.md index 4c55b02..45f69a9 100644 --- a/Progress.md +++ b/Progress.md @@ -691,6 +691,28 @@ Verificat în browser, pe ambele teme, la 360px și 1280px, cu `prefers-reduced- cadru (`motion.line` cu `animate` și fără valori statice), deci consola primește patru erori pe `derivare-numerica` și pe `ecuatii-neliniare`. E mai vechi decât lista și nu ține de ea. +### Refacerea derulării se face doar la întoarcere (17 august 2026) + +Urmarea directă a reparației de mai sus, din a doua trecere: odată ce poziția chiar se reținea, s-a +văzut că se **refăcea prea des**. Săgeata „pagina următoare" te lăsa în subsolul paginii următoare, +nu la titlul ei. + +Cauza nu era derularea, ci **unde stau săgețile**: chiar la fundul paginii. Orice pagină părăsită +printr-o săgeată își salva poziția „la fund", iar a doua oară când ajungeai pe ea — oricum ai fi +ajuns — erai pus înapoi acolo. Măsurat pe `interpolare-polinomiala` → `curbe-bezier`, a doua +trecere: **6713 din 6966** pe telefon și **5031 din 5031** pe desktop. + +**Nu era o problemă de telefon**, deși acolo a fost văzută: pe telefon paginile sunt cam de două ori +mai înalte și săgeata se apasă mult mai des decât butonul „înapoi" al browserului, deci se nimerea +mai des. Pe desktop se reproduce identic. + +Acum poziția se reface **doar la `POP`** (`useNavigationType` din react-router) — înapoi/înainte din +browser, adică exact gestul căruia browserul îi reface singur derularea pe un site fără router. Un +clic pe o legătură e `PUSH`: ai cerut altă pagină, deci o primești de la început. + +**De reținut**: „reține poziția paginii" nu e o singură cerință, ci două — _ce_ se salvează și _când_ +se reface. Prima trecere a rezolvat-o pe prima și a presupus că a doua n-are variante. + ### Pagina 13 — `curbe-bezier`, ce e gata și ce nu Ce există: From 3918919a54dbc2465455a1e8387b62db49a931d2 Mon Sep 17 00:00:00 2001 From: Dimitrescu Robert Date: Mon, 17 Aug 2026 21:27:13 +0300 Subject: [PATCH 12/20] =?UTF-8?q?fix(clip):=20comenzile=20stau=20pe=20un?= =?UTF-8?q?=20r=C3=A2nd=20p=C3=A2n=C4=83=20pe=20la=20334px,=20cu=20goluri?= =?UTF-8?q?=20egale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pe telefon, bara se rupea pe la 382px, deși butoanele încăpeau: cu `justify-between`, prisosul se împărțea doar între cele trei grupuri de nivel întâi, deci golul dintre redare și viteze era de câteva ori cât cel dintre „reia" și „pornește", iar când prisosul ajungea zero rândul ceda. Acum toate golurile sunt `gap-1`, deci lățimea cerută e fixă. Butoanele de viteză trec pe `px-1`: „0.5×" are patru semne mono la 14px, adică 33,6px de text, iar cu `px-1.5` ieșea 45,6px — peste podeaua de 44px a țintei de atingere, deci butonul ăla singur lățea rândul. Socoteala: 6 × 44px + 5 × 4px = 284px, dintr-o ramă care lasă lățimea ecranului − 32 (Container) − 2 (rama) − 16 (`p-2`). Măsurat pe capturi la 350px, 360px și 382px: un singur rând, cu distanțe egale. La 320px se rupe curat, între grupuri, fără derulare orizontală. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012EvFhxeqEqtCsEsDgRqgN4 --- src/components/viz/PlaybackClip.tsx | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/components/viz/PlaybackClip.tsx b/src/components/viz/PlaybackClip.tsx index 503f745..aff7e55 100644 --- a/src/components/viz/PlaybackClip.tsx +++ b/src/components/viz/PlaybackClip.tsx @@ -94,8 +94,20 @@ export function PlaybackClip({ {/* Al doilea rând pe telefon. Peste `sm`, învelișurile astea dispar din așezare (`contents`) și copiii lor redevin celule ale rândului unic — de aceea n-au `role`: un `role` pe un element cu `display: contents` - poate cădea din arborele de accesibilitate. */} -
+ poate cădea din arborele de accesibilitate. + + **Pe telefon toate golurile sunt `gap-1`, și rândul nu se mai + împinge cu `justify-between`.** Cele două nu sunt cerințe separate: + `justify-between` împărțea prisosul doar între cele trei grupuri de + nivel întâi, deci golul dintre redare și viteze era de câteva ori cât + cel dintre „reia" și „pornește" — iar când prisosul ajungea zero, + rândul se rupea, deși butoanele încă încăpeau. Cu goluri egale, + lățimea cerută e fixă și se poate socoti: 6 × 44px (ținta de atingere) + + 5 × 4px = 284px. Rama lasă `lățimea ecranului − 32` (`Container + px-4`) `− 2` (rama) `− 16` (`p-2`), deci rândul ține până pe la 334px + — sub etalonul de 360px, cu rezervă. `flex-wrap` rămâne pentru ce e + mai îngust de atât: acolo se rupe curat, între grupuri. */} +