Beskrivelsen og tegningen
Til venstre er alt, der skal skrives for kalenderen. Spøgelset, jordskyggen, fyldet, konturens fire vægte, hånden og tidslinjen lægger motoren på. Klik på tegningen for at se den blive tegnet.
Kompileren
Første udgave var én funktion, der læste beskrivelsen og skrev SVG-tekst undervejs. Anden udgave deler arbejdet op, som en compiler gør: hvert led har én opgave, og mellem leddene findes en scene, der kan undersøges.
Eksakt geometri
Alt er kubiske Bézier-kurver fra start til slut. Buelængde regnes med adaptiv Gauss-Legendre, deling med de Casteljau, yderpunkter og boks ud fra den afledtes roots. Første udgave samplede punkter hver 0,8 enhed og forenklede bagefter.
Uforanderlige scener
Intet trin ændrer den scene det får. Scenerne deler alt, der ikke er ændret, så motoren kan gemme hvert mellemtrin næsten gratis. En test fryser alle scener undervejs, og et trin der prøver at ændre sin indgang, fejler med det samme.
Gentagelig tilfældighed
Hvert trin får sin egen talrække ud fra frøet og sit navn. Et nyt trin flytter derfor ikke de andres tilfældighed, og samme frø giver samme tegning byte for byte på alle maskiner.
Trin for trin
Scenen efter hvert trin. Det trinet har tilføjet eller ændret står fuldt op; resten er dæmpet. Tabellen viser elementerne med de navne motoren giver dem, så en fejl kan føres tilbage til linjen i beskrivelsen.
Reglen som data
Motoren kender ingen tal selv. De står i to versioner af reglen, og hvert af registrets motiver er bundet til den version, det er tegnet efter. Tabellen er skrevet direkte fra reglens data.
Hvert motiv er tegnet med begge love og målt mod originalen, med hånden slået fra og en tolerance på en tredjedel enhed. Alle motiver passer bedst til den lov, de er bundet til. Ved 1,5 enheds tolerance, som første udgave blev målt med, er næsten alt 100 %, og forskellen mellem lovene kan ikke ses.
Registret genskabt
Hver original ved siden af motorens udgave, med den lov motivet er bundet til. Tallet er streger ramt, målt som ovenfor.
Ti nye tomrum til appen
Følger altid den nyeste lov. Sat i Tomrum-komponenten med titel, én linje og præcis to handlinger. Teksterne er forslag.
Tilstandene
Et tomrum er én af seks tilstande. De fem nye har samme hånd og samme lov som resten. Registrets regel om bevægelse er lagt ind i reglen: efter indtegningen står alt stille, undtagen stopurets viser, mens noget indlæses. Linteren melder et motiv, der bryder reglen, og tæller handlingerne: to i alle tilstande undtagen indlæsningen, som ingen har.
Fra SVG til beskrivelse
Importen læser en SVG og skriver en beskrivelse i samme form som motiverne. Det reglen selv lægger på, bliver genkendt og fjernet: spøgelset, skyggen og kroppens kontur. Reglen aflæses af spøgelset. Et ikon fra et andet sæt bliver skaleret ind i rammen og får krop, roller og prik som et udkast, der kan rettes videre.
Tidslinjen er data
Kompileren giver hvert element en start, en varighed og en art: tegnes langs stregen, eller fader frem. Afspilleren i browseren og React-udgangen læser tiderne; ingen af dem regner dem selv. Canvas-udgangen kan tegne ethvert øjeblik, så tegningen kan eksporteres billede for billede.
Hånden er ét felt
I første udgave fik hver streg sin egen afvigelse. Konturens fire stykker bøjede derfor hver sin vej, og fyldet blev liggende. Nu flyttes hvert punkt efter hvor det ligger i planen, gennem en sum af fem lange svingninger. Fyld og kontur følges ad, og stykkerne mødes stadig i overlappene.
Til venstre er feltet vist som et gitter, forstørret fire gange sammen med tegningen. Det er det samme felt, der bøjer begge.
Pennen med tryk
Stregen bliver til en udfyldt form, der sætter an, holder og løfter. Formen er kubiske kurver forskudt langs normalerne, med halvcirkler i enderne, og ikke længere en polygon af punkter. En tegning med tryk fylder derfor en tredjedel mindre end i første udgave.
Én scene, tre udgange
Skiltet fra appen. SVG og React skrives fra det samme lille træ, så de ikke kan tegne forskelligt. Canvas tegner direkte fra kurverne. React-udgangen bruger appens egne klasser, farver og 70 ms-trin og kan erstatte den håndskrevne Tegninger.tsx.
Eksport uden browser
Motoren rastrerer selv. PNG og animeret PNG laves i ren TypeScript, så en build eller en CLI kan skrive billeder uden Chromium. Billederne herunder er lavet på siden med den samme kode. Lottie bruger trim paths til indtegningen og masker til pennen med tryk, og e-mail-udgaven har faste farver og hverken CSS, masker eller animation.
Delingsbillede
1200 × 630 med motivet og tomrummets tekst i Inter. CLI'en skriver det som SVG eller, når Playwright findes, som PNG.
Ind i appen
Et Vite-plugin tegner motiverne ved build. De kommer ind som React-komponenter fra et virtuelt modul, med motivernes id'er som typer, og motoren kommer ikke med i appen. En .tomrum-fil i mappen er et nyt motiv. En fejl i den stopper buildet med stien til stedet, og linterens advarsler står i loggen.
De fire håndtegnede motiver i Tegninger.tsx er låst. Pluginnet genererer dem ikke, så de bliver i appen, som de er.
import react from "@vitejs/plugin-react"
import { tomrum } from "@ramtt/tomrum-motor/vite"
export default {
plugins: [
react(),
tomrum({ mappe: "src/tomrum", dts: "src/tomrum.d.ts" }),
],
}import { TOMRUM, TegningStopur } from "virtual:tomrum"
import "virtual:tomrum/lever.css"
const { Tegning, tekst } = TOMRUM.kalender
<Tomrum
tegning={<Tegning />}
titel={tekst.titel}
linje1={tekst.linje}
primaer={{ label: tekst.primaer, onClick: plan }}
videre={{ label: tekst.videre, onClick: bibliotek }}
/>Tests
Testene kører med Nodes egen testløber mod den kompilerede kode. De visuelle krav måles i Chromium. Resultaterne her er fra kørslen, der byggede siden.
Første og anden udgave
Median over de 22 motiver i Node 22. Størrelsen er SVG uden tidslinje med to decimaler.
Prøv selv
Ret i beskrivelsen, så kontrollerer og tegner motoren igen, og linteren melder hvad den ser. Træk i håndtagene på tegningen, så skrives tallene i beskrivelsen med. Et tal, der er regnet ud, har intet håndtag. Prøv også at stave et felt forkert, sætte en bredde uden for rollens spænd eller slette Z i kroppen.
Til repoet
Motoren ligger i ~/tomrum/motor/v2 ved siden af første udgave. Kilden er TypeScript uden afhængigheder ved kørsel; esbuild laver modul- og script-udgaver, og ci/tomrum-motor.yml er workflowet til GitHub.
geometri.ts, spec.ts, kompiler.ts, trin/, lov/, render/, eksport/, import.ts, redigering.ts, vite.ts, lint.ts og motiver.ts.
tomrum byg, tomrum tjek fil.tomrum, tomrum tegn id --png --apng --lottie --epost --og, tomrum importer ikon.svg og tomrum regler.
npm test for enhed, egenskaber og gyldne aftryk, node test/visuel.mjs for originalerne og rastreringen i Chromium, og node test/bench.mjs mod første udgave.