docs(amiga): fix README navigation indexes, add missing entries, and update Tier 3 statuses

This commit is contained in:
Ilia Sharin 2026-05-12 22:18:43 -04:00
parent 7960cbdf25
commit fa8ce16936
4 changed files with 413 additions and 9 deletions

View file

@ -20,13 +20,13 @@ This section provides a systematic methodology for reverse engineering AmigaOS e
| [ida_setup.md](ida_setup.md) | IDA Pro configuration for 68k/Amiga analysis |
| [ghidra_setup.md](ghidra_setup.md) | Ghidra configuration for 68k/Amiga analysis & decompilation |
| [compiler_fingerprints.md](compiler_fingerprints.md) | Compiler identification by code patterns |
| [library_reconstruction.md](library_reconstruction.md) | Reconstructing unknown library JMP tables |
| [static/library_jmp_table.md](static/library_jmp_table.md) | Reconstructing unknown library JMP tables and LVOs |
| [static/code_vs_data_disambiguation.md](static/code_vs_data_disambiguation.md) | Distinguishing code bytes from data — IDA/Ghidra workflows |
| [patching_techniques.md](patching_techniques.md) | Surgical binary patching methods |
| [unpacking_and_decrunching.md](unpacking_and_decrunching.md) | Executable unpacking, decruncher architecture, and manual extraction |
| [custom_loaders_and_drm.md](custom_loaders_and_drm.md) | Bypassing DOS, Trackloaders, and physical DRM tricks |
| [anti_debugging.md](anti_debugging.md) | The Cracker vs. Developer arms race: Trace vector abuse, NMI defeat, CIA timers |
| [whdload_architecture.md](whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, and runtime memory patching |
| [games/whdload_architecture.md](games/whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, and runtime memory patching |
| [case_studies/](case_studies/) | Real-world RE walkthroughs |
| [case_studies/ramdrive_device.md](case_studies/ramdrive_device.md) | ramdrive.device RE walkthrough |

View file

@ -392,12 +392,413 @@ The `MaxChars` field includes the null terminator. If your buffer is 64 bytes, s
6. **Set `PLACETEXT_LEFT/RIGHT/ABOVE`** for label placement — don't hardcode text positions
7. **Handle `IDCMP_REFRESHWINDOW`** with `GT_BeginRefresh()`/`GT_EndRefresh()`
8. **Give every gadget a unique `GadgetID`** — this is how you identify the source in `IDCMP_GADGETUP`
9. **Always check `CreateGadget()` return** — a NULL return means the list is broken; you must free everything
10. **Create GadTools gadgets in order** — the linked list must be contiguous; skipping one breaks the chain
11. **Use `GTMN_NewLookMenus, TRUE`** when calling `CreateMenus()` — consistent 3D look
12. **Use `GA_Immediate` / `GA_RelVerify`** on raw gadgets — without both, you miss press/release events
---
## Named Antipatterns
### "The Invisible Gadget" — Forgetting GT_RefreshWindow
```c
/* BAD: GadTools gadgets need an explicit render pass after window open.
Without it, the gadget structures exist but nothing is drawn. */
struct Window *win = OpenWindowTags(NULL,
WA_Gadgets, glist,
TAG_DONE);
/* User sees an empty window — gadgets are invisible! */
```
```c
/* CORRECT: Always call GT_RefreshWindow after opening */
struct Window *win = OpenWindowTags(NULL,
WA_Gadgets, glist,
TAG_DONE);
GT_RefreshWindow(win, NULL); /* renders all gadget borders and labels */
```
### "The Message Mangler" — Mixing GetMsg with GadTools
```c
/* BAD: Using exec.library GetMsg() instead of GT_GetIMsg().
GadTools internally injects messages for sub-events (ListView scrolling,
slider dragging). GetMsg() doesn't route through GadTools' filter,
so internal state desynchronizes — gadgets stop responding. */
struct IntuiMessage *msg;
while ((msg = GetMsg(win->UserPort))) /* WRONG */
{
HandleMessage(msg);
ReplyMsg(msg); /* ALSO WRONG — must use GT_ReplyIMsg */
}
```
```c
/* CORRECT: Always use the GT_ pair */
struct IntuiMessage *msg;
while ((msg = GT_GetIMsg(win->UserPort)))
{
HandleMessage(msg);
GT_ReplyIMsg(msg);
}
```
### "The Orphaned Chain" — Not Checking CreateGadget Return
```c
/* BAD: If CreateGadget() returns NULL, the linked list is broken.
Continuing to use 'gad' as context for subsequent calls creates
a corrupted gadget list — crash or silent malfunction. */
gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_DONE);
/* No NULL check! If this failed, gad is NULL... */
gad = CreateGadget(STRING_KIND, gad, &ng, TAG_DONE); /* undefined behavior */
```
```c
/* CORRECT: Check every CreateGadget return */
gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_DONE);
if (!gad) goto cleanup;
gad = CreateGadget(STRING_KIND, gad, &ng, TAG_DONE);
if (!gad) goto cleanup;
/* ... */
cleanup:
FreeGadgets(glist); /* frees everything created so far */
```
### "The Hot-Swap Hazard" — Modifying Gadgets In-Place
```c
/* BAD: Changing a raw gadget's position while it's attached.
Intuition may be in the middle of rendering the gadget when
you change its coordinates — screen corruption. */
myGadget->LeftEdge = 50; /* LIVE MODIFICATION — DANGEROUS */
myGadget->Width = 200;
```
```c
/* CORRECT: Remove → modify → re-add → refresh */
UWORD pos = RemoveGadget(win, myGadget);
myGadget->LeftEdge = 50;
myGadget->Width = 200;
AddGadget(win, myGadget, pos);
RefreshGList(myGadget, win, NULL, 1);
```
> [!TIP]
> For GadTools gadgets, use `GT_SetGadgetAttrs()` instead — it handles the remove/modify/add/refresh cycle internally.
### "The Silent Button" — Missing GACT_RELVERIFY
```c
/* BAD: Without GACT_RELVERIFY, Intuition never sends IDCMP_GADGETUP.
The user clicks the button, sees it highlight, but nothing happens. */
struct Gadget myButton = {
.Flags = GFLG_GADGHCOMP,
.Activation = GACT_IMMEDIATE, /* only sends GADGETDOWN, not GADGETUP */
.GadgetType = GTYP_BOOLGADGET,
};
```
```c
/* CORRECT: Set both IMMEDIATE and RELVERIFY */
struct Gadget myButton = {
.Flags = GFLG_GADGHCOMP,
.Activation = GACT_IMMEDIATE | GACT_RELVERIFY,
.GadgetType = GTYP_BOOLGADGET,
};
/* Now you get both IDCMP_GADGETDOWN (press) and IDCMP_GADGETUP (release) */
```
---
## GadTools → BOOPSI Migration Guide
GadTools is built on top of raw `struct Gadget`. BOOPSI gadgets (`GTYP_CUSTOMGADGET`) are a different system. Here's when and how to migrate:
### When to Stick with GadTools
- Standard buttons, checkboxes, sliders, string fields
- Application targets OS 2.03.1
- No custom gadget rendering needed
- Quick prototyping
### When to Move to BOOPSI
- Custom gadget appearance or behavior
- Inter-gadget communication (slider auto-updates label)
- Reusable components across projects
- Need `layouthook`-based auto-positioning
### Quick-Reference: Same Gadget, Two APIs
| Task | GadTools | BOOPSI (ReAction/MUI) |
|------|----------|-----------------------|
| Create button | `CreateGadget(BUTTON_KIND, ...)` | `NewObject(NULL, "button.gadget", ...)` |
| Set value | `GT_SetGadgetAttrs(gad, win, NULL, TAG_DONE)` | `SetAttrs(obj, TAG_DONE)` |
| Get value | `GT_GetGadgetAttrs(gad, win, NULL, TAG_DONE)` | `GetAttr(attr, obj, &val)` |
| Disable | `GT_SetGadgetAttrs(gad, win, NULL, GA_Disabled, TRUE, TAG_DONE)` | `SetAttrs(obj, GA_Disabled, TRUE, TAG_DONE)` |
| Event | `IDCMP_GADGETUP`, check `GadgetID` | `IDCMP_GADGETUP`, check `GadgetID` or `GA_ID` |
| Free | `FreeGadgets(glist)` | `DisposeObject(obj)` |
### Key Differences
```c
/* GadTools: all gadgets share one linked list, created sequentially */
gad = CreateContext(&glist);
gad = CreateGadget(BUTTON_KIND, gad, &ng1, TAG_DONE);
gad = CreateGadget(STRING_KIND, gad, &ng2, TAG_DONE);
/* glist points to the head — contains all gadgets */
/* BOOPSI: each gadget is an independent object */
Object *btn = NewObject(NULL, "button.gadget",
GA_ID, 1,
TAG_DONE);
Object *str = NewObject(NULL, "strgadget",
GA_ID, 2,
TAG_DONE);
/* Must manually build into a gadget list or use a group */
```
```mermaid
graph LR
subgraph "GadTools Approach"
CTX[CreateContext] --> G1[Button]
G1 --> G2[String]
G2 --> G3[Slider]
end
subgraph "BOOPSI Approach"
B[NewObject button]
S[NewObject strgadget]
SL[NewObject propgadget]
B -->|GA_Next| S
S -->|GA_Next| SL
end
```
---
## Practical Cookbook: Form with Mixed Gadgets
```c
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <libraries/gadtools.h>
enum {
GAD_NAME = 1,
GAD_AGE,
GAD_COLOR,
GAD_OK,
GAD_CANCEL
};
static const STRPTR colorLabels[] = { "Red", "Green", "Blue", NULL };
struct AppGadgets {
struct Gadget *glist;
struct Gadget *gadName;
struct Gadget *gadAge;
struct Gadget *gadColor;
struct Gadget *gadOk;
};
struct AppGadgets CreateFormGadgets(APTR vi, struct TextAttr *topaz8)
{
struct AppGadgets ag = {0};
struct Gadget *gad;
struct NewGadget ng = {0};
gad = CreateContext(&ag.glist);
/* --- Name string gadget --- */
ng.ng_LeftEdge = 80;
ng.ng_TopEdge = 20;
ng.ng_Width = 200;
ng.ng_Height = 16;
ng.ng_GadgetText = "Name:";
ng.ng_TextAttr = topaz8;
ng.ng_VisualInfo = vi;
ng.ng_Flags = PLACETEXT_LEFT;
ag.gadName = gad = CreateGadget(STRING_KIND, gad, &ng,
GTST_MaxChars, 63,
GTST_String, "",
GA_ID, GAD_NAME,
TAG_DONE);
/* --- Age integer gadget --- */
ng.ng_TopEdge += 24;
ng.ng_GadgetText = "Age:";
ng.ng_GadgetID = GAD_AGE;
ag.gadAge = gad = CreateGadget(INTEGER_KIND, gad, &ng,
GTIN_MaxChars, 4,
GA_ID, GAD_AGE,
TAG_DONE);
/* --- Color cycle gadget --- */
ng.ng_TopEdge += 24;
ng.ng_Width = 200;
ng.ng_GadgetText = "Color:";
ng.ng_GadgetID = GAD_COLOR;
ag.gadColor = gad = CreateGadget(CYCLE_KIND, gad, &ng,
GTCY_Labels, colorLabels,
GA_ID, GAD_COLOR,
TAG_DONE);
/* --- OK / Cancel buttons --- */
ng.ng_TopEdge += 30;
ng.ng_LeftEdge = 120;
ng.ng_Width = 80;
ng.ng_Height = 20;
ng.ng_GadgetText = "_OK";
ng.ng_Flags = PLACETEXT_IN;
ag.gadOk = gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_ID, GAD_OK,
TAG_DONE);
ng.ng_LeftEdge += 90;
ng.ng_GadgetText = "_Cancel";
ng.ng_GadgetID = GAD_CANCEL;
gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_ID, GAD_CANCEL,
TAG_DONE);
return ag;
}
void ReadFormValues(struct AppGadgets *ag, struct Window *win)
{
STRPTR name;
LONG age;
USHORT colorIdx;
GT_GetGadgetAttrs(ag->gadName, win, NULL,
GTST_String, &name, TAG_DONE);
GT_GetGadgetAttrs(ag->gadAge, win, NULL,
GTIN_Number, &age, TAG_DONE);
GT_GetGadgetAttrs(ag->gadColor, win, NULL,
GTCY_Active, &colorIdx, TAG_DONE);
Printf("Name=%s Age=%ld Color=%s\n",
name, age, colorLabels[colorIdx]);
}
```
---
## Historical Context & Modern Analogies
### Competitive Landscape
| Platform | Gadget System | Custom Classes | Layout Engine | Inter-Gadget Communication |
|----------|-------------|---------------|--------------|--------------------------|
| **AmigaOS GadTools** | `CreateGadget()` + `NewGadget` | No — fixed gadget types | Manual coordinates | Via application event loop |
| **AmigaOS BOOPSI** | `NewObject()` + dispatcher | Yes — subclass rootclass | Manual or layout hook | ICA interconnection (observer) |
| **Amiga MUI** | `NewObject("mui.class")` | Yes — subclass MUI classes | Automatic (group/layout) | Notification hooks |
| **Mac OS (Classic)** | Control Manager + CNTL resources | Yes (via CDEF) | Manual or dialog resources | Application event routing |
| **Windows 3.x** | `CreateWindow()` + `WNDCLASS` | Yes (via WNDPROC) | Manual or dialog templates | `WM_COMMAND` / `SendDlgItemMessage()` |
| **X11/Motif** | `XtCreateWidget()` + `XmCreate*` | Yes (via Xt class) | `XmForm` constraints | `XtAddCallback()` |
### Evolution of Amiga Gadget Systems
```mermaid
timeline
title Amiga Gadget API Timeline
1985 : OS 1.0 — Raw struct Gadget\nManual Border/Image imagery
1987 : OS 1.3 — No significant changes\nGadgets remained primitive
1990 : OS 2.0 — GadTools.library\nCreateGadget() API\nBOOPSI introduced
1992 : OS 2.1 — gadtools V39\nGT_GetGadgetAttrs added
1993 : OS 3.0 — NewLook 3D gadgets\nGA_Disabled appearance
1995 : OS 3.1 — No API changes\nBug fixes only
1996 : MUI 3.x — Third-party\nAutomatic layout, skinning
1999 : ReAction — AROS/OS 3.5+\nWindow.class, Layout.gadget
```
### Modern Analogies
| Amiga Concept | Modern Equivalent | Notes |
|--------------|-------------------|-------|
| `struct Gadget` | `GtkWidget` / `QWidget` / `NSView` | Base widget type |
| `GadgetID` | `gtk_buildable_get_name()` / Qt `objectName` | Widget identification |
| `CreateGadget(KIND, ...)` | `gtk_button_new_with_label()` / Qt `QPushButton(tr("..."))` | Factory creation |
| `GT_SetGadgetAttrs()` | `gtk_widget_set_property()` / Qt `setProperty()` | Runtime update |
| `GT_GetGadgetAttrs()` | `gtk_widget_get_property()` / Qt `property()` | Runtime query |
| `GA_Disabled` | `gtk_widget_set_sensitive()` / Qt `setEnabled()` | Gray out |
| `GFLG_RELWIDTH/RELHEIGHT` | GTK `hexpand` / Qt `sizePolicy` | Responsive sizing |
| `CreateContext(&glist)` | GtkBuilder `.ui` file / Qt `.ui` file | Container for widget tree |
| `GT_RefreshWindow()` | Not needed — modern toolkits auto-render | Amiga requires explicit refresh |
| `PropInfo` (HorizPot/VertPot) | `gtk_adjustment_set_value()` / Qt `QSlider::setValue()` | Scrollbar/slider state |
| `RemoveGadget()` / `AddGadget()` | `gtk_container_remove()` / `gtk_container_add()` | Dynamic widget management |
| `PLACETEXT_LEFT/RIGHT` | GTK `GtkLabel` + `GtkBox` / Qt `QFormLayout` | Label positioning |
---
## Use Cases
| Application | Gadget Types Used | Notable Patterns |
|-------------|------------------|-----------------|
| **Workbench** | System gadgets (close, depth, drag, size) | All windows use the same system gadget set |
| **Prefs programs** | Cycle, slider, palette, button | Cycle for screen mode, slider for frequency, palette for colors |
| **File requesters (ASL)** | ListView, string, button, scroller | ListView for file list, string for filename input |
| **Text editors** | String, button, scroller | String for find/replace dialogs, scroller for document view |
| **Image editors (DPaint)** | Cycle, palette, button, custom gadgets | Palette for color selection, custom gadgets for tool options |
| **Audio trackers** | Integer, slider, button, listview | Integer for BPM/tempo, slider for volume, listview for patterns |
| **Installer scripts** | Button, checkbox, string | Checkbox for options, string for install path |
| **Game launchers** | Cycle, button, checkbox, slider | Cycle for resolution, slider for volume, checkbox for fullscreen |
---
## FAQ
**Q: What's the difference between GadTools and BOOPSI gadgets?**
A: GadTools is a convenience wrapper that creates raw `struct Gadget` objects with pre-built rendering and behavior. BOOPSI gadgets (`GTYP_CUSTOMGADGET`) use `DoMethod()` dispatch and support inheritance and ICA interconnection. GadTools gadgets are simpler but limited to fixed types; BOOPSI gadgets are extensible but require more boilerplate.
**Q: Can I mix GadTools and BOOPSI gadgets in the same window?**
A: Yes — both ultimately become `struct Gadget` nodes in the same linked list. However, you must use the correct API for each type: `GT_SetGadgetAttrs()` for GadTools, `SetAttrs()` for BOOPSI. Event handling (`IDCMP_GADGETUP`) works the same for both.
**Q: Why does my slider only send `IDCMP_GADGETUP` on release?**
A: By default, sliders only report the final value. To get continuous updates while dragging, set `GA_FollowMouse` in `CreateGadget()`. This causes `IDCMP_MOUSEMOVE` events with the slider gadget as `IAddress` while the user drags.
**Q: How do I create a scrollable list that updates dynamically?**
A: Use `LISTVIEW_KIND` with `GT_SetGadgetAttrs()` and `GTLV_Labels` to update the string array. The listview redraws automatically. Remember the label array must remain valid (static or heap-allocated) for the lifetime of the gadget.
**Q: Can gadgets span multiple windows?**
A: No — a gadget can only be attached to one window at a time. To create the same gadget in multiple windows, create separate gadget instances for each.
**Q: What happens to gadget input during menu mode?**
A: Intuition freezes all gadget input while the menu strip is active (right mouse button held). No `IDCMP_GADGETDOWN`/`IDCMP_GADGETUP` events are delivered until the menu closes.
---
## References
- NDK 3.9: `intuition/intuition.h`, `intuition/gadgetclass.h`, `libraries/gadtools.h`
- ADCD 2.1: `CreateGadget()`, `GT_SetGadgetAttrs()`, `GT_GetGadgetAttrs()`
- AmigaOS Reference Manual (RKRM): Libraries, Chapter 7 — Gadgets
- See also: [BOOPSI](boopsi.md), [IDCMP](idcmp.md), [Windows](windows.md)
### NDK Headers
- `intuition/intuition.h``struct Gadget`, `struct PropInfo`, `struct StringInfo`, `GFLG_*`/`GACT_*`/`GTYP_*` flags
- `intuition/gadgetclass.h` — BOOPSI gadget class attributes (`GA_*`)
- `libraries/gadtools.h``struct NewGadget`, gadget kinds (`*_KIND`), `GTST_*`/`GTSL_*`/`GTCY_*` tags
### Autodocs
- ADCD 2.1: `CreateGadget()`, `CreateContext()`, `GT_SetGadgetAttrs()`, `GT_GetGadgetAttrs()`, `FreeGadgets()`
- ADCD 2.1: `GT_GetIMsg()`, `GT_ReplyIMsg()`, `GT_RefreshWindow()`, `GT_BeginRefresh()`, `GT_EndRefresh()`
- ADCD 2.1: `AddGadget()`, `RemoveGadget()`, `RefreshGList()`
### Related Knowledge Base Articles
- [BOOPSI](boopsi.md) — object-oriented gadget system, ICA interconnection
- [IDCMP](idcmp.md) — `IDCMP_GADGETUP`/`IDCMP_GADGETDOWN` event handling
- [Windows](windows.md) — windows host gadget lists
- [Screens](screens.md) — VisualInfo ties gadgets to screen appearance
- [Intuition Base](intuition_base.md) — Intuition's global state and rendering

View file

@ -126,7 +126,7 @@ The Amiga's documentation was scattered across out-of-print manuals, Usenet post
| [unpacking_and_decrunching.md](05_reversing/unpacking_and_decrunching.md) | Executable unpacking, decruncher architecture, and manual extraction |
| [custom_loaders_and_drm.md](05_reversing/custom_loaders_and_drm.md) | Bypassing DOS, Trackloaders, and physical DRM tricks |
| [anti_debugging.md](05_reversing/anti_debugging.md) | The Cracker vs. Developer arms race: Trace vector abuse, NMI defeat |
| [whdload_architecture.md](05_reversing/whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, memory patching |
| [games/whdload_architecture.md](05_reversing/games/whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, memory patching |
| [case_studies/ramdrive_device.md](05_reversing/case_studies/ramdrive_device.md) | Case Study: ramdrive.device RE walkthrough |
| Per-Compiler RE Field Manuals | Topic |
@ -213,6 +213,8 @@ The Amiga's documentation was scattered across out-of-print manuals, Usenet post
| [blitter.md](08_graphics/blitter.md) | Blitter DMA, minterms, BltBitMap |
| [blitter_programming.md](08_graphics/blitter_programming.md) | Blitter deep dive: cookie-cut, fill, line draw |
| [sprites.md](08_graphics/sprites.md) | Hardware sprites, SimpleSprite |
| [display_modes.md](08_graphics/display_modes.md) | ModeID selection flowchart, CRT vs flat-panel, interlace/progressive tradeoffs, named antipatterns, FPGA/MiSTer impact, historical context, modern analogies, FAQ |
| [ham_ehb_modes.md](08_graphics/ham_ehb_modes.md) | HAM6/HAM8 encoding pipeline, EHB half-brite, fringing, palette programming, FPGA decoder logic |
| [rastport.md](08_graphics/rastport.md) | RastPort, drawing primitives, layers |
| [views.md](08_graphics/views.md) | View/ViewPort, MakeVPort, display pipeline |
| [text_fonts.md](08_graphics/text_fonts.md) | TextFont bitmap layout, baseline rendering, algorithmic styles, AvailFonts enumeration |
@ -233,6 +235,7 @@ The Amiga's documentation was scattered across out-of-print manuals, Usenet post
| [boopsi.md](09_intuition/boopsi.md) | BOOPSI object system, custom classes |
| [input_events.md](09_intuition/input_events.md) | InputEvent, Commodities Exchange |
| [commodities.md](09_intuition/commodities.md) | Commodities Exchange: hotkeys, screen blankers, CxObject API |
| **[frameworks/mui/](09_intuition/frameworks/mui/)** | **MUI (Magic User Interface): architecture, layout system, widgets, custom classes, events, reference snippets** |
### 10 — Devices
| File | Topic |

View file

@ -57,7 +57,7 @@ Articles were scored against [AGENTS.md](../amiga/AGENTS.md) "Deep" criteria:
| 17 | `09_intuition/screens.md` | 582 | 582 | ❌ **Pending** — Antipatterns, cookbook (screen flipping, borderless, PAL→NTSC handling) |
| 18 | `09_intuition/windows.md` | 370 | 778 | ✅ **Complete** — Added 5 named antipatterns (Border Collision, Unresponsive Close, Leaked Message, Refresh Loop, Phantom Window), window type decision guide with Mermaid, 3 cookbooks (resizable, borderless overlay, multi-window shared port), historical comparison, modern analogies, use cases, 7 FAQ |
| 19 | `09_intuition/menus.md` | 378 | 695 | ✅ **Complete** — Added render chain sequence diagram, 5 named antipatterns (Multi-Select Ghost, Stale Menu, Cleanup Reversal, Shortcut Collision, Phantom VisualInfo), complete lifecycle cookbook, historical comparison, modern analogies, use cases, 6 FAQ |
| 20 | `09_intuition/gadgets.md` | 403 | 403 | ❌ **Pending** — Named antipatterns, BOOPSI command flow, GadTools→BOOPSI migration guide |
| 20 | `09_intuition/gadgets.md` | 403 | 804 | ✅ **Complete** — Added 5 named antipatterns (Invisible Gadget, Message Mangler, Orphaned Chain, Hot-Swap Hazard, Silent Button), GadTools→BOOPSI migration guide with comparison table, form cookbook, historical timeline, modern analogies, use cases, 6 FAQ |
| 21 | `11_libraries/iffparse.md` | 271 | 1031 | ✅ **DONE** — Nesting & chunk hierarchy diagrams, ILBM/EHB pitfalls, PBM read patterns, cross-reference to Datatypes |
| 22 | `13_toolchain/gcc_amiga.md` | 82 | 82 | ❌ **Pending** — Extremely thin stub. Needs full build pipeline, Docker cross-compilation guide, linker scripts, amiga-gcc specifics |
| 23 | `11_libraries/layers.md` | 224 | 739 | ✅ **Complete** — Expanded with ClipRect engine deep-dive, API reference with LVOs, backfill hook cookbook, refresh type decision guide, 4 named antipatterns, 4 pitfalls, ClipBlit vs ScrollRaster optimization, historical comparison table, modern analogies, 7 FAQ |
@ -269,7 +269,7 @@ Articles were scored against [AGENTS.md](../amiga/AGENTS.md) "Deep" criteria:
| `commodities.md` | 769 | ✅ Deep | Tier 1 creation: Exchange, hotkeys, CxObjects, brokers |
| `screens.md` | 582 | ❌ Pending | Tier 3 #17: needs antipatterns, cookbook (screen flipping, borderless, PAL→NTSC) |
| `boopsi.md` | 505 | ✅ Adequate | OOP dispatcher, ICA interconnection, custom class tutorial |
| `gadgets.md` | 403 | ❌ Pending | Tier 3 #20: needs antipatterns, BOOPSI command flow, GadTools→BOOPSI guide |
| `gadgets.md` | 804 | ✅ Deep | 5 antipatterns, GadTools→BOOPSI migration, form cookbook, timeline, modern analogies, use cases, 6 FAQ |
| `menus.md` | 695 | ✅ Deep | Render chain diagram, 5 antipatterns, lifecycle cookbook, historical + modern analogies, use cases, 6 FAQ |
| `windows.md` | 778 | ✅ Deep | 5 named antipatterns, window type decision guide, 3 cookbooks (resizable, borderless, shared port), historical + modern analogies, use cases, 7 FAQ |
| `requesters.md` | 370 | ✅ Adequate | EasyRequest, ASL file/font/screenmode dialogs |