Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
04453fd
style.backgroundColor,textColor,cornerSmoothing
nathanacurtis Feb 19, 2026
c874b8e
Add cornersmoothing to StyleKey type
nathanacurtis Feb 19, 2026
f483417
feat: add cornerSmoothing style property to types and schema
nathanacurtis Feb 19, 2026
64f26eb
Aligning version numbers
nathanacurtis Feb 19, 2026
046e501
Metadata License
nathanacurtis Feb 24, 2026
f425d17
Agent updates
nathanacurtis Feb 24, 2026
55ad86b
ADR-002 Shadows
nathanacurtis Feb 24, 2026
4828518
ADR 002 - Shadows CHANGELOG
nathanacurtis Feb 24, 2026
99d8fcf
Anova ADR agent updates
nathanacurtis Feb 24, 2026
f100ed1
Updated Shadows ADR
nathanacurtis Feb 25, 2026
e690809
Change ADR name
nathanacurtis Feb 25, 2026
744fff3
Accepting the Shadow ADR
nathanacurtis Feb 25, 2026
55fb8d3
Effects ADR note
nathanacurtis Feb 25, 2026
d22bcdf
Gradient ADR
nathanacurtis Feb 25, 2026
423f2b5
Updated Gradient changelog
nathanacurtis Feb 25, 2026
2ed3ed2
Merge pull request #22 from DirectedEdges/003-gradients
nathanacurtis Feb 25, 2026
8454c20
Update Shadows ADR status
nathanacurtis Feb 25, 2026
e8438c5
Merge pull request #24 from DirectedEdges/v0.11.0
nathanacurtis Feb 25, 2026
f105a1f
Aspect Ratio ADR
nathanacurtis Feb 25, 2026
6047306
Merge pull request #26 from DirectedEdges/004-aspect-ratio
nathanacurtis Feb 25, 2026
ef11c4d
Update schema/root.schema.json
nathanacurtis Feb 26, 2026
96998b7
ADR 005-Typography
nathanacurtis Feb 26, 2026
76b8365
Merge pull request #29 from DirectedEdges/005-typography-composite
nathanacurtis Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ You **MUST** consider the user input before proceeding (if not empty).

## Outline

1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root. Parse `REPO_ROOT`, `BRANCH`, `FEATURE_DIR`. All paths must be absolute.
1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root. Parse `REPO_ROOT`, `BRANCH`. All paths must be absolute.

2. **Load context**:
- **REQUIRED**: Read `$FEATURE_DIR/adr.md` — confirm Status is `PROPOSED` (if already `ACCEPTED`, report and halt)
- **REQUIRED**: Read `$REPO_ROOT/adr/$BRANCH.md` — confirm Status is `DRAFT` (if already `ACCEPTED`, report and halt)
- Confirm that `types/`, `schema/`, `package.json`, and `CHANGELOG.md` have been modified by `/speckit.implement` (check git status or file timestamps)
- If no changes are detected, halt: "Run `/speckit.implement` first."

Expand All @@ -27,7 +27,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- Run: `tsc --noEmit --strict tests/*.test-d.ts` (if `tests/*.test-d.ts` files exist)
- If exit code ≠ 0: halt and display errors. Do not set ACCEPTED.

4. **Mark ADR ACCEPTED**: In `$FEATURE_DIR/adr.md` header, change to `Status: ACCEPTED`.
4. **Mark ADR ACCEPTED**: In `$REPO_ROOT/adr/$BRANCH.md` header, change `Status: DRAFT` to `Status: ACCEPTED`.

5. **Report**: Confirm all gates passed and the ADR is now ACCEPTED. List the next steps: open PR → merge → `npm publish`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: Draft an Architecture Decision Record (ADR) for a proposed change to the anova types or schema package.
handoffs:
- label: Implement the ADR
agent: speckit.implement
agent: AnovaADR.implement
prompt: Implement the necessary changes for this ADR
send: true
---
Expand All @@ -17,46 +17,66 @@ You **MUST** consider the user input before proceeding (if not empty).

## Outline

1. **Setup**:
- Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root. Parse `REPO_ROOT` and `BRANCH`.
- Check whether `specs/$BRANCH/` already exists in the repo root.
- If the directory **exists**: the feature is already started. Skip `create-new-feature.sh`. Set `BRANCH_NAME=$BRANCH`, `FEATURE_DIR=$REPO_ROOT/specs/$BRANCH`, `SPEC_FILE=$FEATURE_DIR/adr.md`.
- If the directory **does not exist**: run `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS"` from repo root. Parse JSON for `BRANCH_NAME`, `SPEC_FILE`, `FEATURE_NUM`.
1. **Interactive setup** — ask the user two questions using VS Code's interactive question UI before doing anything else:

**Question 1 — Branch name**
- Header: `Branch`
- Question: "Which branch should this ADR be filed under?"
- Options (single-select):
1. `Use the current branch` — read the active git branch name via `git rev-parse --abbrev-ref HEAD` and use it as `BRANCH_NAME`
2. `Next minor version` — read the current version from `package.json`, increment the minor component, and format as `v[MAJOR].[MINOR+1].0`
3. `New ADR number` — count existing files in `adr/` and format as `[N+1]-[slugified user input]`; prompt user for the short description via the free-form fallback
4. `Other` — allow free-form text input
- After the user selects, resolve `BRANCH_NAME` per the rule above before continuing.

**Question 2 — ADR file name**
- Header: `ADR file`
- Question: "What should the ADR file be named? This becomes `adr/[name].md`. Use the format `###-short-description` (e.g. `002-shadows`)."
- Allow free-form input. No predefined options.

Parse the answers as `BRANCH_NAME` and `ADR_NAME`. All subsequent paths must use these values.

2. **File setup**:
- Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root. Parse `REPO_ROOT`.
- Set `SPEC_FILE=$REPO_ROOT/adr/$ADR_NAME.md`.
- Check whether `$SPEC_FILE` already exists. If it does, read it and continue editing rather than overwriting.
- All paths must be absolute.

2. **Load context**: Read `.specify/memory/constitution.md`. Read `.specify/templates/adr-template.md` — this is the output template you will fill.
3. **Load context**: Read `.specify/memory/constitution.md`. Read `.specify/templates/adr-template.md` — this is the output template you will fill.

3. **Understand the change**: From the user input and any open files, determine:
4. **Understand the change**: From the user input and any open files, determine:
- Which schema files in `schema/` are affected
- Which types in `types/` are affected (added, removed, renamed fields)
- Which downstream consumers are affected (`anova-transformer`, `anova-kit`, `anova-plugin`)
- Whether the change is MAJOR (breaking), MINOR (additive), or PATCH (non-semantic) per the constitution

4. **Evaluate options** *(skip if the decision is already made)*:
5. **Evaluate options** *(skip if the decision is already made)*:
- If the user input or context indicates the decision is pre-decided (e.g., "record and implement this decision"), omit this step and leave the Options Considered section of the ADR with a single entry marked *(Pre-decided — no alternatives evaluated)*.
- Otherwise, identify at least two alternative approaches and for each: assess against the constitution's Decision Drivers (type-schema sync, no logic, stable API, etc.) and state which is selected and which are rejected with clear rationale.

5. **Draft the ADR**: Fill `adr-template.md` and write to `specs/[branch]/adr.md`:
6. **Draft the ADR**: Fill `adr-template.md` and write to `$SPEC_FILE`:
- **Branch**: `BRANCH_NAME`
- **Status**: `DRAFT`
- **Context**: Current state of the relevant types/schema and what gap or opportunity this addresses
- **Decision Drivers**: Enumerate the constraints from the constitution that apply
- **Options Considered**: At least two options with pros/cons relative to the drivers
- **Decision**: Precise list of type and schema changes (file, field, modification type)
- **Type ↔ Schema Impact**: Confirm symmetry or document justified asymmetry
- **Downstream Impact**: Per-consumer impact table
- **Downstream Impact**: `anova-kit` only — see Key rules below
- **Semver Decision**: MAJOR / MINOR / PATCH with justification citing the constitution
- **Consequences**: What becomes true after acceptance

6. **Report**: Output `specs/[branch]/adr.md` path and a one-paragraph summary of the decision.
7. **Report**: Output `$SPEC_FILE` path and a one-paragraph summary of the decision.
## Formatting rules (apply when drafting the ADR)

- **Examples over prose**: Wherever a type shape, schema property, or field change is described, include a YAML example showing the before/after or the new structure. Prefer this over sentences explaining the same idea in abstract terms.
- **Bullets over enumeration**: Use bullet lists for Decision Drivers, Consequences, and any list of more than two items. Do not write "X, Y, and Z" as a sentence when a list would be clearer.
- **Backticks for terms**: All type names, field names, file names, and schema property paths MUST be in backtick format (e.g., `Config`, `license`, `types/Config.ts`, `#/properties/license`).
- **Types and schema only**: The ADR MUST describe only changes to `types/` and `schema/` within this package. Do NOT reference implementation classes, internal files, or processing logic from downstream packages (`anova-transformer`, `anova-plugin`, `anova-kit`). Downstream impact is described in terms of the observable API surface — what types or schema keys change — not how those packages implement consumption.

## Key rules

- Status MUST be `DRAFT` — never set to `ACCEPTED` in this command.
- The ADR describes *what* will change and *why*. It does not contain type or schema file content — those changes are applied directly by `/speckit.implement`.
- **Downstream Impact table**: Include only `anova-kit` as a consumer row. Do not add rows for `anova-transformer` or `anova-plugin` — those packages manage their own ADR and change workflows.
- If the change clearly violates a constitution gate (e.g., adds runtime logic), state the violation explicitly in the ADR and halt rather than proceeding without justification.
- Use absolute paths for all file operations.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: Applies the changes described in an ADR directly to types, schema, tests, and changelog. Runs all validation gates. Author reviews the result as a normal code diff before merging.
handoffs:
- label: Accept ADR
agent: speckit.accept
agent: AnovaADR.accept
prompt: All gates passed — mark the ADR as ACCEPTED
send: true
---
Expand Down Expand Up @@ -58,15 +58,21 @@ You **MUST** consider the user input before proceeding (if not empty).
- Create or update `tests/[type-name].test-d.ts` for each changed type using `tsd`-style assertions or `@ts-expect-error` patterns
- Run: `tsc --noEmit --strict tests/*.test-d.ts` to confirm test files compile
- If tests fail: halt and report
- **All gates have now passed. Steps 10 and 11 are REQUIRED before reporting completion. Do not skip to step 12.**

10. **Update CHANGELOG.md**:
- Prepend a new entry at the top using the existing format in the file
- Include: version number, date, concise consumer-facing description of what changed
- If MAJOR: include a `### Migration` subsection describing what callers must update
- **Format**: one top-level bullet per user-visible change; no sub-bullets; no bold; no code blocks; no wrapping prose paragraphs
- **Entry line**: `` `Parent.field` `` — one-phrase description; aim for ≤ 12 words; omit implementation detail (class names, file paths, method names)
- **Names**: `<Parent>.<field>` in backticks, em dash separator — e.g. `Styles.cornerSmoothing` — corner smoothing factor (0–1)
- **Sections**: use `### Added`, `### Changed`, `### Removed` as needed; add `### Migration` (MAJOR or rename only)
- **Migration line**: `` `Parent.old` → `Parent.new` ``: one sentence; imperative; describe what to read instead and how to handle the new type
- **Gate**: After writing, verify the new entry is present in the file. If CHANGELOG.md does not contain the new version heading, halt and report — do not proceed to step 11.

11. **Bump version in `package.json`**: Apply the `NEW` version from the ADR's Semver Decision.
- **Gate**: After writing, read `package.json` back and confirm the `"version"` field matches the ADR's `NEW` version. If it does not match, halt and report — do not proceed to step 12.

12. **Report**: List every file modified (with one-line description each). State that the author should review the diff and run `/speckit.accept` once satisfied.
12. **Report**: List every file modified (with one-line description each). The list **must** include `CHANGELOG.md` and `package.json` — if either is absent from the list, halt: steps 10–11 were not completed. State that the author should review the diff and run `/speckit.accept` once satisfied.

## Key rules

Expand Down
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,68 @@ All notable changes to the Anova schema will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.11.0] - 2026-02-25

### Added

- `Styles.typography` — composite typography property; value is `FigmaStyle` (text style reference), `Typography` (inline properties), or omitted when absent
- `Typography` interface — 13 optional fields for inline text styling: `fontSize`, `fontFamily`, `fontStyle`, `lineHeight`, `letterSpacing`, `textCase`, `textDecoration`, `paragraphIndent`, `paragraphSpacing`, `leadingTrim`, `listSpacing`, `hangingPunctuation`, `hangingList`
- `Typography` and `TypographyStyleValue` definitions in `schema/styles.schema.json`
- `'typography'` added to `StyleKey` union
- `Styles.aspectRatio` — optional aspect ratio constraint emitted when a node has a locked ratio; value is `AspectRatioValue` (`{ x: number; y: number }` numerator/denominator pair, e.g. `{ x: 16, y: 9 }`) or `null` when unconstrained; field is omitted from output entirely when no ratio is set
- `AspectRatioValue` — exported interface with required `x` (numerator) and `y` (denominator) number fields; named per existing specialised-type precedent (`GradientCenter`) rather than a generic `Vector`
- `AspectRatioStyle` — exported type alias `AspectRatioValue | null`; `VariableStyle` intentionally excluded as aspect ratio is a structural lock of literal numbers in the Figma API
- `AspectRatioValue` and `AspectRatioStyleValue` definitions in `schema/styles.schema.json`
- `'aspectRatio'` added to `StyleKey` union
- `Metadata.license?` — optional `{ status: string; description: string }` field; absent when no license is supplied
- `styles.textColor` — new style key for text colour
- `styles.cornerSmoothing` — new style key for corner smoothing (Figma squircle factor)
- `styles.effects` — new style key replacing `effectStyleId`; value is `FigmaStyle` when the node references a named effects style, or `EffectsGroup` when effects are defined inline
- `Shadow` interface — exported from `@directededges/anova`; fields: `visible` (boolean), `x`, `y`, `blur`, `spread` (number or `VariableStyle`), `color` (8-digit hex `#RRGGBBAA` or `VariableStyle`); used for both `dropShadows` and `innerShadows` entries
- `Blur` interface — exported from `@directededges/anova`; fields: `visible` (boolean), `radius` (number or `VariableStyle`)
- `EffectsGroup` interface — exported from `@directededges/anova`; fields: `dropShadows?` (`Shadow[]`), `innerShadows?` (`Shadow[]`), `layerBlur?` (`Blur`), `backgroundBlur?` (`Blur`)
- `Shadow`, `Blur`, `EffectsGroup`, and `EffectsStyleValue` definitions in `schema/styles.schema.json`
- `GradientStop` interface — fields: `position` (number, normalised 0–1), `color` (hex/rgba string or `VariableStyle`)
- `GradientCenter` interface — fields: `x`, `y` (number, normalised 0–1); centre point for RADIAL and ANGULAR variants
- `LinearGradient` interface — fields: `type: 'LINEAR'`, `angle` (degrees), `stops` (`GradientStop[]`)
- `RadialGradient` interface — fields: `type: 'RADIAL'`, `center` (`GradientCenter`), `stops` (`GradientStop[]`)
- `AngularGradient` interface — fields: `type: 'ANGULAR'`, `center` (`GradientCenter`), `stops` (`GradientStop[]`)
- `GradientValue` type — discriminated union `LinearGradient | RadialGradient | AngularGradient`; `type` field is the discriminant; DIAMOND excluded
- `ColorStyle` type — colour-specific style union (`string | VariableStyle | FigmaStyle | ReferenceValue | GradientValue | null`); mirrors `ColorStyleValue` in `schema/styles.schema.json`
- `GradientCenter`, `GradientStop`, `LinearGradient`, `RadialGradient`, `AngularGradient`, `GradientValue` definitions in `schema/styles.schema.json`

### Changed

- `Styles.backgroundColor` — narrowed from `Style` to `ColorStyle`; inline gradients now representable
- `Styles.textColor` — narrowed from `Style` to `ColorStyle`; inline gradients now representable
- `Styles.strokes` — narrowed from `Style` to `ColorStyle`; inline gradients now representable
- `ColorStyleValue` in `schema/styles.schema.json` — gains `{ "$ref": "#/definitions/GradientValue" }` variant
- `styles.fills` renamed to `styles.backgroundColor`

### Removed

- `Styles.fontSize` — removed; use `typography.fontSize` instead
- `Styles.fontFamily` — removed; use `typography.fontFamily` instead
- `Styles.fontStyle` — removed; use `typography.fontStyle` instead
- `Styles.lineHeight` — removed; use `typography.lineHeight` instead
- `Styles.letterSpacing` — removed; use `typography.letterSpacing` instead
- `Styles.textCase` — removed; use `typography.textCase` instead
- `Styles.textDecoration` — removed; use `typography.textDecoration` instead
- `Styles.paragraphIndent` — removed; use `typography.paragraphIndent` instead
- `Styles.paragraphSpacing` — removed; use `typography.paragraphSpacing` instead
- `Styles.leadingTrim` — removed; use `typography.leadingTrim` instead
- `Styles.listSpacing` — removed; use `typography.listSpacing` instead
- `Styles.hangingPunctuation` — removed; use `typography.hangingPunctuation` instead
- `Styles.hangingList` — removed; use `typography.hangingList` instead
- `Styles.textStyleId` — removed; use `typography` with `FigmaStyle` instead (named text style reference)
- `styles.effectStyleId` — removed with no deprecation period; consumers must migrate to `styles.effects` (see Migration)

### Migration

- `Styles.<typographyProperty>` → `Styles.typography.<property>`: all 14 flat typography properties replaced with single composite `typography` field. When `typography` is a `FigmaStyle` (text style reference), read `id` and `name`. When `typography` is a `Typography` object, read individual fields (`fontSize`, `fontFamily`, `fontStyle`, `lineHeight`, `letterSpacing`, `textCase`, `textDecoration`, `paragraphIndent`, `paragraphSpacing`, `leadingTrim`, `listSpacing`, `hangingPunctuation`, `hangingList`). Old `textStyleId` becomes `typography: { id, name }`.
- `fills` → `backgroundColor`: any consumer reading `component.styles.fills` must update to `component.styles.backgroundColor`.
- `effectStyleId` → `effects`: any consumer reading `styles.effectStyleId` must update to `styles.effects`. When `effects` is a `FigmaStyle`, the style `id` and `name` are available. When `effects` is an `EffectsGroup`, read from `dropShadows`, `innerShadows`, `layerBlur`, or `backgroundBlur` by role.

## [0.9.0] - 2026-02-12

### Added
Expand Down
Loading