Visualisation Next Generation

Extended GUI for ioBroker

Current Release
2.15.5
Developer
bluefox
License
CC-BY-NC-4.0

WEB visualization for ioBroker platform.

Overview

License requirements

To use this adapter in ioBroker you need to accept the source code license of the adapter. The source code of this adapter is available under the CC BY-NC license.

Additionally, you need a license to use the adapter. The following license editions are available on https://iobroker.net/www/pricing

  • Community-License: Free for private use!: Get a free license by registering an account on https://iobroker.net. The license if checked online against the ioBroker license server when the vis-2 adapter is started, so an online connection at this time point is required!
  • Private use Offline-License: For paying a small support fee, you can get rid of the required online license check on adapter startup. Only for Private use!
  • Commercial License: When using Vis in a commercial environment or selling Vis as a part of ioBroker packages to your customers, this license is for you. License check is also not requiring an online connection.

Installation & Documentation

Demo interface Demo interface

Online Demos

Bindings of objects

Normally, most of the widgets have ObjectID attribute, and this attribute can be bound with some value of object ID. But there is another option for how to bind any attribute of widget to some ObjectID.

Just write into attribute {object.id} e.g. {hm-rpc.0.OEQ1880105.4.ACTUAL_TEMPERATURE} and it will be bound to this object's value. If you use the special format, you can even make some simple operations with it, e.g., multiplying or formatting.

E.g., to calculate the hypotenuse of a triangle:

{h:javascript.0.myCustom.height;w:javascript.0.myCustom.width;Math.max(20, Math.sqrt(h*h + w*w))} will be interpreted as function:

value = await (async function () {
    var h = (await getState('javascript.0.myCustom.height')).val;
    var w = (await getState('javascript.0.myCustom.width')).val;
    return Math.max(20, Math.sqrt(h * h + w * w));
})();

or

{h:javascript.0.myCustom.height;w:javascript.0.myCustom.width;h*w} will simply multiply height with width.

You can use any JavaScript (browser) functions. Arguments must be defined with ':', if not, it will be interpreted as formula.

Take care about types. All of them are defined as strings. To be sure, that value will be treated as a number use parseFloat function.

So our Hypotenuse calculation will be:

{h:javascript.0.myCustom.height;w:javascript.0.myCustom.width;Math.max(20, Math.sqrt(Math.pow(parseFloat(h), 2) + Math.pow(parseFloat(w), 2)))}

Deprecated format

Patten has the following format:

{objectID;operation1;operation2;...}

The following operations are supported:

  • * - multiplying. Argument must be in brackets, like "*(4)". In this sample, we multiply the value with 4.
  • + - add. Argument must be in brackets, like "+(4.5)". In this sample we add to value 4.5.
  • - - subtract. Argument must be in brackets, like "-(-674.5)". In this sample we subtract from value -674.5.
  • / - dividing. Argument must be in brackets, like "/(0.5)". In this sample, we divide the value by 0.5.
  • % - modulo. Argument must be in brackets, like "%(5)". In this sample, we take modulo of 5.
  • round - round the value.
  • round(N) - round the value with N places after point, e.g., 34.678;round(1) => 34.7
  • hex - convert value to hexadecimal value. All letters are lower cased.
  • hex2 - convert value to hexadecimal value. All letters are lower cased. If value less 16, so the leading zero will be added.
  • HEX - same as hex, but upper-cased.
  • HEX2 - same as hex2, but upper-cased.
  • date - format date according to given format. Format is the same as in iobroker.javascript
  • min(N) - if value is less than N, take the N, else value
  • max(M) - if value is greater than M, take the M, else value
  • sqrt - square root
  • pow(n) - power of N.
  • pow - power of 2.
  • floor - Math.floor
  • ceil - Math.ceil
  • json - operation for getting JSON or object property. E.g., {id;json(common.name.en)}
  • random(R) - Math.random() * R, or just Math.random() if no argument
  • formatValue(decimals) - format value according to system settings and use decimals
  • date(format) - format value as date. The format is like: "YYYY-MM-DD hh:mm:ss.sss"
  • momentDate(format, useTodayOrYesterday) - format value as date using Moment.js. Approved formats must be entered according to the moment.js library. With useTodayOrYesterday=true the moment.js format ddd/dddd are overwritten with today / yesterday
  • array(element1,element2[,element3,element4]) - returns the element of index. e.g.: {id.ack;array(ack is false,ack is true)}

You can use this pattern in any text, like

My calculations with {objectID1;operation1;operation2;...} are {objectID2;operation3;operation4;...}

or color calculations:

#{objectRed;/(100);*(255);HEX2}{objectGreen;HEX2}{objectBlue;HEX2}

To show timestamp of an object write .ts or .lc (for last change) at the end of object id, e.g.:

Last change: {objectRed.lc;date(hh:mm)}

Special bindings

There are a number of different internal bindings to provide additional information in views:

  • username - shows logged-in user
  • view - name of actual view
  • wname - widget name
  • widget - is an object with all data of widget. Can be used only in JS part, like {a:a;widget.data.name}
  • widgetOid - use the OID of the widget to assign the widget's value in the assignment section, like {t:widgetOid.val;t}
  • wid - name of actual widget
  • language - can be de, en or ru.
  • instance - browser instance
  • login - if login required or not (e.g., to show/hide logout button)
  • local_* - if state name is started from local_ it will not be reported to ioBroker but will update all widgets, that depends on this state. (Local variable for current browser session)

Note: to use ":" in calculations (e.g., in string formula), use "::" instead.

Remember that style definitions will be interpreted as bindings, so use {{style: value}} or just

{
	style: value
}

for that.

Filters

To visualize on the one view the whole number of widgets, you can use filters to reduce the count of widgets simultaneously shown on the view.

Every widget has a field filter. If you set it to some value, e.g. light, so you can use other widget (bars - filters, filter - dropdown) to control which filter is actually active.

The entries of the filter - dropdown widget (buttons as well as dropdown items) have the CSS class vis-filter-item, and the currently active entries additionally vis-filter-item-active, so they can be styled in the project CSS, e.g.:

/* buttons (horizontal / vertical) */
.vis-filter-item-active {
    background-color: #ff0000;
}

/* entries of the dropdown */
.vis-filter-item-active.Mui-selected {
    background-color: #ff0000;
}

Two rules are required, because the active entry of the dropdown additionally has the class Mui-selected, and its own background color is more specific than .vis-filter-item-active alone.

Please note:

  • If a color is configured for an entry in the widget itself, it is written as an inline style and cannot be overwritten with the color property from the project CSS. Leave the color of the entry empty if you want to set it via CSS.
  • The entries of the dropdown are rendered outside the widget (in a popup on page level), so they can only be addressed globally and not with a selector for a single widget, like #w00001 .vis-filter-item-active. The buttons are a part of the widget and can be addressed this way.

Control interface

Vis creates 3 variables:

  • control.instance - Here the browser instance should be written or FFFFFFFF if every browser must be controlled.
  • control.data - Parameter for command. See a specific command description.
  • control.command - Command name. Write this variable triggering the command. That means before the command will be written, the "instance" and "data" must be prepared with data.

Commands:

  • alert - show an alert window in the vis-2. "control.data" has the following format "message;title;jquery-icon". Title and jquery-icon are optional. Icon names can be found here. To show icon "ui-icon-info" write Message;;info.

  • changeView - switch to desired view. "control.data" must have the name of view. You can specify the project name too as project/view. The default project is main.

  • refresh - reload the vis-2, for instance after the project is changed to reload on all browsers.

  • reload - same as refresh.

  • dialog - Show dialog window. Dialog must exist on view. One of:

    • static - HTML - Dialog,
    • static - Icon - Dialog,
    • container - HTML - view in jqui Dialog,
    • container - ext cmd - view in jqui Dialog,
    • container - Icon - view in jqui Dialog,
    • container - Button - view in jqui Dialog.

    control.data must have id of dialog widget, e.g. w00056.

  • dialogClose

  • popup - opens a new browser window. Link must be specified in control.data, e.g., http://google.com

  • playSound - play sound file. The link to file is specified in control.data, e.g., http://www.modular-planet.de/fx/marsians/Marsiansrev.mp3. You can upload your own file in vis-2 and let it play as for instance /vis-2.0/main/img/myFile.mp3. Important browser cannot play audio till the user has not clicked at least once on the page. It is a browser security policy. Here you can read more.

If the user changes the view or at the start, the variables will be filled by the vis-2 with

  • control.instance: browser instance and ack=true
  • control.data: project and view name in form project/view, e.g. main/view (and ack=true)
  • control.command: changedView and ack=true

You can write the JSON string or Object into control.command as {instance: 'AABBCCDD', command: 'cmd', data: 'ddd'}. In this case, the instance and data will be taken from the JSON object.

Example for JavaScript adapter:

setState('vis-2.0.control.command', { instance: '*', command: 'refresh', data: ''});

If you write the JSON as a string, ensure that it is parseable, e.g. {"instance": "*", "command": "refresh", "data": ""}, note the ".

Default view

You can define for every view the desired resolution (Menu=>Tools=>Resolution). This is only the visual border in edit mode to show you the screen size on some specific device. In the real-time mode, it will not be visible and all widgets outside the border will be visible.

Additionally, you can define if this view must be used as default for this resolution.

So every time the index.html (without #viewName) is called, the best suitable for this resolution view will be opened. If only one view has "Default" flag, so this view will be opened independently of screen resolution or orientation.

E.g., you can create two views "Landscape-Mobile" and "Portrait-Mobile" and these two views will be switched automatically when you change the orientation or screen size.

There is a helper widget "basic - Screen Resolution" that shows actual screen resolution and the best suitable default view for this resolution.

Navigation

Every widget that leads to a view - the Go to view option of the jQui widgets, basic - HTML navigation, … - gets the CSS class vis-nav-active as long as the view it points to is the view that is shown. So the entry of the current view can be highlighted in the CSS of the project:

.vis-nav-active button {
    border: 1px solid #0d72b8;
}

Permissions System

Project

In the project management dialog, you can configure read and write permissions for each ioBroker user.

The read flag means that the project is accessible for this user in the Runtime. The write flag means that the project is accessible for this user in the Edit Mode.

When a new user is created via ioBroker Admin adapter, it will have both permissions by default.

View

You can also specify which views the user is allowed to access for runtime and edit mode. When one of the access rights is not granted on the project level, it does not have any effect to specify them on view level, as the project as a whole will not be accessible.

Note that whenever you try to access a view where the current user has no permission for, the user will see the project selection panel instead.

Widget

If the user has no read permissions, the widget will not be rendered in the runtime. If user has no write permissions, the widget will not be rendered in edit mode.

Settings

Reload if sleep longer than

There is a rule that after some disconnection period, the whole VIS page will be reloaded to synchronize the project. You can configure it in the menu "Settings...". If you set the interval to "never", so the page will never be reloaded.

Reconnect interval

Set the interval between the connection attempts if disconnected. If you set 2 seconds, it will try to establish the connection every 2 seconds.

Dark reconnect screen

Sometimes (in the night) it is required to have the dark loading screen. With this option, you can set it.

Notice that these settings are valid only for reconnection and not for the first connecting.

Dark

SVG and currentColor

The currentColor keyword in CSS allows elements to inherit the current text color from their parent element. It can be particularly useful in SVGs (Scalable Vector Graphics) because it allows for more dynamic styling and easier integration with HTML content.

You can use the currentColor keyword in place of a specific color value for any property inside the SVG that accepts a color value. Here's a simple example with a circle in an SVG:

<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <circle cx="50" cy="50" r="40" fill="currentColor" />
</svg>

In this case, if the SVG takes the color of the parent element. E.g., if it was used in a menu and the menu is red, the circle would be red.

Development and Debugging

In order to make adjustments to the vis-2 editor itself, to search for errors and to debug, the following steps must be carried out.

  1. fork the iobroker/iobroker.vis-2 repository into your own account via the user interface of GitHub

  2. clone the repository into a directory. copy the url from your GitHub repository. the command looks like

git clone https://github.com/<your profile name>/ioBroker.vis-2.git
  1. open the downloaded repository with your IDE

  2. to install and download all necessary libraries, run the following command in a terminal in the root directory of the repository

npm run install-monorepo
  1. to start the editor in the browser, please execute the following command. An already separately running iobroker server instance must be available on port 8082.
npm run start
  • Debugging is available in the browser e.g. chrome F12
  • if you change a file, automatic reload of the editor is supported

Todo

Changelog

WORK IN PROGRESS

  • (@typhosj) licenseInformation.link points at the license editions now. For a non-free license that link is meant to name validity, shop and seller, which the source license file does not
  • (@typhosj) A timestamp that arrives as a string is shown as a date again instead of NaN:NaN:NaN, and a value that cannot be parsed at all is shown as it is
  • (@typhosj) A widget that leads to the view that is shown gets the CSS class vis-nav-active, so the current entry of a self-built navigation can be highlighted. The jQui buttons mark themselves by the active view now instead of the address of the browser, which they never noticed changing
  • (@typhosj) The project setting States Debounce Time is applied again: the commands for one object ID are collected during that period. It had no effect at all, as the value was never read from the project
  • (@typhosj) The switch of the binary control widget shows the state of the object again if no text and no icon are defined
  • (@typhosj) widgetOid delivers the object ID of a widget inside a group again instead of the name of the group attribute
  • (@typhosj) A view can show the navigation menu without being an entry of it: the new view setting Hide this view in the menu
  • (@typhosj) A resize of the window does not leave the opened view anymore, unless that view offers itself for a resolution
  • (@typhosj) Fixed the widget attributes keeping the groups of the previously selected widget after a view change
  • (@typhosj) The view of a jQui dialog is drawn inside the dialog again and no longer over its title
  • (@typhosj) Fixed the crash of the bulb on/off widget if the value of its object is null
  • (@typhosj) An iFrame or echarts widget is transparent again in the dark mode. The CSS variables put color-scheme: dark on :root, and a browser paints an opaque canvas behind an iframe whose document declares itself transparent (#661)
  • (@typhosj, @GermanBluefox) The content of a widget is not cut off anymore: CssBaseline is gone. It switched the whole document to border-box and painted the body, while the widgets - the built-in ones and those of other adapters alike - are laid out for the default content-box (#661)
  • (@typhosj) The text of a Fab button is readable again in the dark mode. MUI writes text.primary into it as soon as the CSS variables are generated, which is white, although the background of the button stays light grey in both themes (#661)
  • (@GermanBluefox) vis-2 uses MUI 9 and @iobroker/gui-components now, the successor of @iobroker/adapter-react-v5
  • (@GermanBluefox) @mui/styles is gone: it does not exist beyond MUI 6 and vis-2 never used it. It stays in the shared modules of the module federation so that a widget set built against MUI 6 keeps its own copy
  • (@GermanBluefox) Replaced the unmaintained mui-nested-menu, whose peer range ends at MUI 7, with an own sub menu entry built from MUI components
  • (@GermanBluefox) Followed the MUI props that were consolidated into slotProps (TransitionProps, TabIndicatorProps, InputLabelProps, PaperProps) and the renamed HelpOutline icon
  • (@GermanBluefox) vis-2 runs on React 19 now
  • (@GermanBluefox) Replaced the unmaintained react-beautiful-dnd with its api-compatible fork @hello-pangea/dnd, which is the only one of the two that supports React 19
  • (@GermanBluefox) Fixed the connectors of react-dnd being passed as a ref: React 19 takes what a ref callback returns as its cleanup function, and those connectors return a React element, so React would have tried to call an element on unmount
  • (@GermanBluefox) Fixed the type of window.VisMaterialIconSelector, which named the state of the component instead of its properties
  • (@GermanBluefox) A widget set that was built for an older React is recognized by its federation manifest and skipped with a readable message, instead of dying somewhere inside the module federation loader where no error boundary can catch it. As long as vis-2 itself runs on react 18 nothing is skipped
  • (@GermanBluefox) Widget sets that were skipped are named in a dialog in the editor and in the runtime, so a view with missing widgets does not leave the user guessing. It is shown once per affected set
  • (@GermanBluefox) Dropped the mime dependency; copied widget files are compared byte for byte instead of by type
  • (@GermanBluefox) @iobroker/types-vis-2: @iobroker/vis-2-widgets-react-dev left the list of shared modules. vis-2 never provided it anyway, and bundled as a share it dragged its undeclared @iobroker/adapter-react-v5 into the host build
  • (@GermanBluefox) The check that skips widget sets built for an older React works on a real installation too: it asked for the federation manifest under /vis-2/vis-2/..., was always answered 404 and let every set through
  • (@GermanBluefox) The build declares one placeholder remote (vis2-dynamic-remotes.js), which makes @module-federation/vite 1.21 treat vis-2 as the host it is. Without it the plugin deferred every shared module to the federation bootstrap and vis-2 died on jsx is not a function / createCssVarsProvider is not a function
  • (@GermanBluefox) @iobroker/types-vis-2: @mui/icons-material and the i18n JSONs of @iobroker/gui-components are not shared modules anymore, and moment is one now. Since a shared entry is bundled as a whole namespace, the icons alone put all ~10700 of them into every vis-2 delivery although vis-2 uses 83 - the build shrinks from 11 MB to 5.9 MB. A widget set bundles the icons it really uses instead, which is what already happened for every set of an older MUI major
  • (@GermanBluefox) Dropped the unused echarts and echarts-for-react dependencies of the editor
  • (@GermanBluefox) A widget could not be dropped on a view anymore: the workspace wrapper carried no height, so the height: 100% of the canvas resolved to auto and the drop area collapsed to zero pixels. The workspace is a flex column now - the tabs take their height, the canvas takes the rest
  • (@GermanBluefox) @iobroker/types-vis-2: @mui/material and @mui/system are singletons now instead of being versioned by the range of the consumer. A widget set built against 9.1.0 while vis-2 ships 9.1.2 used to carry its own copy; it renders with the MUI of vis-2 now, whatever patch or minor it was built against. Widget sets of an older MUI major are react 18 builds and are skipped before they are evaluated anyway
  • (@GermanBluefox) The federation host uses the loaded-first share strategy, so a widget set cannot replace the shared react, MUI or gui-components of vis-2 with its own copy

2.15.0 (2026-08-16)

  • (@GermanBluefox) Reworked the name plate of a widget in the editor: it is only as wide as its content, its buttons sit next to the name instead of on fixed positions that left a gap whenever a button was hidden, and the plate of a selected widget is drawn in the same blue as its frame
  • (@GermanBluefox) The three buttons of the name plate have a tooltip now and no longer turn red and double their size when the cursor is over them
  • (@GermanBluefox) The widget under the cursor is highlighted in blue instead of olive in the editor, in both themes
  • (@GermanBluefox) Several selected widgets are marked with the same frame as a single one, only without the handles to resize them. They carried no mark at all before, as the frame is drawn by those handles
  • (@GermanBluefox) Relative widgets can be reordered by dragging them again: a half transparent copy follows the cursor and a placeholder shows the slot the widget will land in. Dragging one never reordered anything before, because the gesture was not started for relative widgets at all
  • (@GermanBluefox) Removed the arrow buttons and the re-order menu of the relative widgets, as dragging replaces them
  • (@GermanBluefox) Moving and resizing a widget is rendered from the widget state now instead of being written into the DOM, which removes the duplicated geometry of the service and the can.js element
  • (@GermanBluefox) Removed the dead calculateRelativeWidgetPosition callback from onMove and WidgetReference: it has been null since 2022 and was never called
  • (@typhosj) The view in widget 8 and image 8 widgets show the view/image with the number of the value again
  • (@typhosj) vis.updateStates does not write the states back to ioBroker anymore, like in vis-1
  • (@typhosj) The iFrame 8 widget shows the frame with the number of the value, also for a boolean object
  • (@typhosj) Every copy of a group gets its own member widgets if several widgets are pasted at once
  • (@typhosj) A binding can be used as the comparison value of the visibility condition
  • (@typhosj) The application bar is not wider than the window anymore
  • (@typhosj) Fixed the invisible content of the tabs widget if the tabs are placed vertically
  • (@typhosj) The tabs of the tabs widget are as wide as their title now and can be scrolled on a touch device
  • (@GermanBluefox) Shortened the values that a failing binding writes to the console: a widget with braces in its HTML produced hundreds of failing bindings, each printing the complete HTML, which buried every other error
  • (@typhosj) Fixed the position of the vis-1 widgets in a view with a limited screen size
  • (@typhosj) The bulb on/off widget writes numeric min/max values as a number and not as a string
  • (@typhosj) Fixed min, max and step of the vis-1 widget attributes: they are optional and may be fractional
  • (@typhosj) Fixed the doubled border of the jQui widgets: the border is drawn by the button only and not by the widget too
  • (@typhosj) Fixed the missing attributes of a group: the sections could not be opened and the group attributes were not editable
  • (@typhosj) Made the background color and the text color of the selected entry editable for the horizontal navigation menu. The new background color takes precedence over the color of the application bar, which the horizontal menu borrowed before, so a view that was switched from the vertical to the horizontal navigation can change its color once
  • (@typhosj) Fixed the enumerable widget groups and fields that start at the index 0 and were not expanded
  • (@typhosj) Added the MUI CSS variables (--mui-palette-*), so the theme colors can be adjusted with CSS
  • (@typhosj) Fixed the overlapping entries of the horizontal navigation menu in a narrow window
  • (@typhosj) Fixed the invalid HTML element IDs of the widgets shown in multiple views
  • (@GermanBluefox) A widget that crashes while rendering does not take the whole view down anymore, but is replaced by a placeholder
  • (@GermanBluefox) Added react/jsx-runtime and react/jsx-dev-runtime to the shared modules of the module federation, so a widget set uses the JSX runtime of vis-2 instead of bundling its own
  • (@GermanBluefox) Fixed the shared modules react-dom/client and the i18n files of adapter-react-v5 being dropped if a widget set passes its package.json to moduleFederationShared()
  • (@GermanBluefox) @mui/material, @mui/system, @mui/icons-material and @mui/styles are shared per version now instead of as a singleton. A widget set that is rebuilt keeps its own MUI copy if it was built against another MUI major than vis-2, instead of being given the one of vis-2
  • (@GermanBluefox) Added @mui/private-theming to the shared modules, so the theme of vis-2 also reaches a widget set that uses its own MUI major
  • (@GermanBluefox) The widgeteria is not shown in the GUI anymore

2.14.4 (2026-08-10)

  • (@typhosj) The entries of the horizontal navigation menu can be scrolled now instead of being cut off in a narrow window
  • (@typhosj) Fixed the invalid HTML element IDs of the widgets shown in multiple views. Their IDs changed from <view>_<widget> to v<view>_<widget>, so a user script or CSS that addresses such a copy must be adapted
  • (@typhosj) Fixed the double click on a widget shown in multiple views jumping to a wrong view
  • (@typhosj) Show the text of the button widgets as entered and not upper cased
  • (@GermanBluefox) Fixed the ignored "small" option of the filter - dropdown widget
  • (@typhosj) Subscribed to object IDs that are the result of a binding
  • (@typhosj) Fixed the ignored read-only option of the Bool SVG widget
  • (@GermanBluefox) Fixed the position of a new group created inside another group
  • (@typhosj) Fixed the position of the members when a nested group is dissolved
  • (@GermanBluefox) Fixed "same width"/"same height" applying the sizes of a previously selected widget
  • (@GermanBluefox) Fixed the widget selection when a stored selected widget does not exist anymore
  • (@typhosj) Fixed dissolving a group deleting a member widget instead of the group
  • (@GermanBluefox) The user permissions are now applied to widgets embedded via getWidgetInWidget, which can return null now
  • (@typhosj) Fixed the user permissions being ignored for widgets inside a group
  • (@typhosj) Added the CSS classes vis-filter-item and vis-filter-item-active to the filter - dropdown widget
  • (@GermanBluefox) Fixed exist/not exist of signals evaluating the comparison value instead of the state value
  • (@GermanBluefox) Fixed the signal condition if the state value is null
  • (@typhosj) Fixed the URL attributes of the iFrame 8 widget being subscribed as object IDs
  • (@typhosj) Fixed the visibility condition if the state value is null

2.14.3 (2026-06-09)

  • (@GermanBluefox) Applied the user-defined style to tplValueInput

2.14.0 (2026-05-29)

  • (@GermanBluefox) Refactoring of the build process

2.13.19 (2026-04-27)

  • (@GermanBluefox) Refactoring

2.13.17 (2026-03-29)

  • (@GermanBluefox) Removed debug code for theme

License

Copyright (c) 2021-2026 Denis Haev, https://github.com/GermanBluefox dogafox@gmail.com,

Creative Common Attribution-NonCommercial (CC BY-NC)

http://creativecommons.org/licenses/by-nc/4.0/

CC BY-NC License

Short content: Licensees may copy, distribute, display and perform the work and make derivative works based on it only if they give the author or licensor the credits in the manner specified by these. Licensees may copy, distribute, display, and perform the work and make derivative works based on it only for noncommercial purposes. (Free for non-commercial use).