Skip to content

Commit

Permalink
build a lint, fix some stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
mcnuttandrew committed Feb 12, 2024
1 parent 2862cf4 commit 8199d15
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 82 deletions.
74 changes: 39 additions & 35 deletions LintLanguageDocs.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,54 @@
Expressions
EXPR = Conjunction | Quantifier | Comparison | Boolean
Conjunction | Quantifier | Comparison | Boolean

Value = Variable | Number | Color | Boolean

Conjunctions:
AND: {and: [EXPR, EXPR, ...]}
OR: {or: [EXPR, EXPR, EXPR]}
NOT: {not: EXPR}
{and: [EXPR, EXPR, ...]}
{or: [EXPR, EXPR, EXPR]}
{not: EXPR}

Quantifiers:
FORALL: {all: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
EXISTS: {exists: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
{all: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
{exists: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}

Comparisons (value) => expression
similar: {"similar": {left: Value, right: Value, threshold: Number}}
equal: {"==": {left: Value, right: Value}}
not equal: {"!=": {left: Value, right: Value}}
less than: {"<": {left: Value, right: Value}}
greater than: {">": {left: Value, right: Value}}

Value = Variable | Number | Color | Boolean
Comparisons:
{"similar": {left: Value, right: Value, threshold: Number}}
{"==": {left: Value, right: Value}}
{"!=": {left: Value, right: Value}}
{"<": {left: Value, right: Value}}
{">": {left: Value, right: Value}}

Operations:
Math Operations:
\*: {left: Number | Variable, right: Number | Variable}
+: {left: Number | Variable, right: Number | Variable}
/: {left: Number | Variable, right: Number | Variable}
-: {left: Number | Variable, right: Number | Variable}

dist: {left: Color | Variable, right: Color | Variable, space: COLOR_SPACE }
deltaE: {left: Color | Variable, right: Color | Variable, algorithm: '2000' | etc }
contrast: {left: Color | Variable, right: Color | Variable, algorithm: | "APCA" | "WCAG21" | "Michelson" | "Weber" | "Lstar" | "DeltaPhi"}

count: {count: Variable | Number[] | Color[]}
sum: {sum: Variable | Number[]}
min: {min: Variable | Number[]}
max: {max: Variable | Number[]}
mean: {mean: Variable | Number[]}
first: {first: Variable | Number[]}
last: {last: Variable | Number[]}
extent: {extent: Variable | Number[]}

toColor: {toColor: variableName, space: 'lab' | 'hsl' | etc, channel: 'a' | 'b' | 'l' | etc}
cvdSim: {cvdSim: variableName, type: 'protanomaly' | 'deuteranomaly' | 'tritanopia' | 'grayscale'}
name: {name: variableName}

map: {map: Variable | Value[], func: Operation, varb: Variable}
sort: {sort: Variable | Value[], func: Operation, varb: Variable}
filter: {filter: Variable | Value[], func: EXPR, varb: Variable}
Value Comparisons:
{dist: {left: Color | Variable, right: Color | Variable}, space: COLOR_SPACE }
{deltaE: {left: Color | Variable, right: Color | Variable}, algorithm: '2000' | etc }
{contrast: {left: Color | Variable, right: Color | Variable}, algorithm: | "APCA" | "WCAG21" | "Michelson" | "Weber" | "Lstar" | "DeltaPhi"}

Aggregates
{count: Variable | Number[] | Color[]}
{sum: Variable | Number[]}
{min: Variable | Number[]}
{max: Variable | Number[]}
{mean: Variable | Number[]}
{first: Variable | Number[]}
{last: Variable | Number[]}
{extent: Variable | Number[]}

Color Manipulations:
{toColor: variableName, space: 'lab' | 'hsl' | etc, channel: 'a' | 'b' | 'l' | etc}
{cvdSim: variableName, type: 'protanomaly' | 'deuteranomaly' | 'tritanopia' | 'grayscale'}
{name: variableName}

Maps:
{map: Variable | Value[], func: Operation, varb: Variable}
{sort: Variable | Value[], func: Operation, varb: Variable}
{filter: Variable | Value[], func: EXPR, varb: Variable}

```yaml
---
Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ Macros story
# Language todos

- [ ] Add more blame robustness, may pay to try to reason across all of the operator families (insight: keep a list of the blamable variables in the environment to support tracing)
- [ ] Add background, roles, palette level semantics
- [ ] Categorical mutually distinct
- [ ] roles, palette level semantics
- [ ] per cols 4 all: color blindness metric should maybe be sensitive to task?
- [ ] Sequential check fix is incorrect for things with equi-ligthness
- [x] Add background,
- [x] Categorical mutually distinct
- [x] Integration into main app
- [x] "Blame" for colors
- [x] JSON Schema (for validation) (if parser is not used), get a sustainable way to use it
Expand All @@ -31,20 +34,21 @@ Macros story

# Todo bankruptcy

- [ ] Search paletes by lint screen
- [ ] Search palettes-by-lint screen
- [ ] off by one persistance error in undo/redo
- [ ] Gamut algorithm broken again
- [ ] Add HCT/CAM, add explainers to each of the color spaces, blocked by colorjs release
- [ ] Allow no palettes, allows renaming of non-current palettes
- [ ] Allow no palettes, allows renaming of non-current palettes, which would be enable by:
- [ ] Parameterize the scatter column completely, allow edits to the compare stuff
- [ ] Colors from String should save on enter?
- [ ] Changing spaces is pretty bad on lab <-> oklab, cf ("#35ffbf", "#87b995", "#e84f82")
- [ ] "Easy on ramp" progressive disclosure
- [ ] per cols 4 all: color blindness metric should maybe be sensitive to task?
- [ ] Labels, tooltips, etc
- [ ] Bug: Color channel usage slightly cursed (doesn't update positions correctly)
- [ ] Bug: rotate in polar coordinates doesn't work right
- [ ] Directional subtile for aligns, they do not work in polar also
- [ ] Sequential check fix is incorrect for things with equi-ligthness
- [ ] Performance stuff for linter (separate message generation into something very throttled, maybe move to web workers? Cache as hard as possible)
- [ ] Hover broken on compare
- [x] Gamut algorithm broken again
- [x] Add up/down manipulation to palettes

# Nice to have
Expand Down
72 changes: 44 additions & 28 deletions netlify/functions/suggest-lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,56 @@ You are a color expert and domain-specific language programmer. You take in a li
# Task and output format
Given a lint prompt, suggest a lint using the color check linting language Your response should be a JSON object written in the following JSON DSL. You must be explicit in your response and include all necessary information. If a list of colors is suggest you should guess what those colors are and give explicit values
Expressions
EXPR = Conjunction | Quantifier | Comparison | Boolean
Conjunction | Quantifier | Comparison | Boolean
Value = Variable | Number | Color | Boolean
Conjunctions:
AND: {and: [EXPR, EXPR, ...]}
OR: {or: [EXPR, EXPR, EXPR]}
NOT: {not: EXPR}
{and: [EXPR, EXPR, ...]}
{or: [EXPR, EXPR, EXPR]}
{not: EXPR}
Quantifiers:
FORALL: {all: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
EXISTS: {exist: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
{all: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
{exists: {varbs: Variable[], predicate: EXPR, where?: EXPR, in: Variable | Value[]}}
Comparisons (value) => expression
similar: {"similar": {left: Value, right: Value, threshold: Number}}
equal: {"==": {left: Value, right: Value}}
not equal: {"!=": {left: Value, right: Value}}
less than: {"<": {left: Value, right: Value}}
greater than: {">": {left: Value, right: Value}}
Comparisons:
{"similar": {left: Value, right: Value, threshold: Number}}
{"==": {left: Value, right: Value}}
{"!=": {left: Value, right: Value}}
{"<": {left: Value, right: Value}}
{">": {left: Value, right: Value}}
Value = Variable | Number | Color | Boolean
Variable = string | colors | background
Operations:
*|+|/|-: {left: Number | Variable, right: Number | Variable}
dist: {left: Color | Variable, right: Color | Variable, space: COLOR_SPACE }
deltaE: {left: Color | Variable, right: Color | Variable, algorithm: '2000' | etc }
contrast: {left: Color | Variable, right: Color | Variable, algorithm: | "APCA" | "WCAG21" | "Michelson" | "Weber" | "Lstar" | "DeltaPhi"}
count: {count: Variable | Number[] | Color[]}
sum|min|max|mean|first|last|extent: {sum: Variable | Number[]}
toColor: {toColor: variableName, space: 'lab' | 'hsl' | etc, channel: 'a' | 'b' | 'l' | etc}
cvdSim: {cvdSim: variableName, type: 'protanomaly' | 'deuteranomaly' | 'tritanopia' | 'grayscale'}
name: {name: variableName}
map|sort: {map: Variable | Value[], func: Operation}
filter: {filter: Variable | Value[], func: EXPR}
Math Operations:
\*: {left: Number | Variable, right: Number | Variable}
+: {left: Number | Variable, right: Number | Variable}
/: {left: Number | Variable, right: Number | Variable}
-: {left: Number | Variable, right: Number | Variable}
Value Comparisons:
{dist: {left: Color | Variable, right: Color | Variable}, space: COLOR_SPACE }
{deltaE: {left: Color | Variable, right: Color | Variable}, algorithm: '2000' | etc }
{contrast: {left: Color | Variable, right: Color | Variable}, algorithm: | "APCA" | "WCAG21" | "Michelson" | "Weber" | "Lstar" | "DeltaPhi"}
Aggregates
{count: Variable | Number[] | Color[]}
{sum: Variable | Number[]}
{min: Variable | Number[]}
{max: Variable | Number[]}
{mean: Variable | Number[]}
{first: Variable | Number[]}
{last: Variable | Number[]}
{extent: Variable | Number[]}
Color Manipulations:
{toColor: variableName, space: 'lab' | 'hsl' | etc, channel: 'a' | 'b' | 'l' | etc}
{cvdSim: variableName, type: 'protanomaly' | 'deuteranomaly' | 'tritanopia' | 'grayscale'}
{name: variableName}
Maps:
{map: Variable | Value[], func: Operation, varb: Variable}
{sort: Variable | Value[], func: Operation, varb: Variable}
{filter: Variable | Value[], func: EXPR, varb: Variable}
Example prompt: All colors should be color blind friendly for deuteranopia
Example Result:
Expand Down
18 changes: 9 additions & 9 deletions src/lib/lint-language/lint-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ type LintComparison =
type MathOperations = "+" | "-" | "*" | "/";
type LintMathOps = Record<MathOperations, Number | LintVariable>;
type LintPairOps =
| { dist: { left: LintRef; right: LintRef; space: "lab" | "hsl" } }
| { deltaE: { left: LintRef; right: LintRef; algorithm: "2000" | "76" } }
| { dist: { left: LintRef; right: LintRef }; space: "lab" | "hsl" }
| { deltaE: { left: LintRef; right: LintRef }; algorithm: "2000" | "76" }
| {
contrast: {
left: LintRef;
right: LintRef;
algorithm:
| "APCA"
| "WCAG21"
| "Michelson"
| "Weber"
| "Lstar"
| "DeltaPhi";
};
algorithm:
| "APCA"
| "WCAG21"
| "Michelson"
| "Weber"
| "Lstar"
| "DeltaPhi";
};
type LintMap =
// | { map: LintVariable | LintValue[]; func: LintColorFunction | LintPairOps }
Expand Down
9 changes: 6 additions & 3 deletions src/linting/Eval.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
$: evalConfig = currentPal.evalConfig;
$: customLints = $lintStore.lints;
// $: checks = runLintChecks(currentPal, palType, customLints, evalConfig);
let checks = [] as ColorLint<any, any>[];
let updateSearchDebounced = debounce(100, (pal: any) => {
checks = runLintChecks(pal, palType, customLints, evalConfig);
$: checks = [] as ColorLint<any, any>[];
$: selectedLint = $lintStore.focusedLint;
$: updateSearchDebounced = debounce(100, (pal: any) => {
if (!selectedLint) {
checks = runLintChecks(pal, palType, customLints, evalConfig);
}
});
$: updateSearchDebounced(currentPal);
Expand Down
5 changes: 5 additions & 0 deletions src/scatterplot/ColorScatterPlot.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,11 @@
&nbsp;
{/if}
</div>
{#if $configStore.showGamutMarkers}
<div class="flex items-center text-sm w-full justify-center">
X indicates value that is out of gamut
</div>
{/if}

<style>
circle {
Expand Down
24 changes: 24 additions & 0 deletions src/stores/built-in-lints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,30 @@ const BUILT_INS: CustomLint[] = [
id: `colorblind-friendly-${type}-built-in`,
blameMode: "pair" as const,
})),

{
program: toString({
all: {
in: "colors",
varbs: ["a", "b"],
where: { "!=": { left: "index(a)", right: "index(b)" } },
predicate: {
">": {
left: { dist: { left: "a", right: "b" }, space: "lab" },
right: 15,
},
},
},
}),
name: "Mutually Distinct",
taskTypes: ["categorical"] as const,
group: "usability",
level: "error",
description: `All colors in a palette should be different from each other. This is because if they are not, then they will not be differentiable from each other in some contexts.`,
failMessage: `Some colors in this palette ({{blame}}) are not differentiable from each other.`,
id: "mutually-distinct-built-in",
blameMode: "pair" as const,
},
];

export default BUILT_INS;

0 comments on commit 8199d15

Please sign in to comment.