Files
mpabi 8bf8e22448
Check card layouts / check (push) Has been cancelled
feat: publish A1-A8 card viewer and FreeRTOS C generator
2026-07-19 16:43:35 +02:00

288 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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://<url_host_uuid>/<doc_uuid>`.
`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.<id>.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.