Coder Social home page Coder Social logo

sodiboo / niri-flake Goto Github PK

View Code? Open in Web Editor NEW
75.0 75.0 10.0 668 KB

Nix packages and modules for niri

Home Page: https://github.com/YaLTeR/niri

License: MIT License

Nix 98.89% Shell 0.71% Just 0.39%
niri nix nix-flake nixos wayland wayland-compositor

niri-flake's People

Contributors

2639-unofficial avatar algernon avatar danth avatar github-actions[bot] avatar k0ral avatar logicaloverflow avatar mergify[bot] avatar sodiboo avatar twoneis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

niri-flake's Issues

document nix-specific equivalents of topics from niri wiki (+ off-topic nix talk, vscode ozone)

niri's wiki documents a bunch of common tasks and how to achieve them using niri.
users of this flake repo will face the challenge of how to translate those solutions to the NixOS context, or may further wonder how much of those concerns will have been addressed by this repo out of the box already.
it would be nice to have perhaps the readme here explain tackling such related tasks for users of this repo as well, including which of those have been tackled by this flake and which ones should be handled manually (and if so, how).

allow-when-locked=false is being added to every bind

This may be user error, I'm setting this up for the first time.

It appears that allow-when-locked=false is being added to every keybind, and niri is complaining that this field may only be set on spawn binds.

Here are my binds:

      binds = {
        "Mod+Shift+Slash".action.show-hotkey-overlay = [];
      
        "Mod+Return".action.spawn = ["kitty"];
        "Mod+D".action.spawn = ["rofi" "-show" "run"];
        "Super+Alt+L".action.spawn = ["swaylock"];
      
	"XF86AudioRaiseVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"];
	"XF86AudioLowerVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"];
      
        "Mod+Q".action.close-window = [];
      
        "Mod+Left".action.focus-column-left = [];
        "Mod+H".action.focus-column-left = [];
        "Mod+Down".action.focus-window-down = [];
        "Mod+J".action.focus-window-down = [];
        "Mod+Up".action.focus-window-up = [];
        "Mod+K".action.focus-window-up = [];
        "Mod+Right".action.focus-column-right = [];
        "Mod+L".action.focus-column-right = [];
      
        "Mod+Ctrl+Left".action.move-column-left = [];
        "Mod+Ctrl+H".action.move-column-left = [];
        "Mod+Ctrl+Down".action.move-window-down = [];
        "Mod+Ctrl+J".action.move-window-down = [];
        "Mod+Ctrl+Up".action.move-window-up = [];
        "Mod+Ctrl+K".action.move-window-up = [];
        "Mod+Ctrl+Right".action.move-column-right = [];
        "Mod+Ctrl+L".action.move-column-right = [];
      
        "Mod+Home".action.focus-column-first = [];
        "Mod+End".action.focus-column-last = [];
        "Mod+Ctrl+Home".action.move-column-to-first = [];
        "Mod+Ctrl+End".action.move-column-to-last = [];
      
        "Mod+Shift+Left".action.focus-monitor-left = [];
        "Mod+Shift+H".action.focus-monitor-left = [];
        "Mod+Shift+Down".action.focus-monitor-down = [];
        "Mod+Shift+J".action.focus-monitor-down = [];
        "Mod+Shift+Up".action.focus-monitor-up = [];
        "Mod+Shift+K".action.focus-monitor-up = [];
        "Mod+Shift+Right".action.focus-monitor-right = [];
        "Mod+Shift+L".action.focus-monitor-right = [];
      
        "Mod+Shift+Ctrl+Left".action.move-column-to-monitor-left = [];
        "Mod+Shift+Ctrl+H".action.move-column-to-monitor-left = [];
        "Mod+Shift+Ctrl+Down".action.move-column-to-monitor-down = [];
        "Mod+Shift+Ctrl+J".action.move-column-to-monitor-down = [];
        "Mod+Shift+Ctrl+Up".action.move-column-to-monitor-up = [];
        "Mod+Shift+Ctrl+K".action.move-column-to-monitor-up = [];
        "Mod+Shift+Ctrl+Right".action.move-column-to-monitor-right = [];
        "Mod+Shift+Ctrl+L".action.move-column-to-monitor-right = [];
      
        "Mod+Page_Down".action.focus-workspace-down = [];
        "Mod+Page_Up".action.focus-workspace-up = [];
        "Mod+U".action.focus-workspace-down = [];
        "Mod+I".action.focus-workspace-up = [];
        "Mod+Ctrl+Page_Down".action.move-column-to-workspace-down = [];
        "Mod+Ctrl+Page_Up".action.move-column-to-workspace-up = [];
        "Mod+Ctrl+U".action.move-column-to-workspace-down = [];
        "Mod+Ctrl+I".action.move-column-to-workspace-up = [];
      
        "Mod+Shift+Page_Down".action.move-workspace-down = [];
        "Mod+Shift+Page_Up".action.move-workspace-up = [];
        "Mod+Shift+U".action.move-workspace-down = [];
        "Mod+Shift+I".action.move-workspace-up = [];
      
        "Mod+WheelScrollDown" = {
  	 cooldown-ms = 150;
  	 action.focus-workspace-down = [];
  	};
        "Mod+WheelScrollUp" = {
  	 cooldown-ms = 150;
  	 action.focus-workspace-up = [];
  	};
        "Mod+Ctrl+WheelScrollDown" = {
  	 cooldown-ms = 150;
  	 action.move-column-to-workspace-down = [];
  	};
        "Mod+Ctrl+WheelScrollUp" = {
  	 cooldown-ms = 150;
  	 action.move-column-to-workspace-up = [];
  	};
  
        "Mod+WheelScrollRight".action.focus-column-right = [];
        "Mod+WheelScrollLeft".action.focus-column-left = [];
        "Mod+Ctrl+WheelScrollRight".action.move-column-right = [];
        "Mod+Ctrl+WheelScrollLeft".action.move-column-left = [];
      
        "Mod+Shift+WheelScrollDown".action.focus-column-right = [];
        "Mod+Shift+WheelScrollUp".action.focus-column-left = [];
        "Mod+Ctrl+Shift+WheelScrollDown".action.move-column-right = [];
        "Mod+Ctrl+Shift+WheelScrollUp".action.move-column-left = [];
      
        #Mod+1 { focus-workspace 1; }
        #Mod+2 { focus-workspace 2; }
        #Mod+3 { focus-workspace 3; }
        #Mod+4 { focus-workspace 4; }
        #Mod+5 { focus-workspace 5; }
        #Mod+6 { focus-workspace 6; }
        #Mod+7 { focus-workspace 7; }
        #Mod+8 { focus-workspace 8; }
        #Mod+9 { focus-workspace 9; }
        #Mod+Ctrl+1 { move-column-to-workspace 1; }
        #Mod+Ctrl+2 { move-column-to-workspace 2; }
        #Mod+Ctrl+3 { move-column-to-workspace 3; }
        #Mod+Ctrl+4 { move-column-to-workspace 4; }
        #Mod+Ctrl+5 { move-column-to-workspace 5; }
        #Mod+Ctrl+6 { move-column-to-workspace 6; }
        #Mod+Ctrl+7 { move-column-to-workspace 7; }
        #Mod+Ctrl+8 { move-column-to-workspace 8; }
        #Mod+Ctrl+9 { move-column-to-workspace 9; }
      
        "Mod+Comma".action.consume-window-into-column = [];
        "Mod+Period".action.expel-window-from-column = [];
      
        "Mod+R".action.switch-preset-column-width = [];
        "Mod+F".action.maximize-column = [];
        "Mod+Shift+F".action.fullscreen-window = [];
        "Mod+C".action.center-column = [];
      
        "Mod+Minus".action.set-column-width = "-10%";
        "Mod+Equal".action.set-column-width = "+10%";
      
        "Mod+Shift+Minus".action.set-window-height = "-10%";
        "Mod+Shift+Equal".action.set-window-height = "+10%";
      
        "Mod+Space".action.switch-layout = "next";
        "Mod+Shift+Space".action.switch-layout = "prev";
      
        "Print".action.screenshot = [];
        "Ctrl+Print".action.screenshot-screen = [];
        "Alt+Print".action.screenshot-window = [];
      
        "Mod+Shift+E".action.quit = [];
      
        "Mod+Shift+P".action.power-off-monitors = [];
      };

Running home-manager switch gives me:

error: builder for '/nix/store/8hr5hmkm207jyh7zigpdhgr1hl9s1kzl-config.kdl.drv' failed with exit code 1;
       last 10 log lines:
       > Error: allow-when-locked can only be set on spawn binds
       >     Diagnostic severity: error
       >
       > Begin snippet for .attr-041r6j70w6v6dakqkzmwb899h71g2hibch7d14bbv9gy7bxhd5mp starting at line 133, column 1
       >
       > snippet line 133:     Mod+WheelScrollUp allow-when-locked=false cooldown-ms=150 { focus-workspace-up; }
       > snippet line 134:     Print allow-when-locked=false { screenshot; }
       >     label at line 134, columns 11 to 27: unexpected property
       > snippet line 135:     Super+Alt+L allow-when-locked=false { spawn "swaylock"; }
       >
       For full logs, run 'nix log /nix/store/8hr5hmkm207jyh7zigpdhgr1hl9s1kzl-config.kdl.drv'.
error: 1 dependencies of derivation '/nix/store/mr66jb6g3v8qp9bdmgsirzk38hzb988j-home-manager-files.drv' failed to build
error: 1 dependencies of derivation '/nix/store/5hv1da881bnmbxfh143ky5k7gvlvm5pa-home-manager-generation.drv' failed to build

And checking out the requested log file shows me many lines as above, one for each bind (not reproduced here due to length).

Again, this may be error on my end, but not sure what I could be doing wrong.

Why no module for NixOS?

First of all, thank you for your work and effort on this!

So far i haven't used flakes and am thus a bit hesitant about it. That's why i am wondering why you havent't added a niri module to NixOS (like the one for hyprland for example)?

I understand that using your flake provides more flexibility but i don't need that and would be happy with a "vanilla" module.

Would you consider adding one (while continuing your flake of course)?

It seems like stylix and niri-flake not doing well

error: The option `home-manager.users.lennylizowzskiy.programs.niri.finalConfig' in `/nix/store/a7idmrymwccm7gnssm2hb04f6yk2mz9c-source/nixos/common.nix' is already declared in `/nix/store/hixvzv8fr9k5dp9fvrxyhjvij9f6r84p-hx7fxaip5vqk92y05rjsyf25hfb5vhph-source/home-manager/presets/per-user/lennylizowzskiy/configs/gui/de/niri'.

Config:

# home-manager
{
  imports = [
    inputs.niri-flake.homeModules.config

    # ...
  ];

  home.packages = with pkgs; [
    # ...
  ];

  programs.niri = {
    settings = {
      prefer-no-csd = true;

      output = {
        "DP-2".mode = "[email protected]";
      };
  # ...

I'm running NixOS unstable with stylix and home-manager both enabled

niri cannot use

really sorry to bother you, i'm new to nixos and i wanna try niri, i'm using vmware to do this but after sddm it's just purely dark screen.

systemctl niri.service log:

3.29 23:49:19 nixos niri[1121]: 2024-03-29T15:49:19.738679Z  WARN niri::niri: error starting PipeWire: error creating Core
3.29 23:49:19 nixos niri[1121]: Caused by:
3.29 23:49:19 nixos niri[1121]:     Creation failed
3.29 23:49:19 nixos niri[1121]: 2024-03-29T15:49:19.738816Z DEBUG niri::backend::tty: device added: 57856 "/dev/dri/card0"
3.29 23:49:19 nixos niri[1121]: VMware: No 3D enabled (0, Success).
3.29 23:49:19 nixos niri[1121]: 2024-03-29T15:49:19.763147Z  WARN niri::backend::tty: error adding device: None of the following EGL extensions is supported by the underlying EGL implementation, at least one is required>
3.29 23:49:19 nixos niri[1121]: 2024-03-29T15:49:19.763180Z  INFO niri: listening on Wayland socket: wayland-1
3.29 23:49:19 nixos niri[1121]: 2024-03-29T15:49:19.763186Z  INFO niri: IPC listening on: /run/user/1000/niri.wayland-1.1121.sock
3.29 23:49:19 nixos systemd[1078]: Started A scrollable-tiling Wayland compositor.
3.29 23:50:26 nixos niri[1121]: 2024-03-29T15:50:26.477927Z DEBUG niri::backend::tty: pausing session

my nix config:

configuration.nix

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Bootloader.
  boot.loader.grub.enable = true;
  boot.loader.grub.device = "/dev/sda";
  boot.loader.grub.useOSProber = true;

  networking.hostName = "nixos"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Enable networking
  networking.networkmanager.enable = true;

  # Set your time zone.
  time.timeZone = "Asia/Shanghai";

  # Select internationalisation properties.
  i18n.defaultLocale = "en_US.UTF-8";

  i18n.extraLocaleSettings = {
    LC_ADDRESS = "zh_CN.UTF-8";
    LC_IDENTIFICATION = "zh_CN.UTF-8";
    LC_MEASUREMENT = "zh_CN.UTF-8";
    LC_MONETARY = "zh_CN.UTF-8";
    LC_NAME = "zh_CN.UTF-8";
    LC_NUMERIC = "zh_CN.UTF-8";
    LC_PAPER = "zh_CN.UTF-8";
    LC_TELEPHONE = "zh_CN.UTF-8";
    LC_TIME = "zh_CN.UTF-8";
  };

  # Configure keymap in X11
  #services.xserver = {
  #  layout = "us";
  #  xkbVariant = "";
  #};
  services.xserver = {
    enable = true;
    libinput.enable = true;

    # Display Manager
    displayManager = {
      defaultSession = "niri";

      # SDDM
      sddm = {
        enable = true;
        wayland.enable = true;
        theme = "catppuccin";
      };
    };
  };

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.ogios = {
    isNormalUser = true;
    description = "ogios";
    extraGroups = [ "networkmanager" "wheel" ];
    packages = with pkgs; [];
  };

  # Allow unfree packages
  nixpkgs.config.allowUnfree = true;

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
    wget
    git
  ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  programs.neovim.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  services.openssh.enable = true;

  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  networking.firewall.enable = false;

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It‘s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "23.11"; # Did you read the comment?
}

hardware-configuration.nix (didn't change)

{ config, lib, pkgs, modulesPath, ... }:

{
  imports = [ ];

  boot.initrd.availableKernelModules = [ "ata_piix" "mptspi" "uhci_hcd" "ehci_pci" "ahci" "sd_mod" "sr_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/950e55c2-fab1-409e-95b7-313288e68f5a";
      fsType = "ext4";
    };

  swapDevices = [ ];

  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
  # (the default) this is the recommended approach. When using systemd-networkd it's
  # still possible to use this option, but it's recommended to use it in conjunction
  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
  networking.useDHCP = lib.mkDefault true;
  # networking.interfaces.ens33.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

flake.nix

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

    niri.url = "github:sodiboo/niri-flake";
  };

  outputs = { self, nixpkgs, niri, ... }: {
    nixosConfigurations.ogios = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        niri.nixosModules.niri
        {
          programs.niri.enable = true;
        }
        #{ # If you wish to use the unstable version of niri, you can set it like so:
        #  nixpkgs.overlays = [ niri.overlays.niri ];
        #  programs.niri.package = pkgs.niri-unstable;
        #}
      ];
    };
  };
}

Nixpkgs 23.11 compatibility

Using niri-flake as a NixOS modulo seems to use the NixOS nixpkgs, which doesn't know about --replace-fail yet on 23.11:

error: builder for '/nix/store/kpcz07qm41dxi5x7lzkxmgmy59bxd5ds-rust_niri-config-0.1.2.drv' failed with exit code 1;
       last 6 log lines:
       > Running phase: unpackPhase
       > unpacking source archive /nix/store/mmczsxgmcidlpksshfw3gky7yw1rpwny-source/niri-config
       > source root is niri-config
       > Running phase: patchPhase
       > substituteStream(): ERROR: Invalid command line argument: --replace-fail
       > /nix/store/10i1kjjq5szjn1gp6418x8bc1hswqc90-stdenv-linux/setup: line 131: pop_var_context: head of shell_variables not a function context
       For full logs, run 'nix log /nix/store/kpcz07qm41dxi5x7lzkxmgmy59bxd5ds-rust_niri-config-0.1.2.drv'.

Desktop Session

I've got the flake working and I can launch niri manually, but I was wondering if there's a magic trick to get niri as an option with gdm or sddm?

services.xserver.displayManager got renamed over to services.displayManager

As of this commit there was a tree-wide change in nixos-unstable that moves services.xserver.displayManager to services.displayManager, making it so no NixOS config can be built if niri-flake is enabled now :(

The affected file is as as of 1fd2e47

services.xserver.displayManager.sessionPackages = [cfg.package];

By editing this file so it has some check like this, this issue may be fixed.

if (system.stateVersion != "24.05") then services.displayManager.sessionPackages = [cfg.package]; 
else services.xserver.displayManager.sessionPackages = [cfg.package]; 

Amazing job with this project!

Feature Request: Generate config without home-manager

I'd really like to be able to use this module to generate my niri config, but I don't use home manager... I currently am doing this with: ```
nixpkgs.overlays = [
niri.overlays.niri

				(_final: _prev: {
					# Modify the niri startup command to point it to the
					# config file
					niri-unstable = _prev.niri-unstable.overrideAttrs (final: prev: {
						postFixup = ''
							${prev.postFixup}

							substituteInPlace $out/share/systemd/user/niri.service --replace "--session" "--session -c ${./niri.kdl}"
							'';
					});
				})
			];

			programs.niri.enable			= true;
			programs.niri.package			= pkgs.niri-unstable;

I'd like to be able to use this flake to generate my `niri.kdl` file though. That would make it a lot easier to make tweaks for specific machines, etc.

Is it possible to do that, and then use the output in my overlay to point to that derivation?

Screensharing possible

Do I have to add some config to enable screensharing? According to niri's README, screensharing should work. But I can't get it working. I saw you've added the gnome xdg-portal but still there is probably something missing in my config.

`error: undefined variable 'mergeAttrsList'` when trying to set binds

Hello! Just trying this out but got stuck when trying to create binds. I have (in my Home Manager configuration):

    niri.settings = {
      binds = {
        "Mod+Left".action = config.lib.niri.actions.focus-left;
      };
      
      outputs."DP-3".mode = {
        width = 2560;
        height = 1440;
        refresh = 165.0;
      };
    };

But this produces the error:

error:
       … while calling the 'head' builtin

         at /nix/store/qwcxqcxfmf6nifz3yqg6rkn2h6mf65x9-source/lib/attrsets.nix:922:11:

          921|         || pred here (elemAt values 1) (head values) then
          922|           head values
             |           ^
          923|         elsewhile evaluating the attribute 'value'

         at /nix/store/qwcxqcxfmf6nifz3yqg6rkn2h6mf65x9-source/lib/modules.nix:807:9:

          806|     in warnDeprecation opt //
          807|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          808|         inherit (res.defsFinal') highestPrio;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: undefined variable 'mergeAttrsList'

       at /nix/store/35l35rk7ximl9zlqqqrk9crccbhbrzx2-source/flake.nix:353:25:

          352|             config.lib.niri = {
          353|               actions = mergeAttrsList (map ({
             |                         ^
          354|                 name,

Can you see anything I'm doing wrong?

document using xdg-portal?

on nixos, using the niri service my services.flatpak.enable = true; would error:

To use Flatpak you must enable XDG Desktop Portals with xdg.portal.enable.

while i see this mentioned in code here and at niri-src, i haven't figured out how to make this work yet.

following the approach i used on hyprland, i tried e.g.:

    xdg.portal = {
      enable = true;
      wlr.enable = true;
      extraPortals = with pkgs; [
        xdg-desktop-portal-gnome
      ];
    };

this appeared not to satisfy the flatpak service yet tho so far.

rofi-wayland does not register keyboard input

Steps to reproduce:

$ rofi -show drun -no-config | wl-copy 

(process:9501): libnkutils-bindings-CRITICAL **: 10:39:42.553: nk_bindings_seat_handle_key: assertion 'self->keymap != NULL' failed

Using default niri configuration.

caching nix builds

i wonder if we could maybe alleviate local builds by say having a cachix user for niri.
if so, would it be best if this were done from niri-flake, from the upstream niri repo, or from both?

How to use this flake

I'm unable to understand where to start with this flake. I was able to follow https://wiki.hyprland.org/Nix/

Is there some explanation of simple clear ways you can add this to a nixos installation so it's available just like the other Compositors?

programs.niri.settings.spawn-at-startup usage

How can I use programs.niri.settings.spawn-at-startup? I tried

programs.niri.settings.spawn-at-startup = [ "waybar"]

and

programs.niri.settings.spawn-at-startup = [ ["waybar"] ]

The docs aren't really clear on the usage. Any help would be appreciated, thanks!

Question: Why is this not merged with the main repo?

Why hasn't this repository been merged with the main one that contains the source code? Keeping the repositories separate makes it more difficult to find. All nix modules, with the exception of flake.nix and flake.lock, could be moved to a nix directory.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.