---
title: "radiatR design contract"
description: >
  The design rules behind the radiatR API: which objects are rich classes,
  which stay plain tibbles, and the conventions the functions share.
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{radiatR design contract}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(radiatR)
```

radiatR keeps a tidyverse-shaped surface: data flows as plain tibbles addressed
by column name, and rich objects are reserved for structure a flat table cannot
hold safely.

## Rich objects, only where structure is irreducible

- `Tracks` — trajectories with coordinate geometry, a per-trajectory reference
  frame, and transform history (invariants a bare tibble cannot enforce).
- `circ_display()` — an orientation convention (zero direction, rotation).
- `circ_regression()` — a fitted model (like `lm`).

## Everything else is a plain tibble, in and out

Plain tibbles are addressed by a column-name argument (`angle_col = "heading"`).
The `circular` package's `circular` objects are an internal implementation
detail — built inside functions, never in a public signature or return.

## `headings_frame`: a dplyr-durable tibble subclass

`headings_frame` is a tibble subclass that carries the display convention
durably through dplyr verbs (via the `dplyr_reconstruct` contract), so a
`mutate()`/`filter()` never silently drops the orientation. Read its metadata
with the `hf_*` accessors. A plain data frame with a heading column is always an
acceptable substitute — the class is an enhancement, never a requirement:

```{r, eval = requireNamespace("dplyr", quietly = TRUE)}
data(cpunctatus)
hd <- derive_headings(cpunctatus, rule = "distal")
hd2 <- dplyr::filter(hd, is.finite(heading))   # class + display preserved
class(hd2)
hf_display(hd2)
```
