-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Roadmap #33
Comments
Hi @jaredjj3, thank you so much for reaching out! Atm I have no time for improving more features. |
Thanks for the update. I'm happy to help. Since my first comment, I've been enhancing a musicXML renderer called opensheetmusicdisplay. I created a system that allows developers to hook into events related to the music notation. The design proposal for official adoption is in this issue comment and a video clip showcasing some of the events is: Screen.Recording.2021-09-19.at.10.46.32.AM.movThis new system lets me know what notes, frets, and strings are being played (or about to be played). My goal for this week is to wire this data into fretboard.js. I will update this comment with some integration insights, bug reports, and/or feature requests after I finish. Perhaps this can seed a roadmap fretboard.js. |
Hey @jaredjj3 , that looks great! I have some similar examples made for abcjs, you may already have seen it. Btw I was very interested in integrating a similar system in a music education project I was working on, but I never managed to find any open source system that was mature enough to allow for flexible authoring / event listening. ABC notation is super easy to author, and the library is great too, but some features were not completely documented yet, plus it doesn't support tab out of the box. Keep me updated with the progress! |
I have great news! The integration was a breeze and a positive experience. I still need to style it, but it's functional. Here's a demo. Screen.Recording.2021-09-22.at.9.58.38.AM.movNB: All reference links are pinned at commit b860d3d881dc48f4c187b14526d4f78687b1469c. InsightsReact Component DevelopmentI created a React component which is being consumed by a page-level component. When developing the React component, I wanted to keep the same philosophy you had for fretboard.js. I purposely avoided making the component have an expressive API. It is the callers' responsibility to map semantics to styles. This approach made it feel like a more natural wrapper around fretboard.js instead of something more transformative. I also wanted to align with React's philosophy by maintaining a declarative API. A caller should be able to declare positions and styles, and the component will do the heavy lifting of making that happen. At one point, I was tempted to surface the fretboard.js Using the fretboard.js
|
Hey that looks awesome! In order: ReactI think the best way is to have a Some may be interested in using <Fretboard options={...}>
<Position string={6} fret={0}/>
<Position string={6} fret={3}/>
...
</Fretboard> style vs renderI am not satisfied with the semantics of the API myself. I think it may make more sense to split the filter operation from the styling - something like: fretboard
.selectPositions(({ degree }) => [1, 3, 5].includes(degree))
.style({ dotFill: 'red'}) I don't like the dots/positions name clash as well, I think position should be all over the place.
I think generics may help here - we could do:
And expose Feature Requests
Ok
See above
it is already the case ˆˆ the I will let you know when I manage to make any changes - PRs are welcome of course. Keep it up with the good work, looking forward to seeing some progress! |
Thanks for taking the time out to respond! I can't commit to a timeline, but I do plan to contribute fretboard.js. I like the React API you proposed. The child elements inherently have an order to them, and you could render different layers at a time—the last position rendered "wins" in terms of style. <Fretboard options={...}>
<Scale root="E" type="major" style={...} />
<Chord chord="022100" style={...} />
<Position string={6} fret={0} style={...} />
...
</Fretboard> Ultimately, I think the higher-level components are composed of I also like the selection API you proposed because it decouples the concern of rendering and selecting. One of the DX tradeoffs of this approach is the loss of fretboard.style<MyPosition extends Position>({ ... }); That generic would certainly clean things up, but I think the current state is good enough for the time being. It seems like a constant challenge to balance the caller's flexibility and type strength throughout the project, so I would rather wait to see if the API evolves into something that doesn't need generics. Ultimately, each position has some contextual metadata. Some metadata is readily calculable (e.g. On the other hand, I'm having trouble discerning if it's a good idea to allow metadata to be attached to each position within the library or not. After all, the caller can do this on their end, using |
I was able to achieve this React component API: <Fretboard opts={fretboardOpts} tuning={tuning}>
{measurePositions.map(({ string, fret }) => (
<Fretboard.Position string={string} fret={fret} />
))}
{pressedPositions.map(({ string, fret }) => (
<Fretboard.Position string={string} fret={fret} style={pressedStyle} />
))}
</Fretboard> The hardest part was creating a mechanism to associate a position with a single style. The reason why I imposed this constraint was to prevent styles from flashing when multiple styles were applied to a single position. While writing this, I realize that this may be the wrong solution because you might want to purposely apply partial styles at different layers. For example, the positions in the key of interest get a certain stroke color, while the pressed positions get a fill color, etc. I'll revisit this. Another challenge was preventing unnecessary renders due to the inability to memoize children. To accomplish this, I added an abstraction encapsulating
Now that there's a concrete solution, I want to elaborate on this from the previous comment. If you wanted to add something like a |
Yeah React makes things unnecessary complex for real-time stuff like this - a more imperative API works better, at least a direct event-bus / pubSub strategy. Layers: I thought about that, but since I haven't got a specific use case yet, I haven't worked on it. If you don't want to get mad with styles, you can just pass a |
I can see myself using this to make guitar exercises in the near future. The caller specifies a style merging strategy: I don't think the concepts of
This is the better solution for simple use cases. There's an ambiguous edge case when using multiple |
I got it to work for scales! The latest component code is here. Most of the interesting code is tucked away in Here's an example of a merged styling layers use case (albeit poorly styled): Screen.Recording.2021-09-23.at.8.49.06.PM.movNotes within the scale are always outlined in green. However, notes outside of the scale are outlined in red. What an intuitive way to learn about tension! |
I've written tests for the component, so I'm closing the integration story on my end. I'm extremely satisfied with the way it came out. Thank you for all of your help! Feel free to continue the discussion or close the thread. |
I wanted to let you know that I've done a soft release of stringsync. Anyone can access it at https://stringsync.com. You may have to hard refresh your browser. I'm using the implementation we discussed in this thread. I'd also like to know if you're interested in me adding the concept of guitar slides to fretboard.js. The implementation from the screenshot is a bit of a hack, but it is straightforward to officially implement. |
Hey @jaredjj3 , that looks neat! I like your implementation of slides, you could try to style the target positions lighter before reaching them - a bit of opacity may do. Most of all I think you have done an impressive work, and I am happy to have supported it somehow. Keep me posted! And great guitar playing too! |
I agree. I found myself running into a lot of cases that aren't so straight forward to represent:
I think context matters, too. For example, if you're in an dynamic context like stringsync, maybe you want to represent articulations differently than a static context. What I've seen in video games is making animations easily interpolatable. You provide the animation renderer an alpha value between 0 and 1, which describes the extent of the animation. Perhaps that could be leveraged to distinguish how to represent an articulation in static and dynamic contexts. I think I should see how I concretely answer all these questions before proposing formal adoption within fretboard.js. I'm happy to make a PR for slides now if you think otherwise.
Thank you for the library! I'd really like to give back by contributing directly to fretboard.js, so I will spend some time over the next few weeks to see if I can identify any opportunities. |
Thank you for the this library! I think it is extremely well made and I plan on using it after I figure out if the licensing is compatible.
What are the future plans of this project?
The text was updated successfully, but these errors were encountered: