19.08.25 Update. Wtat's new?
- Fully rewritten to stock graphics pipeline. Do not use SVG anymore (More freedom for customize).
- Fixed issue with scaling by Vertical and Horizontal (When keys and octave-marks incorrectly shows).
- Some core optimisations.
Many thanks to this wonderful people - @ustk for help! ️
Script:
/*
Author: It_Used, ustk
Date: 19.08.25 | 03:26
Copyright:(c)2025, Vienna Symphonic Library
*/
Content.makeFrontInterface(1140, 500);
// Change both-key spacing (white).
reg KeySpacing = 2;
// Change octave-mark visible.
reg ShowOctaveMark = 1;
// Octaves array.
const var Octaves = ["-2", "-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"];
// Key for octave center (add +-12 to change).
const var OctCenter = 60;
// Declare keyboard.
const var fltKeyboard = Content.getComponent("fltKeyboard");
// Create LookAndFeel.
const keyboardLaf = Content.createLocalLookAndFeel();
fltKeyboard.setLocalLookAndFeel(keyboardLaf);
keyboardLaf.registerFunction("drawKeyboardBackground", function(g, obj)
{
// Draw background.
g.fillAll(Colours.black);
});
// Draw white note via LAF.
keyboardLaf.registerFunction("drawWhiteNote", function(g, obj)
{
var mark_proportion = 0.75;
var font_proportion = 12.0 / 15.0;
var text_y_proportion = 1.5 / 15.0;
var mark_width = obj.area[2] * mark_proportion;
var mark_height = mark_width;
var font_size = mark_width * font_proportion;
var text_y_offset = mark_width * text_y_proportion;
if (!obj.down)
{
// Up key.
// Bottom bounds.
g.setColour(Colours.withAlpha(0x9E9E9E, 100));
g.fillRect([obj.area[0], obj.area[1] + 25, obj.area[2] - KeySpacing, obj.area[3] - 30]);
// Key body.
g.setColour(Colours.withAlpha(0xBABABA, 100));
g.fillRoundedRectangle([obj.area[0], obj.area[1] + 3, obj.area[2] - KeySpacing, obj.area[3] - 15], 2.50);
if (ShowOctaveMark && obj.noteNumber % 12 == 0)
{
var is_center = (OctCenter == obj.noteNumber);
var bg_color = is_center ? Colours.withAlpha(0xB26776, 100) : Colours.withAlpha(0x6B6B6B, 100);
var mark_x = obj.area[0] + (obj.area[2] - mark_width - KeySpacing) / 2;
var mark_y = obj.area[1] + obj.area[3] - 30;
g.setColour(bg_color);
g.fillEllipse([mark_x, mark_y, mark_width, mark_height]);
g.setFont("Inria Sans", font_size);
g.setColour(Colours.withAlpha(0xBABABA, 100));
g.drawAlignedText(Octaves[Math.floor(obj.noteNumber / 12) + 1], [mark_x, mark_y + text_y_offset, mark_width, mark_height], "centred");
}
}
else
{
// Down key.
// Top bounds.
g.setColour(Colours.withAlpha(0x666666, 100));
g.fillRoundedRectangle([obj.area[0], obj.area[1] + 3, obj.area[2] - KeySpacing, obj.area[3] - 15], 2.50);
// Key body gradient.
g.setGradientFill([Colours.withAlpha(0xD9D9D9, 100), obj.area[0], obj.area[1] + 5, Colours.withAlpha(0x737373, 100), obj.area[0], obj.area[1] + 90]);
g.fillRoundedRectangle([obj.area[0], obj.area[1] + 5, obj.area[2] - KeySpacing, obj.area[3] - 7], 2.50);
if (ShowOctaveMark && obj.noteNumber % 12 == 0)
{
var is_center = (OctCenter == obj.noteNumber);
var bg_color = is_center ? Colours.withAlpha(0xB26776, 100) : Colours.withAlpha(0x575757, 100);
var mark_x = obj.area[0] + (obj.area[2] - mark_width - KeySpacing) / 2;
var mark_y = obj.area[1] + obj.area[3] - 20;
g.setColour(bg_color);
g.fillEllipse([mark_x, mark_y, mark_width, mark_height]);
g.setFont("Inria Sans", font_size);
g.setColour(Colours.withAlpha(0xBABABA, 100));
g.drawAlignedText(Octaves[Math.floor(obj.noteNumber / 12) + 1], [mark_x, mark_y + text_y_offset, mark_width, mark_height], "centred");
}
}
});
// Draw black note via LAF.
keyboardLaf.registerFunction("drawBlackNote", function(g, obj)
{
if (!obj.down)
{
// Up key.
// Background.
g.setColour(Colours.black);
g.fillRoundedRectangle(obj.area, {CornerSize: 4, Rounded: [0, 0, 1, 1]});
// Top gradient.
g.setGradientFill([Colours.withAlpha(0x4C4C4C, 100), obj.area[0], obj.area[1] + 2, Colours.withAlpha(0x323232, 100), obj.area[0], obj.area[1] + 53]);
g.fillRoundedRectangle([obj.area[0] + 2, obj.area[1] + 2, obj.area[2] - 4, obj.area[3] - 10], 2);
// Bottom gradient.
g.setGradientFill([Colours.withAlpha(0x252525, 100), obj.area[0], obj.area[3] - 6, Colours.withAlpha(0x0D0D0D, 100), obj.area[0], obj.area[3]]);
g.fillRoundedRectangle([obj.area[0] + 2, obj.area[3] - 6, obj.area[2] - 4, 6], {CornerSize: 2, Rounded: [1, 1, 1, 1]});
}
else
{
// Down key.
// Background.
g.setColour(Colours.black);
g.fillRoundedRectangle(obj.area, {CornerSize: 4, Rounded: [0, 0, 1, 1]});
// Top gradient.
g.setGradientFill([Colours.withAlpha(0x3E3E3E, 100), obj.area[0], obj.area[1] + 4, Colours.withAlpha(0x262626, 100), obj.area[0], obj.area[1] + 52]);
g.fillRoundedRectangle([obj.area[0] + 2, obj.area[1] + 4, obj.area[2] - 4, obj.area[3] - 7], 2);
}
});
Snippet:
HiseSnippet 2126.3oc6YstaiiaEVNSzhMdm.rKP6+YCPWXOqiij7s3DDrIwNd2fIYlf0YlsEAAAzRz1rQVzPhNYbmlGh9l0Gk9FzdN5hMkhykw6rnKZqYfh44B4GO7vOQSdluvlEDH70xk+7oiYZ4dod2odxgsFR4dZG2VK2WpSct85QtZGNcLMHf4nkK2K9ATat0VUK7y+76Oj5R8rYyEoo8dA2lcBeDWNW5Y6+ZtqaGpC6b9HEqqt+w1BuVBWwD.IuP2PaL09Z5.1annYqnq8izfgZ4dkNyoeCCaSpikAqQCnRcyZ8Y8pVkY1neid8ZRsptMcaSsbewQNbovuqjJYAZ4V8PgyztCE25E0AumGv64xvJlZcgdNRbGgqCNDQoZsFxccNKIDEnAsxYyCXuHJf86zOk6vmIedf6qCUPl6gZ.L2Jog2KRAOSU3Yn.uE.obJPZ0HH8M5cs84iky0f34qzO1Sx76Sg4IUnDYq1Ju42qu0qVO+54W6fIxgB+cHGKu5cfQkHSBjWCxaCXcGhYyxFaW1pF4uQLpriUcPQKw3o97ACk6TvtnkgUsRj2yYddTR2oiFOT3wsImv64S8mhcvq1Be1R.vwSVdD8ZVGenxL3UvzrpQIRMCih6hVt0VDHr5MfQ5IjC27Z1TR.jfv8FPJb6PtjUr7548YCHulMsarh8HVY7UXKo2v1bD0+ZxMQg2X2v39aC0dJpbOhYhqQRCHTee5TvZHKMPRtg5OSydjK1XSqMJQ1XSS7oA9H7agBqfOphOpgOpiOZfO1FezLz3HWL23xjdEFFj9B+XDSrYXfgTf53P9tMMsHRAwNbLULKjZEY5dj5FIMValsK0mQfnVOA02IkK8ckuNVN3TxLx.lrkXzXgGTovFJ1rw74CeFjLPNQHt9.OmNLl6r1MoiNg1WoMsCc3DgM0UwoBXCpzAkCXx6YiRCF0+JBJCye7.XL2YhmsjK7JrgiO81j16PfFYfuXhmCDi6mXxfRDQu+Rw0y+w0ySfOXTBbhzal0kiTLnbefu5.W2BQbSAk64B1fn3tYghPWCSCIdB3wMbJ4jC5T94fyeFc6MfWKFdqEACblBSauZruXrvGMBhrFkaTa24FzGBzoMvzprAYKhYsxFJ1IYePd0zLVVtVZCyzu2xcjCA6.XUFxknWXcI4UYgztYbZHCYD.ul2DYga.+uxRY.zpYFG2G4h98grjrtcugU3zC5JuOove.QtCvtVLRV7De7j+6FiIskmKKk1CERoXDP8.4EAJFM.SVixKlkdbKWN7.2wCoEL9PyivRIhIPiUbWU+vjpehYKKbwr.pwkklGcMuj7cDjDUMduoB6lhlJnlJFWp1CofORlzCd4xm.xO7.r7fHGCDLGb..bPtrGcTT44OHLqAdaUtlwhGJ3zXFh5u8aCaBbU2alLpGP78GgjdxdvZihycTYtNIShGbkcBSYAEZy8xzdpHIw2dCtxFhYnqyalumrv3nU8FMpGEGI6rPSpeHVhLISmc+tNLg+CpqCMvXbgzQXkkEpg6hvJbqcefFcpZiFNwkMA6QAmZBUR7I6vIJ44HWW93.HmIZrTJt6Kof5RpzGWV7o63NB70TG64CDucodAHWZB6x8Qwxk5G4KRYefKefGy4bfuoP7l.t3TpbX49tBgegLIj.qpUQHbZB41YFyfzTLZObL.1d.lm4yhdAbBdtK5qw+i4FvVD4Vaf06wn2NWL9Smaqd3m+iyPrPhNx.epCG2yQlwyODKuC.wBWrngU6lXIZXUh7HfF3lWj+Mpfkmg+MSSXuDgsOg2Nz3+A4Uq0.K+lmW05+yq9aYd0LaxOby+e5ax+PzsGdS9el1kZ1e6xCMqL6Wv7DjOIIpkHerkv2i42El12gTsDI1zcHW.+Hc3OS3uKu6A2.J9BlkmRtZKr7LnTsVLkbEKr7bnzq7oRIG0o2CEoYMpduWhgcs0CFsh+0FKe.ypFVd7AbHPpu3.lQar7T9+KLVk.f6EqpeYl7MK07MynjsT4a+B29y+sttoxQX4Yj2WcwoAV0wxyYci0mi0MUex0MMTW1LmaNgPkH7PJ125UnX9Oles72kmjUU+9KTGdBU9BWWl+BUimTs+i4XAuvWIUBdqu6D1LC0xsZ5i38Kd3i3U8DnsiNvLECEdG6wkucLKt9ieF0Zwm3F7s2cbapjhmQbrLvtwLeIGgSt1ra31rnSLdM81rfqkhwg1FezeZ4doL9HtiNi3NtBpD1xy4b.1b.Aqqqb1cZeP83+mNuBe+v28NSv+3uueLdh5775yZhdCRtDfWpW0Z6pMp2rx1FZbIaThhuRuZMqlaWc6JlJxsh7nY0l0aX0rlFtC.06SHLPrxayo+QH+YCn+9YDRa.7KFkPIs4AicoSi13QzdL.k8o.qRn9SD3YJBhLsBq+i73pFaGVu0j.f1FVVNdH2NHkqsY8oSbkGLdLi5i2RRJsgaN.ZqeBhrBPiQ4Z0BUbtX.rv4TgSZ6w6T.OPaOlK18gxdW.68vJMguR+K8mvRT1wkJ6Jm5xTke5YGM6XcS0AmcDjw5Km2IVIxOxyQoqqm+NsnMRMep9Ouu18uNhuVGFES.Lj91Qv6PJVArdJ0URf2DfW.WNU8Nl9rckIOWH9M5mwk1CWLFWYAXDVo8qAFiuno00OpeeXZdN.WUuye5WmaURCHvwU5vFv84v5ZcXIQWXwjMKNA.Zb8bqfrMQ0Mv5XDnKyyIrx+B9DqzDqmKVoYhRsQTaewU1Qrn3UY8kgR.L4EdseqoeJVmXpExrpFmGAqBtx1NcScOGsVVGqrrNVcYcr1x5X8k0wFKqia+zNhjTGLAHDiV1noAjGgLv4xcjGEx.CyV092vq1OFJ