---
title: "Core ggplot-like WebGL layers"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Core ggplot-like WebGL layers}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
ggwebgl_truthy <- function(x) {
  tolower(x) %in% c("1", "true", "yes", "y")
}

ggwebgl_ci_vars <- c(
  "CI",
  "GITHUB_ACTIONS",
  "GITLAB_CI",
  "BUILDKITE",
  "TRAVIS",
  "APPVEYOR",
  "CIRCLECI",
  "JENKINS_URL"
)
ggwebgl_is_ci <- any(vapply(Sys.getenv(ggwebgl_ci_vars), ggwebgl_truthy, logical(1)))
ggwebgl_is_check <- nzchar(Sys.getenv("_R_CHECK_PACKAGE_NAME_"))
ggwebgl_eval_code <- !ggwebgl_is_ci &&
  !ggwebgl_is_check &&
  (
    ggwebgl_truthy(Sys.getenv("NOT_CRAN")) ||
      ggwebgl_truthy(Sys.getenv("GGWEBGL_EVAL_COVERAGE_VIGNETTE"))
  )
ggwebgl_eval_widgets <- ggwebgl_eval_code &&
  ggwebgl_truthy(Sys.getenv("GGWEBGL_EVAL_LIVE_WIDGETS"))

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = ggwebgl_eval_code
)

library(ggplot2)
library(ggWebGL)
```

This vignette covers the core two-dimensional `ggplot2`-style layers and the
renderer-ready specification workflow. The code examples construct
`ggplot2`-style WebGL layers and, when evaluated, convert them into browser-side
WebGL htmlwidgets with `ggplot_webgl()` or `ggWebGL()`.

Code evaluation is disabled during CRAN, package checks, and CI unless
explicitly enabled with `GGWEBGL_EVAL_COVERAGE_VIGNETTE=true` or `NOT_CRAN=true`.
Live WebGL widget rendering is additionally disabled unless
`GGWEBGL_EVAL_LIVE_WIDGETS=true` is set. Rich local or pkgdown builds should set
both `GGWEBGL_EVAL_COVERAGE_VIGNETTE=true` and
`GGWEBGL_EVAL_LIVE_WIDGETS=true`.

```{r coverage-eval-note, echo = FALSE, results = "asis", eval = TRUE}
if (!ggwebgl_eval_code) {
  cat(
    "> Example chunks are shown but not evaluated in this build. ",
    "Set `GGWEBGL_EVAL_COVERAGE_VIGNETTE=true` or `NOT_CRAN=true` ",
    "to evaluate them during a local non-CI render.\n",
    sep = ""
  )
} else if (!ggwebgl_eval_widgets) {
  cat(
    "> Non-widget code chunks may evaluate in this build, but live WebGL ",
    "widgets are skipped. Set `GGWEBGL_EVAL_LIVE_WIDGETS=true` as well ",
    "to render browser-side widgets locally.\n",
    sep = ""
  )
}
```

# Two Workflows

## Applet: Grammar-style points and lines

```{r grammar-points-lines, eval = ggwebgl_eval_widgets}
p <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) +
  geom_point_webgl() +
  geom_line_webgl(aes(group = cyl), alpha = 0.35) +
  labs(title = "Grammar-style points and lines") +
  theme_webgl(shader = "density_splat")

ggplot_webgl(p, height = 420)
```

## Applet: Renderer-ready point specification

Renderer-ready specifications are useful when data have already been transformed
into primitive payloads.

```{r renderer-ready-points, eval = ggwebgl_eval_widgets}
spec <- ggwebgl_spec(
  layers = list(
    ggwebgl_layer_points(mtcars, x = "wt", y = "mpg", colour = "#2563eb")
  ),
  labels = list(title = "Renderer-ready point specification"),
  webgl = webgl_spec(shader = "density_splat")
)

ggWebGL(spec)
```

# Coverage Summary

| Family | Public APIs | Status | Notes |
|---|---|---|---|
| Points | `geom_point_webgl()` | Stable | Core scatter and dense point rendering. |
| Lines and paths | `geom_line_webgl()`, `geom_path_webgl()`, `geom_path3d_webgl()` | Stable / Experimental | Two-dimensional line/path rendering is core; 3D paths are experimental. |
| Segments and vectors | `geom_segment_webgl()`, `geom_vector_webgl()` | Stable / Experimental | Segments are plain line segments; vectors add arrow-oriented metadata. |
| Rectangles and tiles | `geom_rect_webgl()`, `geom_tile_webgl()` | Stable | Uses `ggplot2`-built rectangle bounds. |
| Count and bin geoms | `geom_bar_webgl()`, `geom_histogram_webgl()`, `geom_bin2d_webgl()` | Experimental | Counts and bins are computed by `ggplot2`; WebGL serialization is newer than core point/line/raster paths. |
| Curves and contours | `geom_freqpoly_webgl()`, `geom_density_webgl()`, `geom_density2d_webgl()`, `geom_contour_webgl()` | Experimental | Rendered as line/path primitives; see the statistical coverage vignette. |

Status labels reflect API maturity, test coverage, and rendering-contract
stability; they are not simply an export list.

# Core 2D Layers

## Applet: Ordered 2D path with segments

```{r ordered-path-segments, eval = ggwebgl_eval_widgets}
trajectory <- data.frame(
  x = cos(seq(0, 2 * pi, length.out = 48)) * seq(0.2, 1, length.out = 48),
  y = sin(seq(0, 2 * pi, length.out = 48)) * seq(0.2, 1, length.out = 48),
  frame = seq_len(48),
  group = "spiral"
)

arrows <- data.frame(
  x = c(-0.8, -0.2, 0.4),
  y = c(-0.6, 0.1, 0.5),
  xend = c(-0.45, 0.15, 0.75),
  yend = c(-0.25, 0.35, 0.2)
)

p <- ggplot(trajectory, aes(x, y, group = group)) +
  geom_path_webgl(aes(frame = frame), colour = "#2563eb", linewidth = 1.2) +
  geom_point_webgl(aes(frame = frame), colour = "#0f766e", size = 1.8) +
  geom_segment_webgl(
    data = arrows,
    aes(x = x, y = y, xend = xend, yend = yend),
    inherit.aes = FALSE,
    colour = "#334155"
  ) +
  labs(title = "Ordered 2D path with segments")

ggplot_webgl(p, height = 420)
```

## Applet: Line sorting versus path order

`geom_line_webgl()` keeps the usual line semantics, while
`geom_path_webgl()` preserves row order within groups.

```{r line-sorting-path-order, eval = ggwebgl_eval_widgets}
ordered <- data.frame(
  x = c(3, 1, 2, 4),
  y = c(1, 3, 2, 4),
  group = "ordered"
)

p <- ggplot(ordered, aes(x, y, group = group)) +
  geom_line_webgl(colour = "#64748b") +
  geom_path_webgl(colour = "#dc2626", linewidth = 1.2) +
  labs(title = "Line sorting versus path order")

ggplot_webgl(p, height = 420)
```

# Rectangles, Tiles, and Bins

Rectangle-style geoms use boundaries computed by `ggplot2::ggplot_build()`.
This keeps position adjustments and statistical transformations owned by
`ggplot2`.

## Applet: Tile grid

```{r tile-grid, eval = ggwebgl_eval_widgets}
tile_grid <- expand.grid(
  x = seq_len(5),
  y = seq_len(4),
  KEEP.OUT.ATTRS = FALSE
)
tile_grid$value <- with(tile_grid, sin(x / 2) + cos(y / 2))

p <- ggplot(tile_grid, aes(x, y, fill = value)) +
  geom_tile_webgl(alpha = 0.85) +
  labs(title = "Tile grid")
ggplot_webgl(p, height = 420)
```

## Applet: Stacked bar counts

```{r stacked-bar-counts, eval = ggwebgl_eval_widgets}
p <- ggplot(mtcars, aes(factor(cyl), fill = factor(am))) +
  geom_bar_webgl(position = "stack") +
  labs(title = "Stacked bar counts")
ggplot_webgl(p, height = 420)
```

## Applet: Histogram bins

```{r histogram-bins, eval = ggwebgl_eval_widgets}
p <- ggplot(mtcars, aes(mpg)) +
  geom_histogram_webgl(binwidth = 4) +
  labs(title = "Histogram bins")
ggplot_webgl(p, height = 420)
```

## Applet: Two-dimensional bins

```{r two-dimensional-bins, eval = ggwebgl_eval_widgets}
p <- ggplot(mtcars, aes(wt, mpg)) +
  geom_bin2d_webgl(bins = 8) +
  labs(title = "Two-dimensional bins")
ggplot_webgl(p, height = 420)
```

## Applet: Explicit rectangles

```{r explicit-rectangles, eval = ggwebgl_eval_widgets}
rectangles <- data.frame(
  xmin = c(0.0, 1.2),
  xmax = c(1.0, 2.0),
  ymin = c(0.0, 0.4),
  ymax = c(0.8, 1.4),
  label = c("a", "b")
)

p <- ggplot(rectangles) +
  geom_rect_webgl(
    aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = label),
    alpha = 0.75
  ) +
  labs(title = "Explicit rectangles")

ggplot_webgl(p, height = 420)
```

# Curves and Contours

Curve and contour applets are in
`vignette("ggplot-coverage-summaries", package = "ggWebGL")` so this page keeps
its live widget count moderate.
