Refactor the Piano component to highlight the root note of each chord. If this
makes things too easy, I can support this as a preference.
Also:
- Reduced the number of keys that the piano displays and increased the key
thickness to reclaim the space
- Preferred using Tailwind selectors instead of inline styling where applicable
- Call List.reverse on the keys to ensure that the top-most note is a lower note
than the bottom-most note
TODO:
- Support showing only the name of the chord and not just the notes that
comprise that chord
- Rewrite the function that generates the chords for a given range of notes
- Consider supporting a dark mode
Since I've published this, I should include an Overview page to orient potential
users. This Overview could be better -- as could many things with this app --
but it's a start, and I'm seeking small wins.
Observed problem: Tapping "C major, A minor" key, which LPC sets by default,
does not unset it.
Bug: handleClick passed the relativeMinor Key but the default value in
State.Model is the C Major key. We would toggled b/w [Cmajor] ->
[Cmajor,Aminor], and because toggled checked if either Cmajor or Aminor was
present, it was always true.
Solution: Check relativeMajor to set toggled.
Now that I have a deployed an MVP of my app, I am tidying things up to support
the next phase of development.
TL;DR:
- Moved application Model-related code into State module
- Moved each View into its own module
- Deleted unused ChordInspector component
- Deleted unused Msg's, {Increase,Decrease}Tempo
- Deleted misc unused code
The elm2nix expression builds my code as Main.min.js. As such, I changed my
index.html to require Main.min.js instead of elm.js. When I run elm-live now, I
make sure that I output Main.min.js as well. I need to gitignore this to exclude
it from my repository though.
After a few failed attempts at deploying my Elm application on NixOS, I'm trying
elm2nix, which some NixOS and Elm users created to attempt to solve some of the
issues that I ran into earlier today.
Elm tries to write to $HOME, which NixOS doesn't like. I typically prefer to
avoid things like cabal2nix, elm2nix, node2nix because I don't like the workflow
that they suggest, but I'm so eager to deploy this application, that I'm trying
it.
Thankfully @tazjin builds Gemma (an Elm project) with Nix, so I could reference
Gemma's default.nix to help me with mine. Elm problematically attempts to
HTTP-fetch a list of packages to verify my project's dependencies. Because Nix
builds derivations in a sandbox without network access, I need to use some
escape hatches (i.e. NIX_REDIRECTS, LD_PRELOAD,
SYSTEM_CERTIFICATE_PATH). Welp... it's packaged now...
I'm also pointing learnpianochords.app to this project's index.html. It will be
live soon! :)
TODO(wpcarro): Rename "Chord Drill Sergeant" -> "Learn Piano Chords" (KISS)
I'd like to deploy an MVP version of this application today, so I'm dropping
support for a few features to focus my efforts. I may bring these features
back.
TL;DR:
- Temporarily drop support for "Fine Tune" tab of preferences
- Sort keys by the Circle of Fifths
For now since I'm the only customer and I'm primarily making this for myself,
I'm styling the app specifically for my Google Pixel 4. If I find this app
useful, I will consider supporting other devices.
I'm using the Icons that I bought when I purchased the "Refactoring UI" book.
Other news:
- I bought the domain learnpianochords.app!
What's left:
- Style the "fine tune" tab of the preferences view
- Better support non-mobile devices like the browser and tablet devices
- Deploy the application to learnpianochords.app
- Redesign the "key" tab of the preferences view to sort the keys according to
the circle of fifths
- Dogfood
- Simplify until I cannot simplify anymore
Start styling the Chord Drill Sergeant for mobile devices because that is that
device on which I will primarily use CDS.
I'm also deleting the debugger related code. I would like to support a debugger,
but I'm not currently using this one, so I am going to remove it to keep things
slender.
- Introduce TailwindCSS, which also introduced elm-live, index.html, index.css
- Add mobile-first styling for the preferences modal
- Remove unused code
Generate chords for a given key.
I believe my Theory.allChords function is taking a long time to generate all of
the chord possibilities. I would like to profile this to verify this
assumption. I think I can create a "staging area" for changes and only
regenerate chords when "committing" the options from the "staging area". This
should stress the application less.
TODO: Profile application to find bottleneck.
For the past two to three days, I've been searching for the name for the concept
of "C" or "A". From what I read, notes are specific things like C0 or C4, but I
wanted the name of the concept of a C. Thankfully today I discovered that this
is called a pitch class.
Only show the chords that we can fit on the piano.
TODO: Debug occasional instance where we render chords that do not fit. I am
unsure how to reproduce these states at the moment.
While I did change a lot of functionality, I also ran `elm-format` across the
codebase, which makes these changes a bit noisy.
Here is the TL;DR:
- Properly support chord inversions
- Ensure that the piano styling changes dynamically when I change the variables
like `naturalWidth`
- Add start and end notes to define the size of the piano and which chords we
create
- Support elm-format and run it across entire project
- Debug Misc.comesBefore
- Introduce a ChordInspector and debugger
TODO: Ensure that we only generate chords where all of the notes can be rendered
on the displayed keys.
TODO: Add preferences panel, so that I can do things like "Practice blues chords
in C and E with chord substitutions."
Remodel application to support the scientific pitch notation for notes. Instead
of supporting simply "C", support "C4". This change created cascading
changes. After refactoring for around an hour, I restored the app to a working
state. The current state is not desirable, but it compiles. More changes on the
way.
Define two functions for attempting to return an element in a list that precedes
or succeeds another element.
I prefer having something like Utils.List. Perhaps I will refactor.
Using BPM as the unit for tempo.
TODO: Consider a higher-fidelity way to calculate BPM, although I'm not sure
this is critical functionality; an interesting problem is just seducing me, and
this app would be better off resisting the temptation.
Elm reminds me of Haskell. In fact, I'm using `haskell-mode` (for now) in Emacs
to write my Elm code, and it works reliably. I'm not writing a Haskell app, but
if I were, I would define my application Model with the following Haskell code:
```haskell
data Model = Model { whitelistedChords :: [Theory.Chord]
, selectedChord :: Theory.Chord
, isPaused :: Bool
, tempo :: Int
}
```
When I first modelled my application state, I did something similar. After
reading more Elm examples of SPAs, I see that people prefer using type aliases
to define records. As far as I know, you cannot do this in Haskell; I believe
all types are "tagged" (something about "nominal typing" comes to mind). Anyhow,
Elm isn't Haskell; Haskell has cool features like type classes; Elm has cool
features like human-readable error messages and exhaustiveness checking for
cases. I love Haskell, and I love Elm, and you didn't ask.
Anyhow, this commit refactors my records as type aliases instead of types. I
think the resulting code is more readable and ergonomic.
Create a more convincing representation of the piano.
I would like to compute the left-offset based on the naturalWidth. That change
is probably forthcoming.
First of all, Elm's purity is beautiful. I think every language should model
their error messages and develop experience after Elm. If I didn't have to
download packages, I don't think I would need an internet connection to
troubleshoot my program's errors. This is how helpful I find the compiler.
Now that that's out of the way, here's what I've changed since we've last
corresponded:
- Use Elm's Browser.element to create a reactive application with state
- Write a function to generate all of the chords about which CDS knows
- Move some code out of Main.elm into other modules
- Depend on List.Extra, Random, Random.Extra
What's left:
- Lots of work
- Instead of clicking a button to show a new chord, use a timer
- Add mobile-first styling (probably add TailwindCSS)
- Persist settings in LocalStorage (and then eventually create user accounts)
- Allow users to curate the list of chords they're interested in practicing
- Deploy the website and dogfood it
Unknowns:
- How can I handle tempo? I don't expect setInterval to be enough (maybe it
is)...
Initialize an Elm application to build a MVP for the Chord Drill Sergeant
application. There isn't much to see at the moment. I'm just sketching
ideas. More forthcoming...
See the README for more context on typo-po.
I drank a strong cup of coffee this morning, and I cannot quiet the activity in
my head. I'm attempting to use READMEs in my //website/sandbox to track ideas
that I would typically track using my phone's notes application. Creating a
README forces me to write more than I may have written in my phone's
notes. Also, since this repository is available at https://git.wpcarro.dev, I
can share these ideas with friends by sending them a URL! So much for "stealth
mode"... Well I guess this stress-tests my theory that ideas are less important
than execution.
In //website, I have the following directories about habits:
- days-of-week-habits
- habitgarden
- habits
Without READMEs in each of these directories, visitors (and myself) can
easily get confused.
I think it might be a good idea to version control my habits, so that I can
audit them as they change.
I'm publishing these on my website, so that I can refer to them wherever I had
internet.
briefcase's top-level .gitignore ignores node_modules, so I never noticed that
it was missing from my boilerplate .gitignore. I don't *really* need to add it
to that .gitignore, but if I want to cleanly eject directories from this
monorepo, it makes sense to keep the .gitignore files local to each project.
Problem:
Prettier was not running when I saved Emacs buffers.
Why?
- prettier-js-mode needs needs node; lorri exposes node to direnv; direnv
exposes node to Emacs; lorri was not working as expected.
Solution:
Now that I'm using nix-buffer, I can properly expose node (and other
dependencies) to my Emacs buffers. Now Prettier is working.
Commentary:
Since prettier hadn't worked for so long, I stopped thinking about it. As such,
I did not include it as a dependency in boilerplate/typescript. I added it
now. I retroactively ran prettier across a few of my frontend projects to unify
the code styling.
I may need to run...
```shell
$ cd ~/briefcase
$ nix-shell
$ npx prettier --list-different "**/*.{js,ts,jsx,tsx,html,css,json}"
```
...to see which files I should have formatted.
Lorri does not cleanly integrate with my corporate device, which cannot run
NixOS. To expose dependencies to Emacs buffers, I will use nix-buffer.el, which
reads its values from dir-locals.nix. To easily expose dependencies from my
existing shell.nix files into dir-locals.nix, I wrote a Nix utility function.
By default Parcel prefixes output paths with /. So when Chrome loads
wpcarro.dev/goals it attempts to get the CSS and JS and other assets from
wpcarro.dev/ instead of wpcarro.dev/goals/. Using the --public-url ./ option
makes Parcel output relative paths, which should work better for my needs.
After deploying the version of this application that built everything in the
browser, which originally was the impetus for the entire project, I learned that
the babel in-browser transformer won't work. I'm not sure why, but I need to
move on from this project and do other work.
I ported the code to my boilerplate/typescript, which works. Wahoo!
I used the boilerplate/typescript project as a starting point. This project
fetches and renders books that I'm defining in a Contentful CMS that I created.
- Create ./website directory
- Add a sitemap to wpcarro.dev
- Move covid-uk directory to sandbox directory
TODO: Next sandbox, blog, and learn in the website directory