The objective of the game is to guess the hue, saturation, and lightness values of a given color swatch across ten rounds.
This being my first svelte project, I'd like some insight into best practices, especially svelte-specific ones.
Versions
svelte
:^3.0.0
Specific questions
- Are my choices of abstraction adequate? Are there things that should or shouldn't be components of their own?
- In
src/components/swatch.svelte
, is it okay to style justdiv
(as opposed to adding a class.swatch
to the div and styling that), given that svelte scopes styles to the file? - In
src/components/results.svelte
, I'm a bit concerned about how complicated the score calculation line looks. Is there a way to clean that up a little bit? To my best knowledge I can't assign variables in svelte's template syntax. - Is it standard/acceptable to use an array of length
3
to represent an HSL colour or should I switch to an object with three keys, sayh
,s
, andl
? - I was considering using a
@svelte/store
to store the solution and input history, but eventually decided against it because I thought it was overkill for this. When would one use@svelte/store
?
I'm using prettier for linting, so please avoid feedback on code formatting.
Any other feedback is also welcome.
File structure
.
├── package-lock.json
├── package.json
├── public
│ ├── build
│ │ └── …
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── readme.md
├── rollup.config.js
└── src
├── app.svelte
├── components
│ ├── results.svelte
│ ├── slider.svelte
│ └── swatch.svelte
└── main.js
Code
I have replaced the contents of <style>
tags with …
for brevity.
src/main.js
import App from "./app.svelte";
const app = new App({
target: document.body,
props: {}
});
export default app;
src/app.svelte
<script>
import Swatch from "./components/swatch.svelte";
import Slider from "./components/slider.svelte";
import Results from "./components/results.svelte";
import random from "random-int";
import "../node_modules/milligram/dist/milligram.min.css";
let solution = randomColor();
let input = [0, 0, 0];
let history = [];
const totalRounds = 10;
let round = 1;
function save() {
const solutionCopy = [...solution];
const inputCopy = [...input];
history.push({
solution: solutionCopy,
input: inputCopy
});
round++;
solution = randomColor();
}
function randomColor() {
return [random(0, 255), random(0, 100), random(0, 100)];
}
</script>
<style>
…
</style>
<h1>Guess the HSL</h1>
{#if round <= totalRounds}
<label for="progress">Round {round} / {totalRounds}</label>
<progress id="progress" value={round} max={totalRounds} />
<div class="main">
<Swatch color={solution} inline={false} />
<Slider name="Hue" bind:value={input[0]} range={[0, 360]} step={1} />
<Slider
name="Saturation"
bind:value={input[1]}
range={[0, 100]}
step={1} />
<Slider
name="Lightness"
bind:value={input[2]}
range={[0, 100]}
step={1} />
</div>
<input type="submit" on:click={save} value="Submit" />
{:else}
<Results {history} />
{/if}
src/components/swatch.svelte
<script>
export let width = 50;
export let color = [0, 0, 0];
export let inline = true;
</script>
<style>
…
</style>
<div
style=" width: {width}px; height: {width}px; background: hsl({color[0]}, {color[1]}%,
{color[2]}%);"
class={inline ? '' : 'display'} />
src/components/slider.svelte
<script>
export let name;
export let value;
export let range = [0, 100];
export let step = 1;
</script>
<style>
…
</style>
<fieldset>
<legend>{name}</legend>
<input
type="range"
{name}
bind:value
min={range[0]}
max={range[1]}
{step} />
<input
type="number"
name="hue"
bind:value
min={range[0]}
max={range[1]}
{step} />
</fieldset>
src/components/results.svelte
<script>
import Swatch from "./swatch.svelte";
import round from "round-to";
import convert from "color-convert";
import { differenceCiede2000 as ciede2000 } from "d3-color-difference";
export let history = [];
</script>
<style>
…
</style>
<table>
<thead>
<th>Solution</th>
<th>Input</th>
<th>Score</th>
</thead>
{#each history as { solution, input }}
<tr>
<td>
<Swatch color={solution} width="25" />
<code>hsl({solution[0]}, {solution[1]}%, {solution[2]}%)</code>
</td>
<td>
<Swatch color={input} width="25" />
<code>hsl({input[0]}, {input[1]}%, {input[2]}%)</code>
</td>
<td>
{round(100 - ciede2000(`#${convert.hsl.hex(solution)}`, `#${convert.hsl.hex(input)}`), 2)}
</td>
</tr>
{/each}
</table>
```