# Opis repozytorium pojedynczej karty Każda karta jest osobnym repozytorium lub samodzielnym katalogiem. Jej źródłem prawdy jest `json/card_source.json`; pliki TeX i HTML są artefaktami generowanymi. ## Minimalne drzewo ```text moja-karta/ ├── README.md ├── json/card_source.json ├── doc/ ├── web/ └── src/ ``` ## Obowiązkowe warstwy danych ### Metadane Obiekt `card` identyfikuje serię, numer, wersję, UUID, autora i status. Obiekt `generated` wskazuje ścieżki wyjściowe TeX/HTML/CSS. Pole `template` wybiera layout. Opcjonalny obiekt `title_block` włącza tabliczkę zasobu o skonfigurowanej wysokości 2,6 lub 3 cm na każdej stronie, także pierwszej, bibliografii, słownika i stronach kontynuacji. Tabliczka zastępuje dużą tabelę metadanych strony tytułowej. Zawiera kategorię, tytuł, metadane karty, numer strony oraz widoczny, kanoniczny URL. Ten sam URL jest kodowany lokalnie w QR: jako SVG w HTML i przez pakiet `qrcode` w TeX. Opcjonalny `repository_url` dodaje drugi QR do repozytorium. W layoutach klasycznym HTML i PDF komórki QR mają po 24 mm, a kody po 22 mm: Gitea znajduje się po lewej, a wyrenderowany zasób po prawej. Ramka ma 167 mm i biegnie między marginesami bocznymi po 21,5 mm. W HTML widok ekranowy ma rozmiar A4 (210 × 297 mm) i nagłówek na każdej logicznej karcie, a wydruk używa `@page { size: A4; }` oraz pól marginesu, dlatego nagłówek powtarza się również po automatycznym podziale długiej sekcji. Pole `height_cm` przyjmuje `2.6` (kompaktowy nagłówek z QR 22 mm i równym światłem) albo `3`; pola `repeat_on_every_page: true` i `replace_front_matter: true` dokumentują ten kontrakt. `show_qr: true` wymaga kanonicznego adresu HTTP(S) w `url` albo pary `url_host_uuid`/`doc_uuid`, z której powstaje `https:///`. `show_repository_qr: true` wymaga `repository_url`. Adres podglądu `localhost` nie powinien być publikowany na karcie. ### Publikacja lokalna i globalna UUID hosta/workspace oraz UUID karty są stabilną tożsamością zasobu, a nie tożsamością konkretnego serwera. Viewer podczas zajęć otwiera kartę przez względny adres lokalnego ingressu K3s; kanoniczny adres globalny pozostaje w metadanych, QR i udostępnianych odsyłaczach. Utrata Internetu nie może blokować katalogu, przełączania kart, API sterowania, symulatora, dowodów ani raportu. Pełny kontrakt topologii, routingu, magazynowania i przyszłej synchronizacji opisuje [OFFLINE-FIRST-DEPLOYMENT.md](OFFLINE-FIRST-DEPLOYMENT.md). ### Status i wersja tasków w zakresie karty Wiersze `front_page_scope.scope_table.rows[]` mogą opisywać stan opracowania pojedynczego tasku. JSON przechowuje stabilny angielski klucz `status`, a renderer pokazuje jego krótką polską etykietę w HTML i PDF. | Klucz | Etykieta | Znaczenie | |---|---|---| | `not-started` | brak | task nie został jeszcze opracowany | | `draft` | robocze | istnieje niepełna wersja robocza | | `in-progress` | w trakcie | task jest aktualnie opracowywany | | `review` | do przeglądu | materiał czeka na sprawdzenie | | `ready` | opracowane | materiał jest sprawdzony i gotowy do użycia | | `blocked` | zablokowane | dalsza praca wymaga rozwiązania zależności | Pole `version` ma format `vNN.NN`, na przykład `v00.01`. Drugi człon zwiększamy przy zaakceptowanej rewizji treści lub materiałów tasku. Pierwszy człon zwiększamy, gdy zmienia się kontrakt dydaktyczny albo wymagany rezultat; po takim zwiększeniu drugi człon zaczyna się od `00`. ```json { "chapter": "5.4", "task": "Task04", "idea_tex": "arytmetyka adresów, alokator", "priority": "obowiązkowe", "status": "in-progress", "version": "v00.01", "key": true } ``` Status i wersję zmieniamy wyłącznie w źródłowym `card_source.json`; pliki HTML, TeX i PDF pozostają artefaktami generatora. ### Efekty i kryteria - `educational_requirements` — wymagania `WE`; - `learning_effects` — efekty `EN` lub `EK`; - `assessment_criteria` — mierzalne kryteria `KW`; - `educational_requirements.*.learning_tree` — połączenia renderowane na marginesach. Każdy wpis `learning_tree.ogolne[]` lub `learning_tree.zawodowe[]` ma stabilne `tree_id`, odwołanie `effect_ref`, etykietę `display` oraz co najmniej jedno powiązane `KW`. ### Sekcje i kroki Pole `sections[]` porządkuje treść. Kroki `sections[].steps[]` mają: - `id` i `title`; - `tree_refs` wskazujące drzewka z marginesów; - opcjonalne odwołania do wymagań, efektów, kryteriów, równań i figur. ### Referencje zewnętrzne bez kopiowania treści Karta może ładować kanoniczne rejestry współdzielonych strategii, kart, treści i wzorów. Lokalny plik JSON służy do walidacji oraz deterministycznego buildu: ```json { "reference_registries": [ { "uuid": "03403a8a-e20d-5b17-9004-26d9fe6c3003", "source": "../../../tools/debugging-strategies/json/reference_registry.json" } ] } ``` Krok przechowuje tylko rodzaj, UUID rejestru i UUID wpisu: ```json { "references": [ { "kind": "strategy", "registry_uuid": "03403a8a-e20d-5b17-9004-26d9fe6c3003", "uuid": "1ecfc474-4fbd-5a56-8ef1-80ae557761d0" } ] } ``` Generator pobiera z rejestru etykietę, tytuł, ścieżkę i publiczny adres. Strategię pokazuje jako kod `Mxx`, kartę jako jej nazwę, a treść lub wzór jako kanoniczną etykietę. W TeX/PDF i HTML etykieta jest hiperłączem. Nazw ani URL-i nie kopiujemy do `card_source.json`; brak rejestru, UUID albo lokalnego pliku przerywa generowanie. Layouty 5a/5b obsługują również: - `model_block.steps` — kroki modelowania; - `code_block.blocks[].web_steps` — interaktywne kroki HTML; - `hardware_procedure[]` — tabela `step/action/condition` w TeX i HTML. `code_block.blocks[]` jest rzeczywistym podziałem na bloki: każdy wpis jest renderowany jako osobna, opisana ramka w sekcji implementacyjnej, a jego `web_steps` zasila niezależną checklistę HTML. Kolejność głównych bloków strony jest opisana przez `block_map` wybranego szablonu. ### Zrzuty ekranu i inne assety sekcji Zrzutów nie wpisujemy jako ręcznego `\\includegraphics` w wygenerowanym TeX. Sekcja może deklarować listę `assets`, a generator umieszcza każdy element w TeX/PDF i HTML, kopiuje plik do `figures/` strony oraz dodaje link do pełnego rozmiaru: ```json { "title": "Pomiar w debuggerze", "content_tex": "Zatrzymaj program przed pierwszą alokacją.", "assets": [ { "path": "assets/task04-first-allocation-annotated.png", "caption": "Task04 przed pierwszym przydziałem pamięci.", "label": "fig:task04-first-allocation", "alt": "Termdebug: kod C, listing, rejestry i allocbuf", "kind": "screenshot", "width": 1.0 } ] } ``` - `path` jest liczony względem katalogu `doc/` karty; standardem jest `doc/assets/`; - obsługiwane są PNG, JPG/JPEG i PDF; - `width` jest ułamkiem szerokości kolumny od `0.1` do `1.0`; - `label` jest stabilnym identyfikatorem używanym przez `figure_refs`; - `full_size_link` domyślnie włącza otwieranie zrzutu HTML w pełnym rozmiarze. Jeśli każda figura ma odpowiadać osobnej stronie wydruku, sekcja deklaruje `"asset_page_mode": "one-per-page"`. Generator wtedy wstawia jawne podziały stron w TeX i buduje osobne płótna A4 w React/HTML. Diagram interaktywny sam renderuje zwarty, jednakowy nagłówek na każdej części; zewnętrzny nagłówek sekcji nie przesuwa pierwszego kafla względem pozostałych. Orientację wybiera sekcja przez `"page_orientation": "portrait"` albo `"landscape"`. Jest to własność fizycznej strony, a nie zamiennik dla `page_grid`: pojedynczy szeroki diagram może dostać landscape, pionowa hierarchia portrait, a dopiero model nieczytelny po właściwym dobraniu orientacji otrzymuje jawne złożenie kilku stron. Diagram większy od bezpiecznego pola A4 deklaruje `page_grid` przy assetcie: ```json "page_grid": { "columns": 2, "rows": 2, "cuts_x": [660], "cuts_y": [440], "page_width": 660, "page_height": 760, "step_tiles": {"class-base": 1, "runtime-proof": 4} } ``` `cuts_x` i `cuts_y` są współrzędnymi SVG, a `step_tiles` przypisuje każdy krok interaktywny dokładnie do jednego fizycznego kafla (numeracja wierszowa od 1). Generator odrzuca kafel większy od pola A4 oraz szew przecinający zamknięty blok UML. React może złożyć strony w `spread_group`, zachowując jeden kursor i jedną numerację rysunku; wydruk nadal zawiera niezależne kartki A4. Włączony spread jest automatycznie dopasowywany do szerokości widoku, tak aby wszystkie strony jednego wiersza i ich łączenia były widoczne równocześnie. Nagłówki stron pokazują pulsujące kierunki kontynuacji `← ↑ ↓ →`; środkowa strona szeregu może wskazywać obie strony, a złożenie wielowierszowe także górę i dół. Wskaźniki są wyłącznie nawigacją ekranową i znikają w druku. ### Boczne szyny paneli Narzędzia pomocnicze HTML używają wspólnego systemu paneli bocznych zamiast modalnej zasłony. Cienka kolorowa szyna otwiera panel w trybie `Auto` po najechaniu; kliknięcie przełącza go w `Fixed`. Kolejny klik, przycisk zamknięcia albo `Esc` odpina panel. Renderer może wystawić kilka niezależnych szyn po obu stronach (obecnie: katalog i spis treści po lewej, przebieg i raport po prawej). Panele nakładają się na widok tylko podczas pracy i są zawsze usuwane z wydruku. Nie zmieniają geometrii stron A4 ani kafelków diagramu. Końcowy słownik jest domyślnie obecny w React/HTML dla zgodności. Karta, która ma zawierać wyłącznie jawnie wymienione strony, ustawia na poziomie głównym `"render_dictionary": false`. ### Zadania `tasks` jest słownikiem zadań, a `tasks_order` określa ich kolejność. Każde zadanie posiada polecenie `prompt_tex`, kryterium zaliczenia i odwołania do modelu edukacyjnego. Rozbudowane zadanie przechowuje przebieg dydaktyczny w uporządkowanym `tasks..flow[]`: - `kind: "block"` grupuje jedną część objaśnienia lub demonstracji; - opcjonalne `block.steps[]` zachowują kolejność czynności wewnątrz bloku; - `kind: "exercise"` jest samodzielną pracą ucznia należącą bezpośrednio do zadania i podaje `prompt_tex`, `evidence_tex` oraz `criterion`; - `exercise.based_on[]` może wskazać wcześniejsze bloki lub ich kroki. Bloki i ćwiczenia są rodzeństwem w jednym `flow`, dzięki czemu renderer nie gubi kolejności nauczania. `steps` nie może występować bezpośrednio w obiekcie zadania. Dawne `prompt_tex` i `criterion` pozostają wymagane dla zgodności ze starszymi konsumentami; gdy istnieje `flow`, renderer używa jego treści. ## Zalecany README karty README konkretnej karty powinien zawierać: 1. nazwę, numer i miejsce w serii; 2. cel oraz rezultat obserwowalny; 3. mapowanie do źródeł i efektów nauczania; 4. listę kroków/zadań; 5. polecenia generowania i testowania; 6. warunek `PASS`; 7. informację, które pliki są źródłowe, a które generowane. Gotowy przykład znajduje się w `examples/card/README.md`. ## Generowanie Z katalogu repozytorium `card-layouts`: ```bash python3 tools/render_card.py /sciezka/do/mojej-karty ``` Generator najpierw sprawdza spójność identyfikatorów WE/EN/EK/KW, kroków, zadań, rejestrów UUID i odwołań, a dopiero potem zapisuje oba formaty.